1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file cons_nonlinear.c
17 * @ingroup DEFPLUGINS_CONS
18 * @brief constraint handler for nonlinear constraints specified by algebraic expressions
19 * @author Ksenia Bestuzheva
20 * @author Benjamin Mueller
21 * @author Felipe Serrano
22 * @author Stefan Vigerske
23 */
24
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26
27 #ifdef SCIP_DEBUG
28 #define ENFO_LOGGING
29 #endif
30
31 /* enable to get log output for enforcement */
32 /* #define ENFO_LOGGING */
33 /* define to get enforcement logging into file */
34 /* #define ENFOLOGFILE "consexpr_enfo.log" */
35
36 /* define to get more debug output from domain propagation */
37 /* #define DEBUG_PROP */
38
39 /*lint -e440*/
40 /*lint -e441*/
41 /*lint -e528*/
42 /*lint -e666*/
43 /*lint -e777*/
44 /*lint -e866*/
45
46 #include <assert.h>
47 #include <ctype.h>
48
49 #include "scip/cons_nonlinear.h"
50 #include "scip/nlhdlr.h"
51 #include "scip/expr_var.h"
52 #include "scip/expr_sum.h"
53 #include "scip/expr_value.h"
54 #include "scip/expr_pow.h"
55 #include "scip/nlhdlr_convex.h"
56 #include "scip/cons_linear.h"
57 #include "scip/cons_varbound.h"
58 #include "scip/cons_and.h"
59 #include "scip/cons_bounddisjunction.h"
60 #include "scip/heur_subnlp.h"
61 #include "scip/heur_trysol.h"
62 #include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
63 #include "scip/debug.h"
64 #include "scip/dialog_default.h"
65
66 /* fundamental constraint handler properties */
67 #define CONSHDLR_NAME "nonlinear"
68 #define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
69 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
70 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
71 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
72 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
73 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
74
75 /* optional constraint handler properties */
76 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
77 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
78 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79
80 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
81 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
82 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
83
84 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
85 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86
87 /* properties of the nonlinear constraint handler statistics table */
88 #define TABLE_NAME_NONLINEAR "cons_nonlinear"
89 #define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
90 #define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
91 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
92
93 /* properties of the nonlinear handler statistics table */
94 #define TABLE_NAME_NLHDLR "nlhdlr"
95 #define TABLE_DESC_NLHDLR "nonlinear handler statistics"
96 #define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
97 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
98
99 #define DIALOG_NAME "nlhdlrs"
100 #define DIALOG_DESC "display nonlinear handlers"
101 #define DIALOG_ISSUBMENU FALSE
102
103 #define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
104 #define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
105 #define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
106 #define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
107
108 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
109
110 #define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
111
112 /** translate from one value of infinity to another
113 *
114 * if val is ≥ infty1, then give infty2, else give val
115 */
116 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
117
118 /** translates x to 2^x for non-negative integer x */
119 #define POWEROFTWO(x) (0x1u << (x))
120
121 #ifdef ENFO_LOGGING
122 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
123 FILE* enfologfile = NULL;
124 #else
125 #define ENFOLOG(x)
126 #endif
127
128 /*
129 * Data structures
130 */
131
132 /** enforcement data of an expression */
133 typedef struct
134 {
135 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
136 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
137 SCIP_NLHDLR_METHOD nlhdlrparticipation; /**< methods where nonlinear handler participates */
138 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
139 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
140 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
141 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
142 } EXPRENFO;
143
144 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
145 struct SCIP_Expr_OwnerData
146 {
147 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
148
149 /* locks and monotonicity */
150 int nlockspos; /**< positive locks counter */
151 int nlocksneg; /**< negative locks counter */
152 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
153 int monotonicitysize; /**< length of monotonicity array */
154
155 /* propagation (in addition to activity that is stored in expr) */
156 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
157 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
158 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
159
160 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
161 EXPRENFO** enfos; /**< enforcements */
162 int nenfos; /**< number of enforcements, or -1 if not initialized */
163 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
164 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
165 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
166 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
167 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
168
169 /* branching */
170 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
171 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
172 int nviolscores; /**< number of violation scores stored for this expression */
173 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
174
175 /* additional data for variable expressions (TODO move into sub-struct?) */
176 SCIP_CONS** conss; /**< constraints in which this variable appears */
177 int nconss; /**< current number of constraints in conss */
178 int consssize; /**< length of conss array */
179 SCIP_Bool consssorted; /**< is the array of constraints sorted */
180
181 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
182 };
183
184 /** constraint data for nonlinear constraints */
185 struct SCIP_ConsData
186 {
187 /* data that defines the constraint: expression and sides */
188 SCIP_EXPR* expr; /**< expression that represents this constraint */
189 SCIP_Real lhs; /**< left-hand side */
190 SCIP_Real rhs; /**< right-hand side */
191
192 /* variables */
193 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
194 int nvarexprs; /**< total number of variable expressions */
195 SCIP_Bool catchedevents; /**< do we catch events on variables? */
196
197 /* constraint violation */
198 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
199 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
200 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
201 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
202
203 /* status flags */
204 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
205 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
206
207 /* locks */
208 int nlockspos; /**< number of positive locks */
209 int nlocksneg; /**< number of negative locks */
210
211 /* repair infeasible solutions */
212 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
213 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
214 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
215 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
216
217 /* miscellaneous */
218 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
219 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
220 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
221 };
222
223 /** constraint upgrade method */
224 typedef struct
225 {
226 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
227 int priority; /**< priority of upgrading method */
228 SCIP_Bool active; /**< is upgrading enabled */
229 } CONSUPGRADE;
230
231 /** constraint handler data */
232 struct SCIP_ConshdlrData
233 {
234 /* nonlinear handler */
235 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
236 int nnlhdlrs; /**< number of nonlinear handlers */
237 int nlhdlrssize; /**< size of nlhdlrs array */
238 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
239 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
240 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
241
242 /* constraint upgrades */
243 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
244 int consupgradessize; /**< size of consupgrades array */
245 int nconsupgrades; /**< number of constraint upgrade methods */
246
247 /* other plugins */
248 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
249 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
250 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
251
252 /* tags and counters */
253 int auxvarid; /**< unique id for the next auxiliary variable */
254 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
255 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
256 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
257 unsigned int enforound; /**< total number of enforcement calls, including current one */
258 int lastconsindex; /**< last used consindex, plus one */
259
260 /* activity intervals and domain propagation */
261 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
262 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
263 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
264 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
265 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
266
267 /* parameters */
268 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
269 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
270 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
271 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
272 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
273 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
274 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
275 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
276 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
277 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
278 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
279 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
280 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
281 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
282 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
283 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
284 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
285 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
286 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
287 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
288 char rownotremovable; /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
289 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
290 char checkvarlocks; /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
291 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
292 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
293 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
294 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
295 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
296 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
297 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
298 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
299 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
300 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
301 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
302 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
303 char linearizeheursol; /**< whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution) */
304 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
305
306 /* statistics */
307 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
308 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
309 SCIP_Longint ndesperatetightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing because we didn't know anything better */
310 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
311 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
312 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
313 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
314 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
315
316 /* facets of envelops of vertex-polyhedral functions */
317 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
318 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
319
320 /* hashing of bilinear terms */
321 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
322 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
323 int nbilinterms; /**< total number of bilinear terms */
324 int bilintermssize; /**< size of bilinterms array */
325 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
326
327 /* branching */
328 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
329 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
330
331 /* misc */
332 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
333 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
334 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
335 };
336
337 /** branching candidate with various scores */
338 typedef struct
339 {
340 SCIP_EXPR* expr; /**< expression that holds branching candidate */
341 SCIP_Real auxviol; /**< aux-violation score of candidate */
342 SCIP_Real domain; /**< domain score of candidate */
343 SCIP_Real dual; /**< dual score of candidate */
344 SCIP_Real pscost; /**< pseudo-cost score of candidate */
345 SCIP_Real vartype; /**< variable type score of candidate */
346 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
347 } BRANCHCAND;
348
349 /*
350 * Local methods
351 */
352
353 /* forward declaration */
354 static
355 SCIP_RETCODE forwardPropExpr(
356 SCIP* scip, /**< SCIP data structure */
357 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
358 SCIP_EXPR* rootexpr, /**< expression */
359 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
360 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
361 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
362 );
363
364 /** frees auxiliary variables of expression, if any */
365 static
366 SCIP_RETCODE freeAuxVar(
367 SCIP* scip, /**< SCIP data structure */
368 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
369 )
370 {
371 SCIP_EXPR_OWNERDATA* mydata;
372
373 assert(scip != NULL);
374 assert(expr != NULL);
375
376 mydata = SCIPexprGetOwnerData(expr);
377 assert(mydata != NULL);
378
379 if( mydata->auxvar == NULL )
380 return SCIP_OKAY;
381
382 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
383
384 /* remove variable locks
385 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
386 */
387 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
388
389 /* release auxiliary variable */
390 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
391 assert(mydata->auxvar == NULL);
392
393 return SCIP_OKAY;
394 }
395
396 /** frees data used for enforcement of expression, that is, nonlinear handlers
397 *
398 * can also clear indicators whether expr needs enforcement methods, that is,
399 * free an associated auxiliary variable and reset the nactivityuses counts
400 */
401 static
402 SCIP_RETCODE freeEnfoData(
403 SCIP* scip, /**< SCIP data structure */
404 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
405 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
406 )
407 {
408 SCIP_EXPR_OWNERDATA* mydata;
409 int e;
410
411 mydata = SCIPexprGetOwnerData(expr);
412 assert(mydata != NULL);
413
414 if( freeauxvar )
415 {
416 /* free auxiliary variable */
417 SCIP_CALL( freeAuxVar(scip, expr) );
418 assert(mydata->auxvar == NULL);
419
420 /* reset count on activity and auxvar usage */
421 mydata->nactivityusesprop = 0;
422 mydata->nactivityusessepa = 0;
423 mydata->nauxvaruses = 0;
424 }
425
426 /* free data stored by nonlinear handlers */
427 for( e = 0; e < mydata->nenfos; ++e )
428 {
429 SCIP_NLHDLR* nlhdlr;
430
431 assert(mydata->enfos[e] != NULL);
432
433 nlhdlr = mydata->enfos[e]->nlhdlr;
434 assert(nlhdlr != NULL);
435
436 if( mydata->enfos[e]->issepainit )
437 {
438 /* call the separation deinitialization callback of the nonlinear handler */
439 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
440 mydata->enfos[e]->issepainit = FALSE;
441 }
442
443 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
444 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
445 {
446 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
447 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
448 }
449
450 /* free enfo data */
451 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
452 }
453
454 /* free array with enfo data */
455 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
456
457 /* we need to look at this expression in detect again */
458 mydata->nenfos = -1;
459
460 return SCIP_OKAY;
461 }
462
463 /** callback that frees data that this conshdlr stored in an expression */
464 static
465 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
466 {
467 assert(scip != NULL);
468 assert(expr != NULL);
469 assert(ownerdata != NULL);
470 assert(*ownerdata != NULL);
471
472 /* expression should not be locked anymore */
473 assert((*ownerdata)->nlockspos == 0);
474 assert((*ownerdata)->nlocksneg == 0);
475
476 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
477
478 /* expression should not be enforced anymore */
479 assert((*ownerdata)->nenfos <= 0);
480 assert((*ownerdata)->auxvar == NULL);
481
482 if( SCIPisExprVar(scip, expr) )
483 {
484 SCIP_CONSHDLRDATA* conshdlrdata;
485 SCIP_VAR* var;
486
487 /* there should be no constraints left that still use this variable */
488 assert((*ownerdata)->nconss == 0);
489 /* thus, there should also be no variable event catched (via this exprhdlr) */
490 assert((*ownerdata)->filterpos == -1);
491
492 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
493
494 /* update var2expr hashmap in conshdlrdata */
495 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
496 assert(conshdlrdata != NULL);
497
498 var = SCIPgetVarExprVar(expr);
499 assert(var != NULL);
500
501 /* remove var -> expr map from hashmap if present
502 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
503 * if variable-expression stored for var is different, then also do nothing)
504 */
505 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
506 {
507 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
508 }
509 }
510
511 SCIPfreeBlockMemory(scip, ownerdata);
512
513 return SCIP_OKAY;
514 }
515
516 static
517 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
518 { /*lint --e{715}*/
519 assert(ownerdata != NULL);
520
521 /* print nl handlers associated to expr */
522 if( ownerdata->nenfos > 0 )
523 {
524 int i;
525 SCIPinfoMessage(scip, file, " {");
526
527 for( i = 0; i < ownerdata->nenfos; ++i )
528 {
529 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
530 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
531 SCIPinfoMessage(scip, file, "a");
532 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
533 SCIPinfoMessage(scip, file, "u");
534 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
535 SCIPinfoMessage(scip, file, "o");
536 if( i < ownerdata->nenfos-1 )
537 SCIPinfoMessage(scip, file, ", ");
538 }
539
540 SCIPinfoMessage(scip, file, "}");
541 }
542
543 /* print aux var associated to expr */
544 if( ownerdata->auxvar != NULL )
545 {
546 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
547 }
548 SCIPinfoMessage(scip, file, "\n");
549
550 return SCIP_OKAY;
551 }
552
553 /** possibly reevaluates and then returns the activity of the expression
554 *
555 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
556 */
557 static
558 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
559 {
560 SCIP_CONSHDLRDATA* conshdlrdata;
561
562 assert(scip != NULL);
563 assert(expr != NULL);
564 assert(ownerdata != NULL);
565
566 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
567 assert(conshdlrdata != NULL);
568
569 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
570 {
571 /* update activity of expression */
572 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
573
574 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
575 }
576
577 return SCIP_OKAY;
578 }
579
580 /** callback that creates data that this conshdlr wants to store in an expression */
581 static
582 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
583 {
584 assert(scip != NULL);
585 assert(expr != NULL);
586 assert(ownerdata != NULL);
587
588 SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
589 (*ownerdata)->nenfos = -1;
590 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
591
592 if( SCIPisExprVar(scip, expr) )
593 {
594 SCIP_CONSHDLRDATA* conshdlrdata;
595 SCIP_VAR* var;
596
597 (*ownerdata)->filterpos = -1;
598
599 /* add to var2expr hashmap if not having expr for var yet */
600
601 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
602 assert(conshdlrdata != NULL);
603
604 var = SCIPgetVarExprVar(expr);
605
606 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
607 {
608 /* store the variable expression in the hashmap */
609 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
610 }
611 else
612 {
613 /* if expr was just created, then it shouldn't already be stored as image of var */
614 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
615 }
616 }
617 else
618 {
619 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
620 (*ownerdata)->filterpos = -2;
621 }
622
623 *ownerfree = exprownerFree;
624 *ownerprint = exprownerPrint;
625 *ownerevalactivity = exprownerEvalactivity;
626
627 return SCIP_OKAY;
628 }
629
630 /** creates a variable expression or retrieves from hashmap in conshdlr data */
631 static
632 SCIP_RETCODE createExprVar(
633 SCIP* scip, /**< SCIP data structure */
634 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
635 SCIP_EXPR** expr, /**< pointer where to store expression */
636 SCIP_VAR* var /**< variable to be stored */
637 )
638 {
639 assert(conshdlr != NULL);
640 assert(expr != NULL);
641 assert(var != NULL);
642
643 /* get variable expression representing the given variable if there is one already */
644 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
645
646 if( *expr == NULL )
647 {
648 /* create a new variable expression; this also captures the expression */
649 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
650 assert(*expr != NULL);
651 /* exprownerCreate should have added var->expr to var2expr */
652 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
653 }
654 else
655 {
656 /* only capture already existing expr to get a consistent uses-count */
657 SCIPcaptureExpr(*expr);
658 }
659
660 return SCIP_OKAY;
661 }
662
663 /* map var exprs to var-expr from var2expr hashmap */
664 static
665 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
666 { /*lint --e{715}*/
667 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
668
669 assert(sourcescip != NULL);
670 assert(targetscip != NULL);
671 assert(sourceexpr != NULL);
672 assert(targetexpr != NULL);
673 assert(*targetexpr == NULL);
674 assert(mapexprdata != NULL);
675
676 /* do not provide map if not variable */
677 if( !SCIPisExprVar(sourcescip, sourceexpr) )
678 return SCIP_OKAY;
679
680 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
681
682 return SCIP_OKAY;
683 }
684
685 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
686 static
687 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
688 { /*lint --e{715}*/
689 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
690 SCIP_VAR* var;
691
692 assert(sourcescip != NULL);
693 assert(targetscip != NULL);
694 assert(sourceexpr != NULL);
695 assert(targetexpr != NULL);
696 assert(*targetexpr == NULL);
697 assert(mapexprdata != NULL);
698
699 /* do not provide map if not variable */
700 if( !SCIPisExprVar(sourcescip, sourceexpr) )
701 return SCIP_OKAY;
702
703 var = SCIPgetVarExprVar(sourceexpr);
704 assert(var != NULL);
705
706 /* transform variable */
707 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
708 assert(var != NULL);
709
710 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
711
712 return SCIP_OKAY;
713 }
714
715 /** stores all variable expressions into a given constraint */
716 static
717 SCIP_RETCODE storeVarExprs(
718 SCIP* scip, /**< SCIP data structure */
719 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
720 SCIP_CONSDATA* consdata /**< constraint data */
721 )
722 {
723 SCIP_CONSHDLRDATA* conshdlrdata;
724 int varexprssize;
725 int i;
726
727 assert(consdata != NULL);
728
729 /* skip if we have stored the variable expressions already */
730 if( consdata->varexprs != NULL )
731 return SCIP_OKAY;
732
733 assert(consdata->varexprs == NULL);
734 assert(consdata->nvarexprs == 0);
735
736 /* get an upper bound on number of variable expressions */
737 if( consdata->issimplified )
738 {
739 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
740 * so we cannot have more variable expression than the number of active variables
741 */
742 varexprssize = SCIPgetNVars(scip);
743 }
744 else
745 {
746 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
747 }
748
749 /* create array to store all variable expressions */
750 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
751
752 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
753 assert(varexprssize >= consdata->nvarexprs);
754
755 /* shrink array if there are less variables in the expression than in the problem */
756 if( varexprssize > consdata->nvarexprs )
757 {
758 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
759 }
760
761 conshdlrdata = SCIPconshdlrGetData(conshdlr);
762 assert(conshdlrdata != NULL);
763 assert(conshdlrdata->var2expr != NULL);
764
765 /* ensure that for every variable an entry exists in the var2expr hashmap
766 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
767 */
768 for( i = 0; i < consdata->nvarexprs; ++i )
769 {
770 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
771 {
772 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
773 }
774 }
775
776 return SCIP_OKAY;
777 }
778
779 /** frees all variable expression stored in storeVarExprs() */
780 static
781 SCIP_RETCODE freeVarExprs(
782 SCIP* scip, /**< SCIP data structure */
783 SCIP_CONSDATA* consdata /**< constraint data */
784 )
785 {
786 int i;
787
788 assert(consdata != NULL);
789
790 /* skip if we have stored the variable expressions already*/
791 if( consdata->varexprs == NULL )
792 return SCIP_OKAY;
793
794 assert(consdata->varexprs != NULL);
795 assert(consdata->nvarexprs >= 0);
796
797 /* release variable expressions */
798 for( i = 0; i < consdata->nvarexprs; ++i )
799 {
800 assert(consdata->varexprs[i] != NULL);
801 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
802 assert(consdata->varexprs[i] == NULL);
803 }
804
805 /* free variable expressions */
806 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
807 consdata->varexprs = NULL;
808 consdata->nvarexprs = 0;
809
810 return SCIP_OKAY;
811 }
812
813 /** interval evaluation of variables as used in bound tightening
814 *
815 * Returns slightly relaxed local variable bounds of a variable as interval.
816 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
817 */
818 static
819 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
820 {
821 SCIP_INTERVAL interval;
822 SCIP_CONSHDLRDATA* conshdlrdata;
823 SCIP_Real lb;
824 SCIP_Real ub;
825
826 assert(scip != NULL);
827 assert(var != NULL);
828
829 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
830 assert(conshdlrdata != NULL);
831
832 if( conshdlrdata->globalbounds )
833 {
834 lb = SCIPvarGetLbGlobal(var);
835 ub = SCIPvarGetUbGlobal(var);
836 }
837 else
838 {
839 lb = SCIPvarGetLbLocal(var);
840 ub = SCIPvarGetUbLocal(var);
841 }
842 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
843
844 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
845 if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT )
846 {
847 lb = EPSROUND(lb, 0.0); /*lint !e835*/
848 ub = EPSROUND(ub, 0.0); /*lint !e835*/
849 }
850
851 /* integer variables should always have integral bounds in SCIP */
852 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
853 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
854
855 switch( conshdlrdata->varboundrelax )
856 {
857 case 'n' : /* no relaxation */
858 break;
859
860 case 'a' : /* relax by absolute value */
861 {
862 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
863 if( SCIPvarIsIntegral(var) )
864 break;
865
866 if( !SCIPisInfinity(scip, -lb) )
867 {
868 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
869 SCIP_Real bnd = floor(lb);
870 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
871 }
872
873 if( !SCIPisInfinity(scip, ub) )
874 {
875 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
876 SCIP_Real bnd = ceil(ub);
877 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
878 }
879
880 break;
881 }
882
883 case 'b' : /* relax always by absolute value */
884 {
885 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
886 if( SCIPvarIsIntegral(var) )
887 break;
888
889 if( !SCIPisInfinity(scip, -lb) )
890 lb -= conshdlrdata->varboundrelaxamount;
891
892 if( !SCIPisInfinity(scip, ub) )
893 ub += conshdlrdata->varboundrelaxamount;
894
895 break;
896 }
897
898 case 'r' : /* relax by relative value */
899 {
900 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
901 if( SCIPvarIsIntegral(var) )
902 break;
903
904 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
905 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
906 * further, do not relax beyond next integer value
907 */
908 if( !SCIPisInfinity(scip, -lb) )
909 {
910 SCIP_Real bnd = floor(lb);
911 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
912 }
913
914 if( !SCIPisInfinity(scip, ub) )
915 {
916 SCIP_Real bnd = ceil(ub);
917 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
918 }
919
920 break;
921 }
922
923 default :
924 {
925 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
926 SCIPABORT();
927 break;
928 }
929 }
930
931 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
932 lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
933 ub = infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, ub);
934 assert(lb <= ub);
935
936 SCIPintervalSetBounds(&interval, lb, ub);
937
938 return interval;
939 }
940
941 /** compares two nonlinear constraints by its index
942 *
943 * Usable as compare operator in array sort functions.
944 */
945 static
946 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
947 {
948 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
949 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
950
951 assert(consdata1 != NULL);
952 assert(consdata2 != NULL);
953
954 return consdata1->consindex - consdata2->consindex;
955 }
956
957 /** processes variable fixing or bound change event */
958 static
959 SCIP_DECL_EVENTEXEC(processVarEvent)
960 { /*lint --e{715}*/
961 SCIP_EVENTTYPE eventtype;
962 SCIP_EXPR* expr;
963 SCIP_EXPR_OWNERDATA* ownerdata;
964
965 eventtype = SCIPeventGetType(event);
966 assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED));
967
968 assert(eventdata != NULL);
969 expr = (SCIP_EXPR*) eventdata;
970 assert(SCIPisExprVar(scip, expr));
971
972 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
973 SCIPvarGetName(SCIPeventGetVar(event)),
974 SCIPvarGetLbLocal(SCIPeventGetVar(event)), SCIPvarGetUbLocal(SCIPeventGetVar(event)),
975 SCIPvarGetLbGlobal(SCIPeventGetVar(event)), SCIPvarGetUbGlobal(SCIPeventGetVar(event)));
976
977 ownerdata = SCIPexprGetOwnerData(expr);
978 assert(ownerdata != NULL);
979 /* we only catch varevents for variables in constraints, so there should be constraints */
980 assert(ownerdata->nconss > 0);
981 assert(ownerdata->conss != NULL);
982
983 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
984 * - propagation can only find something new if a bound was tightened
985 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
986 * and we look at global changes (that is, we are not looking at boundchanges in probing)
987 */
988 if( eventtype & (SCIP_EVENTTYPE_BOUNDTIGHTENED | SCIP_EVENTTYPE_VARFIXED) )
989 {
990 SCIP_CONSDATA* consdata;
991 int c;
992
993 for( c = 0; c < ownerdata->nconss; ++c )
994 {
995 assert(ownerdata->conss[c] != NULL);
996 consdata = SCIPconsGetData(ownerdata->conss[c]);
997
998 /* if bound tightening, then mark constraints to be propagated again
999 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1000 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1001 * the locks don't help since they are not available separately for each constraint
1002 */
1003 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1004 {
1005 consdata->ispropagated = FALSE;
1006 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1007 }
1008
1009 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1010 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1011 {
1012 consdata->issimplified = FALSE;
1013 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1014 }
1015 }
1016 }
1017
1018 /* update curboundstag, lastboundrelax, and expr activity */
1019 if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1020 {
1021 SCIP_CONSHDLRDATA* conshdlrdata;
1022 SCIP_INTERVAL activity;
1023
1024 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1025 assert(conshdlrdata != NULL);
1026
1027 /* increase tag on bounds */
1028 ++conshdlrdata->curboundstag;
1029 assert(conshdlrdata->curboundstag > 0);
1030
1031 /* remember also if we relaxed bounds now */
1032 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1033 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1034
1035 /* update the activity of the var-expr here immediately
1036 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1037 */
1038 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1039 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1040 #ifdef DEBUG_PROP
1041 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1042 #endif
1043 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1044 }
1045
1046 return SCIP_OKAY;
1047 }
1048
1049 /** registers event handler to catch variable events on variable
1050 *
1051 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1052 * When an event occurs, all stored constraints are notified.
1053 */
1054 static
1055 SCIP_RETCODE catchVarEvent(
1056 SCIP* scip, /**< SCIP data structure */
1057 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1058 SCIP_EXPR* expr, /**< variable expression */
1059 SCIP_CONS* cons /**< nonlinear constraint */
1060 )
1061 {
1062 SCIP_EXPR_OWNERDATA* ownerdata;
1063
1064 assert(eventhdlr != NULL);
1065 assert(expr != NULL);
1066 assert(SCIPisExprVar(scip, expr));
1067 assert(cons != NULL);
1068
1069 ownerdata = SCIPexprGetOwnerData(expr);
1070 assert(ownerdata != NULL);
1071
1072 #ifndef NDEBUG
1073 /* assert that constraint does not double-catch variable */
1074 {
1075 int i;
1076 for( i = 0; i < ownerdata->nconss; ++i )
1077 assert(ownerdata->conss[i] != cons);
1078 }
1079 #endif
1080
1081 /* append cons to ownerdata->conss */
1082 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1083 ownerdata->conss[ownerdata->nconss++] = cons;
1084 /* we're not capturing the constraint here to avoid circular references */
1085
1086 /* updated sorted flag */
1087 if( ownerdata->nconss <= 1 )
1088 ownerdata->consssorted = TRUE;
1089 else if( ownerdata->consssorted )
1090 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1091
1092 /* catch variable events, if not done so yet (first constraint) */
1093 if( ownerdata->filterpos < 0 )
1094 {
1095 SCIP_EVENTTYPE eventtype;
1096
1097 assert(ownerdata->nconss == 1);
1098
1099 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1100
1101 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1102 assert(ownerdata->filterpos >= 0);
1103 }
1104
1105 return SCIP_OKAY;
1106 }
1107
1108 /** catch variable events */
1109 static
1110 SCIP_RETCODE catchVarEvents(
1111 SCIP* scip, /**< SCIP data structure */
1112 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1113 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1114 )
1115 {
1116 SCIP_CONSHDLRDATA* conshdlrdata;
1117 SCIP_CONSDATA* consdata;
1118 SCIP_EXPR* expr;
1119 int i;
1120
1121 assert(eventhdlr != NULL);
1122 assert(cons != NULL);
1123
1124 consdata = SCIPconsGetData(cons);
1125 assert(consdata != NULL);
1126 assert(consdata->varexprs != NULL);
1127 assert(consdata->nvarexprs >= 0);
1128
1129 /* check if we have catched variable events already */
1130 if( consdata->catchedevents )
1131 return SCIP_OKAY;
1132
1133 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1134 assert(conshdlrdata != NULL);
1135 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1136
1137 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1138
1139 for( i = 0; i < consdata->nvarexprs; ++i )
1140 {
1141 expr = consdata->varexprs[i];
1142
1143 assert(expr != NULL);
1144 assert(SCIPisExprVar(scip, expr));
1145
1146 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1147
1148 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1149 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1150 */
1151 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1152 {
1153 SCIP_INTERVAL activity;
1154 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1155 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1156 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1157 #ifdef DEBUG_PROP
1158 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1159 #endif
1160 }
1161 }
1162
1163 consdata->catchedevents = TRUE;
1164
1165 return SCIP_OKAY;
1166 }
1167
1168 /** unregisters event handler to catch variable events on variable
1169 *
1170 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1171 * If this was the last constraint, then the event handler is unregistered for this variable.
1172 */
1173 static
1174 SCIP_RETCODE dropVarEvent(
1175 SCIP* scip, /**< SCIP data structure */
1176 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1177 SCIP_EXPR* expr, /**< variable expression */
1178 SCIP_CONS* cons /**< expr constraint */
1179 )
1180 {
1181 SCIP_EXPR_OWNERDATA* ownerdata;
1182 int pos;
1183
1184 assert(eventhdlr != NULL);
1185 assert(expr != NULL);
1186 assert(SCIPisExprVar(scip, expr));
1187 assert(cons != NULL);
1188
1189 ownerdata = SCIPexprGetOwnerData(expr);
1190 assert(ownerdata != NULL);
1191 assert(ownerdata->nconss > 0);
1192
1193 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1194 {
1195 pos = ownerdata->nconss-1;
1196 }
1197 else
1198 {
1199 if( !ownerdata->consssorted )
1200 {
1201 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1202 ownerdata->consssorted = TRUE;
1203 }
1204
1205 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1206 {
1207 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1208 return SCIP_ERROR;
1209 }
1210 assert(pos >= 0 && pos < ownerdata->nconss);
1211 }
1212 assert(ownerdata->conss[pos] == cons);
1213
1214 /* move last constraint into position of removed constraint */
1215 if( pos < ownerdata->nconss-1 )
1216 {
1217 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1218 ownerdata->consssorted = FALSE;
1219 }
1220 --ownerdata->nconss;
1221
1222 /* drop variable events if that was the last constraint */
1223 if( ownerdata->nconss == 0 )
1224 {
1225 SCIP_EVENTTYPE eventtype;
1226
1227 assert(ownerdata->filterpos >= 0);
1228
1229 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1230
1231 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1232 ownerdata->filterpos = -1;
1233 }
1234
1235 return SCIP_OKAY;
1236 }
1237
1238 /** drop variable events */
1239 static
1240 SCIP_RETCODE dropVarEvents(
1241 SCIP* scip, /**< SCIP data structure */
1242 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1243 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1244 )
1245 {
1246 SCIP_CONSDATA* consdata;
1247 int i;
1248
1249 assert(eventhdlr != NULL);
1250 assert(cons != NULL);
1251
1252 consdata = SCIPconsGetData(cons);
1253 assert(consdata != NULL);
1254
1255 /* check if we have catched variable events already */
1256 if( !consdata->catchedevents )
1257 return SCIP_OKAY;
1258
1259 assert(consdata->varexprs != NULL);
1260 assert(consdata->nvarexprs >= 0);
1261
1262 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1263
1264 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1265 {
1266 assert(consdata->varexprs[i] != NULL);
1267
1268 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1269 }
1270
1271 consdata->catchedevents = FALSE;
1272
1273 return SCIP_OKAY;
1274 }
1275
1276 /** creates and captures a nonlinear constraint
1277 *
1278 * @attention Use copyexpr=FALSE only if expr is already "owned" by conshdlr, that is, if expressions were created with exprownerCreate() and ownerdata passed in the last two arguments
1279 */
1280 static
1281 SCIP_RETCODE createCons(
1282 SCIP* scip, /**< SCIP data structure */
1283 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1284 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1285 const char* name, /**< name of constraint */
1286 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1287 SCIP_Real lhs, /**< left hand side of constraint */
1288 SCIP_Real rhs, /**< right hand side of constraint */
1289 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1290 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1291 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1292 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1293 * Usually set to TRUE. */
1294 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1295 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1296 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1297 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1298 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1299 * Usually set to TRUE. */
1300 SCIP_Bool local, /**< is constraint only valid locally?
1301 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1302 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1303 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1304 * adds coefficients to this constraint. */
1305 SCIP_Bool dynamic, /**< is constraint subject to aging?
1306 * Usually set to FALSE. Set to TRUE for own cuts which
1307 * are separated as constraints. */
1308 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1309 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1310 )
1311 {
1312 SCIP_CONSHDLRDATA* conshdlrdata;
1313 SCIP_CONSDATA* consdata;
1314
1315 assert(conshdlr != NULL);
1316 assert(expr != NULL);
1317
1318 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1319 assert(conshdlrdata != NULL);
1320
1321 if( local && SCIPgetDepth(scip) != 0 )
1322 {
1323 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1324 return SCIP_INVALIDCALL;
1325 }
1326
1327 /* TODO we should allow for non-initial nonlinear constraints */
1328 if( !initial )
1329 {
1330 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1331 return SCIP_INVALIDCALL;
1332 }
1333
1334 /* create constraint data */
1335 SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1336
1337 if( copyexpr )
1338 {
1339 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1340 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1341 }
1342 else
1343 {
1344 consdata->expr = expr;
1345 SCIPcaptureExpr(consdata->expr);
1346 }
1347 consdata->lhs = lhs;
1348 consdata->rhs = rhs;
1349 consdata->consindex = conshdlrdata->lastconsindex++;
1350 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1351
1352 /* create constraint */
1353 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1354 local, modifiable, dynamic, removable, FALSE) );
1355
1356 return SCIP_OKAY;
1357 }
1358
1359 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1360 *
1361 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1362 * Assume that f(x) is associated with auxiliary variable z.
1363 *
1364 * If there are negative locks, then return the violation of z ≤ f(x) and sets `violover` to TRUE.
1365 * If there are positive locks, then return the violation of z ≥ f(x) and sets `violunder` to TRUE.
1366 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1367 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1368 *
1369 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1370 */
1371 static
1372 SCIP_Real getExprAbsOrigViolation(
1373 SCIP* scip, /**< SCIP data structure */
1374 SCIP_EXPR* expr, /**< expression */
1375 SCIP_SOL* sol, /**< solution that has been evaluated */
1376 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1377 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1378 )
1379 {
1380 SCIP_EXPR_OWNERDATA* ownerdata;
1381 SCIP_Real auxvarvalue;
1382
1383 assert(expr != NULL);
1384
1385 ownerdata = SCIPexprGetOwnerData(expr);
1386 assert(ownerdata != NULL);
1387 assert(ownerdata->auxvar != NULL);
1388
1389 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1390 {
1391 if( violunder != NULL )
1392 *violunder = TRUE;
1393 if( violover != NULL )
1394 *violover = TRUE;
1395 return SCIPinfinity(scip);
1396 }
1397
1398 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1399
1400 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1401 {
1402 if( violunder != NULL )
1403 *violunder = FALSE;
1404 if( violover != NULL )
1405 *violover = TRUE;
1406 return auxvarvalue - SCIPexprGetEvalValue(expr);
1407 }
1408
1409 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1410 {
1411 if( violunder != NULL )
1412 *violunder = TRUE;
1413 if( violover != NULL )
1414 *violover = FALSE;
1415 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1416 }
1417
1418 if( violunder != NULL )
1419 *violunder = FALSE;
1420 if( violover != NULL )
1421 *violover = FALSE;
1422 return 0.0;
1423 }
1424
1425 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1426 *
1427 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1428 * Assume that f(w) is associated with auxiliary variable z.
1429 *
1430 * If there are negative locks, then return the violation of z ≤ f(w) and sets `violover` to TRUE.
1431 * If there are positive locks, then return the violation of z ≥ f(w) and sets `violunder` to TRUE.
1432 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1433 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1434 *
1435 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1436 */
1437 static
1438 SCIP_Real getExprAbsAuxViolation(
1439 SCIP* scip, /**< SCIP data structure */
1440 SCIP_EXPR* expr, /**< expression */
1441 SCIP_Real auxvalue, /**< value of f(w) */
1442 SCIP_SOL* sol, /**< solution that has been evaluated */
1443 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1444 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1445 )
1446 {
1447 SCIP_EXPR_OWNERDATA* ownerdata;
1448 SCIP_Real auxvarvalue;
1449
1450 assert(expr != NULL);
1451
1452 ownerdata = SCIPexprGetOwnerData(expr);
1453 assert(ownerdata != NULL);
1454 assert(ownerdata->auxvar != NULL);
1455
1456 if( auxvalue == SCIP_INVALID )
1457 {
1458 if( violunder != NULL )
1459 *violunder = TRUE;
1460 if( violover != NULL )
1461 *violover = TRUE;
1462 return SCIPinfinity(scip);
1463 }
1464
1465 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1466
1467 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1468 {
1469 if( violunder != NULL )
1470 *violunder = FALSE;
1471 if( violover != NULL )
1472 *violover = TRUE;
1473 return auxvarvalue - auxvalue;
1474 }
1475
1476 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1477 {
1478 if( violunder != NULL )
1479 *violunder = TRUE;
1480 if( violover != NULL )
1481 *violover = FALSE;
1482 return auxvalue - auxvarvalue;
1483 }
1484
1485 if( violunder != NULL )
1486 *violunder = FALSE;
1487 if( violover != NULL )
1488 *violover = FALSE;
1489
1490 return 0.0;
1491 }
1492
1493 /** computes violation of a constraint */
1494 static
1495 SCIP_RETCODE computeViolation(
1496 SCIP* scip, /**< SCIP data structure */
1497 SCIP_CONS* cons, /**< constraint */
1498 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1499 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1500 )
1501 {
1502 SCIP_CONSDATA* consdata;
1503 SCIP_Real activity;
1504
1505 assert(scip != NULL);
1506 assert(cons != NULL);
1507
1508 consdata = SCIPconsGetData(cons);
1509 assert(consdata != NULL);
1510
1511 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1512 activity = SCIPexprGetEvalValue(consdata->expr);
1513
1514 /* consider constraint as violated if it is undefined in the current point */
1515 if( activity == SCIP_INVALID )
1516 {
1517 consdata->lhsviol = SCIPinfinity(scip);
1518 consdata->rhsviol = SCIPinfinity(scip);
1519 return SCIP_OKAY;
1520 }
1521
1522 /* compute violations */
1523 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1524 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1525
1526 return SCIP_OKAY;
1527 }
1528
1529 /** returns absolute violation of a constraint
1530 *
1531 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1532 */
1533 static
1534 SCIP_Real getConsAbsViolation(
1535 SCIP_CONS* cons /**< constraint */
1536 )
1537 {
1538 SCIP_CONSDATA* consdata;
1539
1540 assert(cons != NULL);
1541
1542 consdata = SCIPconsGetData(cons);
1543 assert(consdata != NULL);
1544
1545 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1546 }
1547
1548 /** computes relative violation of a constraint
1549 *
1550 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1551 */
1552 static
1553 SCIP_RETCODE getConsRelViolation(
1554 SCIP* scip, /**< SCIP data structure */
1555 SCIP_CONS* cons, /**< constraint */
1556 SCIP_Real* viol, /**< buffer to store violation */
1557 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1558 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1559 )
1560 {
1561 SCIP_CONSHDLR* conshdlr;
1562 SCIP_CONSHDLRDATA* conshdlrdata;
1563 SCIP_CONSDATA* consdata;
1564 SCIP_Real scale;
1565
1566 assert(cons != NULL);
1567 assert(viol != NULL);
1568
1569 conshdlr = SCIPconsGetHdlr(cons);
1570 assert(conshdlr != NULL);
1571
1572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1573 assert(conshdlrdata != NULL);
1574
1575 *viol = getConsAbsViolation(cons);
1576
1577 if( conshdlrdata->violscale == 'n' )
1578 return SCIP_OKAY;
1579
1580 if( SCIPisInfinity(scip, *viol) )
1581 return SCIP_OKAY;
1582
1583 consdata = SCIPconsGetData(cons);
1584 assert(consdata != NULL);
1585
1586 if( conshdlrdata->violscale == 'a' )
1587 {
1588 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1589
1590 /* consider value of side that is violated for scaling, too */
1591 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1592 {
1593 assert(!SCIPisInfinity(scip, -consdata->lhs));
1594 scale = REALABS(consdata->lhs);
1595 }
1596 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1597 {
1598 assert(!SCIPisInfinity(scip, consdata->rhs));
1599 scale = REALABS(consdata->rhs);
1600 }
1601
1602 *viol /= scale;
1603 return SCIP_OKAY;
1604 }
1605
1606 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1607 assert(conshdlrdata->violscale == 'g');
1608 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1609 {
1610 /* we need the varexprs to conveniently access the gradient */
1611 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1612
1613 /* update cached value of norm of gradient */
1614 consdata->gradnorm = 0.0;
1615
1616 /* compute gradient */
1617 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1618
1619 /* gradient evaluation error -> no scaling */
1620 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1621 {
1622 int i;
1623 for( i = 0; i < consdata->nvarexprs; ++i )
1624 {
1625 SCIP_Real deriv;
1626
1627 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1628 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1629 if( deriv == SCIP_INVALID )
1630 {
1631 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1632 consdata->gradnorm = 0.0;
1633 break;
1634 }
1635
1636 consdata->gradnorm += deriv*deriv;
1637 }
1638 }
1639 consdata->gradnorm = sqrt(consdata->gradnorm);
1640 consdata->gradnormsoltag = soltag;
1641 }
1642
1643 *viol /= MAX(1.0, consdata->gradnorm);
1644
1645 return SCIP_OKAY;
1646 }
1647
1648 /** returns whether constraint is currently violated
1649 *
1650 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1651 */
1652 static
1653 SCIP_Bool isConsViolated(
1654 SCIP* scip, /**< SCIP data structure */
1655 SCIP_CONS* cons /**< constraint */
1656 )
1657 {
1658 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1659 }
1660
1661 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1662 static
1663 void findUnlockedLinearVar(
1664 SCIP* scip, /**< SCIP data structure */
1665 SCIP_CONS* cons /**< constraint */
1666 )
1667 {
1668 SCIP_CONSDATA* consdata;
1669 int poslock;
1670 int neglock;
1671 int i;
1672
1673 assert(cons != NULL);
1674
1675 consdata = SCIPconsGetData(cons);
1676 assert(consdata != NULL);
1677
1678 consdata->linvarincr = NULL;
1679 consdata->linvardecr = NULL;
1680 consdata->linvarincrcoef = 0.0;
1681 consdata->linvardecrcoef = 0.0;
1682
1683 /* root expression is not a sum -> no unlocked linear variable available */
1684 if( !SCIPisExprSum(scip, consdata->expr) )
1685 return;
1686
1687 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1688 {
1689 SCIP_EXPR* child;
1690
1691 child = SCIPexprGetChildren(consdata->expr)[i];
1692 assert(child != NULL);
1693
1694 /* check whether the child is a variable expression */
1695 if( SCIPisExprVar(scip, child) )
1696 {
1697 SCIP_VAR* var = SCIPgetVarExprVar(child);
1698 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1699
1700 if( coef > 0.0 )
1701 {
1702 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1703 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1704 }
1705 else
1706 {
1707 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1708 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1709 }
1710 SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1711
1712 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1713 {
1714 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1715 * if we have already one candidate, then take the one where the loss in the objective function is less
1716 */
1717 if( (consdata->linvardecr == NULL) ||
1718 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1719 {
1720 consdata->linvardecr = var;
1721 consdata->linvardecrcoef = coef;
1722 }
1723 }
1724
1725 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1726 {
1727 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1728 * if we have already one candidate, then take the one where the loss in the objective function is less
1729 */
1730 if( (consdata->linvarincr == NULL) ||
1731 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1732 {
1733 consdata->linvarincr = var;
1734 consdata->linvarincrcoef = coef;
1735 }
1736 }
1737 }
1738 }
1739
1740 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1741 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1742
1743 if( consdata->linvarincr != NULL )
1744 {
1745 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1746 }
1747 if( consdata->linvardecr != NULL )
1748 {
1749 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1750 }
1751 }
1752
1753 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1754 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1755 *
1756 * The method assumes that this is always possible and that not all constraints are feasible already.
1757 */
1758 static
1759 SCIP_RETCODE proposeFeasibleSolution(
1760 SCIP* scip, /**< SCIP data structure */
1761 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1762 SCIP_CONS** conss, /**< constraints to process */
1763 int nconss, /**< number of constraints */
1764 SCIP_SOL* sol, /**< solution to process */
1765 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1766 )
1767 {
1768 SCIP_CONSHDLRDATA* conshdlrdata;
1769 SCIP_SOL* newsol;
1770 int c;
1771
1772 assert(scip != NULL);
1773 assert(conshdlr != NULL);
1774 assert(conss != NULL || nconss == 0);
1775 assert(success != NULL);
1776
1777 *success = FALSE;
1778
1779 /* don't propose new solutions if not in presolve or solving */
1780 if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE || SCIPgetStage(scip) >= SCIP_STAGE_SOLVED )
1781 return SCIP_OKAY;
1782
1783 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1784 assert(conshdlrdata != NULL);
1785
1786 if( sol != NULL )
1787 {
1788 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1789 }
1790 else
1791 {
1792 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1793 }
1794 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1795 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1796 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1797
1798 for( c = 0; c < nconss; ++c )
1799 {
1800 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1801 SCIP_Real viol = 0.0;
1802 SCIP_Real delta;
1803 SCIP_Real gap;
1804
1805 assert(consdata != NULL);
1806
1807 /* get absolute violation and sign */
1808 if( consdata->lhsviol > SCIPfeastol(scip) )
1809 viol = consdata->lhsviol; /* lhs - activity */
1810 else if( consdata->rhsviol > SCIPfeastol(scip) )
1811 viol = -consdata->rhsviol; /* rhs - activity */
1812 else
1813 continue; /* constraint is satisfied */
1814
1815 if( consdata->linvarincr != NULL &&
1816 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1817 {
1818 SCIP_VAR* var = consdata->linvarincr;
1819
1820 /* compute how much we would like to increase var */
1821 delta = viol / consdata->linvarincrcoef;
1822 assert(delta > 0.0);
1823
1824 /* if var has an upper bound, may need to reduce delta */
1825 if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1826 {
1827 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1828 delta = MIN(MAX(0.0, gap), delta);
1829 }
1830 if( SCIPisPositive(scip, delta) )
1831 {
1832 /* if variable is integral, round delta up so that it will still have an integer value */
1833 if( SCIPvarIsIntegral(var) )
1834 delta = SCIPceil(scip, delta);
1835
1836 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1837 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1838 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1839
1840 /* adjust constraint violation, if satisfied go on to next constraint */
1841 viol -= consdata->linvarincrcoef * delta;
1842 if( SCIPisZero(scip, viol) )
1843 continue;
1844 }
1845 }
1846
1847 assert(viol != 0.0);
1848 if( consdata->linvardecr != NULL &&
1849 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1850 {
1851 SCIP_VAR* var = consdata->linvardecr;
1852
1853 /* compute how much we would like to decrease var */
1854 delta = viol / consdata->linvardecrcoef;
1855 assert(delta < 0.0);
1856
1857 /* if var has a lower bound, may need to reduce delta */
1858 if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1859 {
1860 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1861 delta = MAX(MIN(0.0, gap), delta);
1862 }
1863 if( SCIPisNegative(scip, delta) )
1864 {
1865 /* if variable is integral, round delta down so that it will still have an integer value */
1866 if( SCIPvarIsIntegral(var) )
1867 delta = SCIPfloor(scip, delta);
1868 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1869 /*lint --e{613} */
1870 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1871 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1872
1873 /* adjust constraint violation, if satisfied go on to next constraint */
1874 viol -= consdata->linvardecrcoef * delta;
1875 if( SCIPisZero(scip, viol) )
1876 continue;
1877 }
1878 }
1879
1880 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1881 break;
1882 }
1883
1884 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1885 * then pass it to the trysol heuristic
1886 */
1887 if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1888 {
1889 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1890
1891 assert(conshdlrdata->trysolheur != NULL);
1892 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1893
1894 *success = TRUE;
1895 }
1896
1897 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1898
1899 return SCIP_OKAY;
1900 }
1901
1902 /** adds globally valid tight estimators in a given solution as cut to cutpool
1903 *
1904 * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1905 */
1906 static
1907 SCIP_RETCODE addTightEstimatorCut(
1908 SCIP* scip, /**< SCIP data structure */
1909 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1910 SCIP_CONS* cons, /**< constraint */
1911 SCIP_EXPR* expr, /**< expression */
1912 EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1913 SCIP_SOL* sol, /**< reference point where to estimate */
1914 SCIP_Bool overestimate, /**< whether to overestimate */
1915 SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1916 )
1917 {
1918 SCIP_Bool estimatesuccess = FALSE;
1919 SCIP_Bool branchscoresuccess = FALSE;
1920 int minidx;
1921 int maxidx;
1922 int r;
1923
1924 assert(scip != NULL);
1925 assert(expr != NULL);
1926 assert(exprenfo != NULL);
1927 assert(rowpreps != NULL);
1928
1929 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1930 overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1931
1932 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1933 exprenfo->auxvalue, overestimate, SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1934
1935 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1936 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1937 assert(estimatesuccess == (minidx <= maxidx));
1938
1939 if( !estimatesuccess )
1940 {
1941 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1942 return SCIP_OKAY;
1943 }
1944
1945 for( r = minidx; r <= maxidx; ++r )
1946 {
1947 SCIP_ROWPREP* rowprep;
1948 SCIP_ROW* row;
1949 SCIP_Real estimateval;
1950 int i;
1951
1952 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1953 assert(rowprep != NULL);
1954 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1955
1956 /* if estimators is only local valid, then skip */
1957 if( SCIProwprepIsLocal(rowprep) )
1958 {
1959 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1960 SCIPfreeRowprep(scip, &rowprep);
1961 continue;
1962 }
1963
1964 /* compute value of estimator */
1965 estimateval = -SCIProwprepGetSide(rowprep);
1966 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1967 estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1968
1969 /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1970 if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1971 (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1972 {
1973 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1974 SCIPfreeRowprep(scip, &rowprep);
1975 continue;
1976 }
1977
1978 /* complete estimator to cut and clean it up */
1979 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1980 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1981
1982 /* if cleanup failed or rowprep is local now, then skip */
1983 if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1984 {
1985 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1986 SCIPfreeRowprep(scip, &rowprep);
1987 continue;
1988 }
1989
1990 /* generate row and add to cutpool */
1991 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
1992
1993 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
1994 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
1995
1996 SCIP_CALL( SCIPaddPoolCut(scip, row) );
1997 /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
1998
1999 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2000 SCIPfreeRowprep(scip, &rowprep);
2001 }
2002
2003 SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2004
2005 return SCIP_OKAY;
2006 }
2007
2008 /** adds globally valid tight estimators in a given solution as cuts to cutpool
2009 *
2010 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2011 * For convex constraints, we would achieve this by linearizing.
2012 * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2013 * use bound information and check whether the estimator is tight.
2014 *
2015 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2016 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2017 */
2018 static
2019 SCIP_RETCODE addTightEstimatorCuts(
2020 SCIP* scip, /**< SCIP data structure */
2021 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2022 SCIP_CONS** conss, /**< constraints */
2023 int nconss, /**< number of constraints */
2024 SCIP_SOL* sol /**< reference point where to estimate */
2025 )
2026 {
2027 SCIP_CONSDATA* consdata;
2028 SCIP_Longint soltag;
2029 SCIP_EXPRITER* it;
2030 SCIP_EXPR* expr;
2031 SCIP_PTRARRAY* rowpreps;
2032 int c, e;
2033
2034 assert(scip != NULL);
2035 assert(conshdlr != NULL);
2036 assert(conss != NULL || nconss == 0);
2037
2038 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2039
2040 /* TODO probably we just evaluated all expressions when checking the sol before it was added
2041 * would be nice to recognize this and skip reevaluating
2042 */
2043 soltag = SCIPgetExprNewSoltag(scip);
2044
2045 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2046
2047 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2048 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
2049 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
2050
2051 for( c = 0; c < nconss; ++c )
2052 {
2053 /* skip constraints that are not enabled or deleted or have separation disabled */
2054 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2055 continue;
2056 assert(SCIPconsIsActive(conss[c]));
2057
2058 consdata = SCIPconsGetData(conss[c]);
2059 assert(consdata != NULL);
2060
2061 /* TODO we could remember for which constraints there is a chance that we would add anything,
2062 * i.e., there is some convex-like expression, and skip other constraints
2063 */
2064
2065 ENFOLOG(
2066 {
2067 int i;
2068 SCIPinfoMessage(scip, enfologfile, " constraint ");
2069 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2070 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2071 for( i = 0; i < consdata->nvarexprs; ++i )
2072 {
2073 SCIP_VAR* var;
2074 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2075 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2076 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2077 }
2078 })
2079
2080 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2081 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2082
2083 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2084 {
2085 SCIP_EXPR_OWNERDATA* ownerdata;
2086
2087 ownerdata = SCIPexprGetOwnerData(expr);
2088 assert(ownerdata != NULL);
2089
2090 /* we can only generate a cut from an estimator if there is an auxvar */
2091 if( ownerdata->auxvar == NULL )
2092 continue;
2093
2094 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2095 assert(SCIPexprGetEvalTag(expr) == soltag);
2096 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2097 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2098
2099 /* generate cuts from estimators of each nonlinear handler that provides estimates */
2100 for( e = 0; e < ownerdata->nenfos; ++e )
2101 {
2102 SCIP_NLHDLR* nlhdlr;
2103
2104 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2105 assert(nlhdlr != NULL);
2106
2107 /* skip nlhdlr that does not implement estimate (so it does enfo) */
2108 if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2109 continue;
2110
2111 /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2112 * (because it uses activities on vars/auxvars)
2113 */
2114 if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2115 ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2116 continue;
2117
2118 /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2119 if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2120 continue;
2121
2122 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2123 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2124 ENFOLOG(
2125 SCIPinfoMessage(scip, enfologfile, " expr ");
2126 SCIPprintExpr(scip, expr, enfologfile);
2127 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2128 (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2129 )
2130 /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2131 assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2132
2133 /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2134 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2135 {
2136 SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2137 }
2138
2139 /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2140 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2141 {
2142 SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2143 }
2144 }
2145 }
2146 }
2147
2148 SCIPfreeExpriter(&it);
2149 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2150
2151 return SCIP_OKAY;
2152 }
2153
2154 /** processes the event that a new primal solution has been found */
2155 static
2156 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2157 {
2158 SCIP_CONSHDLR* conshdlr;
2159 SCIP_CONSHDLRDATA* conshdlrdata;
2160 SCIP_SOL* sol;
2161
2162 assert(scip != NULL);
2163 assert(event != NULL);
2164 assert(eventdata != NULL);
2165 assert(eventhdlr != NULL);
2166 assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2167
2168 conshdlr = (SCIP_CONSHDLR*)eventdata;
2169
2170 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2171 return SCIP_OKAY;
2172
2173 sol = SCIPeventGetSol(event);
2174 assert(sol != NULL);
2175
2176 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2177 assert(conshdlrdata != NULL);
2178
2179 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2180 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2181 * from the tree, but postprocessed via proposeFeasibleSolution
2182 */
2183 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2184 return SCIP_OKAY;
2185
2186 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2187
2188 SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2189
2190 return SCIP_OKAY;
2191 }
2192
2193 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2194 *
2195 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2196 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2197 *
2198 * Nothing will happen if SCIP is not in presolve or solve.
2199 */
2200 static
2201 SCIP_RETCODE tightenAuxVarBounds(
2202 SCIP* scip, /**< SCIP data structure */
2203 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2204 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2205 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2206 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2207 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2208 )
2209 {
2210 SCIP_VAR* var;
2211 SCIP_Bool tightenedlb;
2212 SCIP_Bool tightenedub;
2213 SCIP_Bool force;
2214
2215 assert(scip != NULL);
2216 assert(conshdlr != NULL);
2217 assert(expr != NULL);
2218 assert(cutoff != NULL);
2219
2220 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2221 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2222
2223 *cutoff = FALSE;
2224
2225 /* do not tighten variable in problem stage (important for unittests)
2226 * TODO put some kind of #ifdef UNITTEST around this
2227 */
2228 if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE && SCIPgetStage(scip) > SCIP_STAGE_SOLVING )
2229 return SCIP_OKAY;
2230
2231 var = SCIPgetExprAuxVarNonlinear(expr);
2232 if( var == NULL )
2233 return SCIP_OKAY;
2234
2235 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2236 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2237
2238 /* try to tighten lower bound of (auxiliary) variable */
2239 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2240 if( tightenedlb )
2241 {
2242 if( ntightenings != NULL )
2243 ++*ntightenings;
2244 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2245 }
2246 if( *cutoff )
2247 {
2248 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2249 return SCIP_OKAY;
2250 }
2251
2252 /* try to tighten upper bound of (auxiliary) variable */
2253 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2254 if( tightenedub )
2255 {
2256 if( ntightenings != NULL )
2257 ++*ntightenings;
2258 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2259 }
2260 if( *cutoff )
2261 {
2262 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2263 return SCIP_OKAY;
2264 }
2265
2266 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2267 * that seems unnecessary and we could easily undo this here, e.g.,
2268 * if( tightenedlb ) expr->activity.inf = bounds.inf
2269 */
2270
2271 return SCIP_OKAY;
2272 }
2273
2274 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2275 * and tries to tighten the bounds of the auxiliary variables accordingly
2276 */
2277 static
2278 SCIP_RETCODE forwardPropExpr(
2279 SCIP* scip, /**< SCIP data structure */
2280 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2281 SCIP_EXPR* rootexpr, /**< expression */
2282 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2283 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2284 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2285 )
2286 {
2287 SCIP_EXPRITER* it;
2288 SCIP_EXPR* expr;
2289 SCIP_EXPR_OWNERDATA* ownerdata;
2290 SCIP_CONSHDLRDATA* conshdlrdata;
2291
2292 assert(scip != NULL);
2293 assert(rootexpr != NULL);
2294
2295 if( infeasible != NULL )
2296 *infeasible = FALSE;
2297 if( ntightenings != NULL )
2298 *ntightenings = 0;
2299
2300 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2301 assert(conshdlrdata != NULL);
2302
2303 /* if value is valid and empty, then we cannot improve, so do nothing */
2304 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2305 {
2306 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2307
2308 if( infeasible != NULL )
2309 *infeasible = TRUE;
2310
2311 /* just update tag to curboundstag */
2312 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2313
2314 return SCIP_OKAY;
2315 }
2316
2317 /* if value is up-to-date, then nothing to do */
2318 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2319 {
2320 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2321
2322 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2323
2324 return SCIP_OKAY;
2325 }
2326
2327 ownerdata = SCIPexprGetOwnerData(rootexpr);
2328 assert(ownerdata != NULL);
2329
2330 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2331 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2332 * during detect, we are in some in-between state where we may want to eval activity
2333 * on exprs that we did not notify about their activity usage
2334 */
2335 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2336 {
2337 #ifdef DEBUG_PROP
2338 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2339 #endif
2340 SCIPABORT();
2341 return SCIP_OKAY;
2342 }
2343
2344 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2345 SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2346 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2347
2348 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2349 {
2350 switch( SCIPexpriterGetStageDFS(it) )
2351 {
2352 case SCIP_EXPRITER_VISITINGCHILD :
2353 {
2354 /* skip child if it has been evaluated already */
2355 SCIP_EXPR* child;
2356
2357 child = SCIPexpriterGetChildExprDFS(it);
2358 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2359 {
2360 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2361 *infeasible = TRUE;
2362
2363 expr = SCIPexpriterSkipDFS(it);
2364 continue;
2365 }
2366
2367 break;
2368 }
2369
2370 case SCIP_EXPRITER_LEAVEEXPR :
2371 {
2372 SCIP_INTERVAL activity;
2373
2374 /* we should not have entered this expression if its activity was already up to date */
2375 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2376
2377 ownerdata = SCIPexprGetOwnerData(expr);
2378 assert(ownerdata != NULL);
2379
2380 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2381 * so we can assume that the activity is up to date for all these variables
2382 * UNLESS we changed the method used to evaluate activity of variable expressions
2383 * or we currently use global bounds (varevents are catched for local bound changes only)
2384 */
2385 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2386 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2387 {
2388 #ifndef NDEBUG
2389 SCIP_INTERVAL exprhdlrinterval;
2390
2391 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2392 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2393 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2394 #endif
2395 #ifdef DEBUG_PROP
2396 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2397 #endif
2398 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2399
2400 break;
2401 }
2402
2403 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2404 {
2405 /* start with entire activity if current one is invalid */
2406 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
2407 }
2408 else if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)) )
2409 {
2410 /* If already empty, then don't try to compute even better activity.
2411 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2412 * so an assert(infeasible == NULL || *infeasible) should work here.
2413 * However, after reporting a cutoff due to expr->activity being empty,
2414 * SCIP may wander to a different node and call propagation again.
2415 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2416 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2417 * we will still have expr->activity being empty, but will have forgotten
2418 * that we found infeasibility here before (!2221#note_134120).
2419 * Therefore we just set *infeasibility=TRUE here and stop.
2420 */
2421 if( infeasible != NULL )
2422 *infeasible = TRUE;
2423 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2424 break;
2425 }
2426 else
2427 {
2428 /* start with current activity, since it is valid */
2429 activity = SCIPexprGetActivity(expr);
2430 }
2431
2432 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2433 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2434 {
2435 #ifdef DEBUG_PROP
2436 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2437 #endif
2438 break;
2439 }
2440
2441 #ifdef DEBUG_PROP
2442 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2443 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2444 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2445 #endif
2446
2447 /* run interval eval of nonlinear handlers or expression handler */
2448 if( ownerdata->nenfos > 0 )
2449 {
2450 SCIP_NLHDLR* nlhdlr;
2451 SCIP_INTERVAL nlhdlrinterval;
2452 int e;
2453
2454 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2455 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2456 {
2457 /* skip nlhdlr if it does not want to participate in activity computation */
2458 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2459 continue;
2460
2461 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2462 assert(nlhdlr != NULL);
2463
2464 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2465 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2466 continue;
2467
2468 /* let nlhdlr evaluate current expression */
2469 nlhdlrinterval = activity;
2470 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2471 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2472 #ifdef DEBUG_PROP
2473 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2474 #endif
2475
2476 /* update activity by intersecting with computed activity */
2477 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2478 #ifdef DEBUG_PROP
2479 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2480 #endif
2481 }
2482 }
2483 else
2484 {
2485 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2486 SCIP_INTERVAL exprhdlrinterval = activity;
2487 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2488 #ifdef DEBUG_PROP
2489 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2490 #endif
2491
2492 /* update expr->activity by intersecting with computed activity */
2493 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2494 #ifdef DEBUG_PROP
2495 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2496 #endif
2497 }
2498
2499 /* if expression is integral, then we try to tighten the interval bounds a bit
2500 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2501 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2502 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2503 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2504 * (constants should be ok, too)
2505 */
2506 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2507 {
2508 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2509 activity.inf = SCIPceil(scip, activity.inf);
2510 if( activity.sup < SCIP_INTERVAL_INFINITY )
2511 activity.sup = SCIPfloor(scip, activity.sup);
2512 #ifdef DEBUG_PROP
2513 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2514 #endif
2515 }
2516
2517 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2518 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2519 */
2520 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2521 {
2522 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2523 SCIPintervalSetEmpty(&activity);
2524 }
2525
2526 /* now finally store activity in expr */
2527 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2528
2529 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
2530 {
2531 if( infeasible != NULL )
2532 *infeasible = TRUE;
2533 }
2534 else if( tightenauxvars && ownerdata->auxvar != NULL )
2535 {
2536 SCIP_Bool tighteninfeasible;
2537
2538 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2539 if( tighteninfeasible )
2540 {
2541 if( infeasible != NULL )
2542 *infeasible = TRUE;
2543 SCIPintervalSetEmpty(&activity);
2544 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2545 }
2546 }
2547
2548 break;
2549 }
2550
2551 default:
2552 /* you should never be here */
2553 SCIPerrorMessage("unexpected iterator stage\n");
2554 SCIPABORT();
2555 break;
2556 }
2557
2558 expr = SCIPexpriterGetNext(it);
2559 }
2560
2561 SCIPfreeExpriter(&it);
2562
2563 return SCIP_OKAY;
2564 }
2565
2566 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2567 *
2568 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2569 *
2570 * If `subsetsufficient` is FALSE, then we require
2571 * - a change from an unbounded interval to a bounded one, or
2572 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2573 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2574 */
2575 static
2576 SCIP_Bool isIntervalBetter(
2577 SCIP* scip, /**< SCIP data structure */
2578 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2579 SCIP_INTERVAL newinterval, /**< new interval */
2580 SCIP_INTERVAL oldinterval /**< old interval */
2581 )
2582 {
2583 assert(scip != NULL);
2584 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2585 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2586
2587 if( subsetsufficient )
2588 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2589 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2590
2591 /* check whether lower bound of interval becomes finite */
2592 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2593 return TRUE;
2594
2595 /* check whether upper bound of interval becomes finite */
2596 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2597 return TRUE;
2598
2599 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2600 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2601 return TRUE;
2602
2603 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2604 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2605 return TRUE;
2606
2607 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2608 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2609 return TRUE;
2610
2611 return FALSE;
2612 }
2613
2614 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2615 *
2616 * The expression will be traversed in breadth first search by using this queue.
2617 *
2618 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2619 * forwardPropExpr() before calling this function.
2620 *
2621 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2622 */
2623 static
2624 SCIP_RETCODE reversePropQueue(
2625 SCIP* scip, /**< SCIP data structure */
2626 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2627 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2628 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2629 )
2630 {
2631 SCIP_CONSHDLRDATA* conshdlrdata;
2632 SCIP_EXPR* expr;
2633 SCIP_EXPR_OWNERDATA* ownerdata;
2634
2635 assert(infeasible != NULL);
2636 assert(ntightenings != NULL);
2637
2638 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2639 assert(conshdlrdata != NULL);
2640
2641 *ntightenings = 0;
2642
2643 /* main loop that calls reverse propagation for expressions on the queue
2644 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2645 */
2646 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2647 {
2648 SCIP_INTERVAL propbounds;
2649 int e;
2650
2651 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2652 assert(expr != NULL);
2653
2654 ownerdata = SCIPexprGetOwnerData(expr);
2655 assert(ownerdata != NULL);
2656
2657 assert(ownerdata->inpropqueue);
2658 /* mark that the expression is not in the queue anymore */
2659 ownerdata->inpropqueue = FALSE;
2660
2661 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2662 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2663 */
2664 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2665 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2666 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2667
2668 /* this intersects propbounds with activity and auxvar bounds
2669 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2670 * auxvar bounds separately, so disabling this for now
2671 */
2672 #ifdef SCIP_DISABLED_CODE
2673 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2674 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2675 {
2676 *infeasible = TRUE;
2677 break;
2678 }
2679 #else
2680 propbounds = ownerdata->propbounds;
2681 #endif
2682
2683 if( ownerdata->nenfos > 0 )
2684 {
2685 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2686 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2687 {
2688 SCIP_NLHDLR* nlhdlr;
2689 int nreds;
2690
2691 /* skip nlhdlr if it does not want to participate in activity computation */
2692 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2693 continue;
2694
2695 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2696 assert(nlhdlr != NULL);
2697
2698 /* call the reverseprop of the nlhdlr */
2699 #ifdef SCIP_DEBUG
2700 SCIPdebugMsg(scip, "call reverse propagation for ");
2701 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2702 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2703 #endif
2704
2705 nreds = 0;
2706 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2707 assert(nreds >= 0);
2708 *ntightenings += nreds;
2709 }
2710 }
2711 else if( SCIPexprhdlrHasReverseProp(SCIPexprGetHdlr(expr)) )
2712 {
2713 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2714 SCIP_INTERVAL* childrenbounds;
2715 int c;
2716
2717 #ifdef SCIP_DEBUG
2718 SCIPdebugMsg(scip, "call reverse propagation for ");
2719 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2720 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2721 #endif
2722
2723 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2724 * been initialized in detectNlhdlr yet (nenfos < 0)
2725 */
2726 assert(ownerdata->nenfos < 0);
2727
2728 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2729 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2730 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2731
2732 /* call the reverseprop of the exprhdlr */
2733 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2734
2735 if( !*infeasible )
2736 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2737 {
2738 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2739 }
2740
2741 SCIPfreeBufferArray(scip, &childrenbounds);
2742 }
2743 }
2744
2745 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2746 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2747 {
2748 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2749 assert(expr != NULL);
2750
2751 ownerdata = SCIPexprGetOwnerData(expr);
2752 assert(ownerdata != NULL);
2753
2754 /* mark that the expression is not in the queue anymore */
2755 ownerdata->inpropqueue = FALSE;
2756 }
2757
2758 return SCIP_OKAY;
2759 }
2760
2761 /** calls domain propagation for a given set of constraints
2762 *
2763 * The algorithm alternates calls of forward and reverse propagation.
2764 * Forward propagation ensures that activity of expressions is up to date.
2765 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2766 * [lhs,rhs] interval as starting point.
2767 *
2768 * The propagation algorithm works as follows:
2769 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2770 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2771 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2772 * provide tighter bounds
2773 * 3. apply reverse propagation to all collected expressions; don't explore
2774 * sub-expressions which have not changed since the beginning of the propagation loop
2775 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2776 *
2777 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2778 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2779 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2780 *
2781 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2782 * e.g., try less to propagate on convex constraints?
2783 */
2784 static
2785 SCIP_RETCODE propConss(
2786 SCIP* scip, /**< SCIP data structure */
2787 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2788 SCIP_CONS** conss, /**< constraints to propagate */
2789 int nconss, /**< total number of constraints */
2790 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2791 SCIP_RESULT* result, /**< pointer to store the result */
2792 int* nchgbds /**< buffer to add the number of changed bounds */
2793 )
2794 {
2795 SCIP_CONSHDLRDATA* conshdlrdata;
2796 SCIP_CONSDATA* consdata;
2797 SCIP_EXPR_OWNERDATA* ownerdata;
2798 SCIP_Bool cutoff = FALSE;
2799 SCIP_INTERVAL conssides;
2800 int ntightenings;
2801 int roundnr;
2802 SCIP_EXPRITER* revpropcollectit = NULL;
2803 int i;
2804
2805 assert(scip != NULL);
2806 assert(conshdlr != NULL);
2807 assert(conss != NULL);
2808 assert(nconss >= 0);
2809 assert(result != NULL);
2810 assert(nchgbds != NULL);
2811 assert(*nchgbds >= 0);
2812
2813 /* no constraints to propagate */
2814 if( nconss == 0 )
2815 {
2816 *result = SCIP_DIDNOTRUN;
2817 return SCIP_OKAY;
2818 }
2819
2820 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2821 assert(conshdlrdata != NULL);
2822 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2823 assert(!conshdlrdata->globalbounds);
2824
2825 *result = SCIP_DIDNOTFIND;
2826 roundnr = 0;
2827
2828 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2829 conshdlrdata->forceboundtightening = force;
2830
2831 /* invalidate all propbounds (probably not needed) */
2832 ++conshdlrdata->curpropboundstag;
2833
2834 /* create iterator that we will use if we need to look at all auxvars */
2835 if( conshdlrdata->propauxvars )
2836 {
2837 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2838 }
2839
2840 /* main propagation loop */
2841 do
2842 {
2843 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2844
2845 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2846
2847 /* apply forward propagation (update expression activities)
2848 * and add promising root expressions into queue for reversepropagation
2849 */
2850 for( i = 0; i < nconss; ++i )
2851 {
2852 consdata = SCIPconsGetData(conss[i]);
2853 assert(consdata != NULL);
2854
2855 /* skip deleted, non-active, or propagation-disabled constraints */
2856 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2857 continue;
2858
2859 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2860 * activity didn't change
2861 */
2862 if( consdata->ispropagated )
2863 continue;
2864
2865 /* update activities in expression */
2866 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2867 SCIPdebugPrintCons(scip, conss[i], NULL);
2868
2869 ntightenings = 0;
2870 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2871 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2872
2873 if( cutoff )
2874 {
2875 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2876 *result = SCIP_CUTOFF;
2877 break;
2878 }
2879
2880 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2881
2882 /* TODO for a constraint that only has an auxvar for consdata->expr (e.g., convex quadratic), we could also just do the if(TRUE)-branch */
2883 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2884 {
2885 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2886 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2887 * so taking auxvar bounds is enough)
2888 */
2889 if( ownerdata->auxvar == NULL )
2890 {
2891 /* relax sides by SCIPepsilon() and handle infinite sides */
2892 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2893 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2894 SCIPintervalSetBounds(&conssides, lhs, rhs);
2895 }
2896 else
2897 {
2898 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2899 }
2900 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2901 }
2902 else
2903 {
2904 /* check whether bounds of any auxvar used in constraint provides a tightening
2905 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2906 * but skip exprs that have an auxvar, but do not participate in propagation
2907 */
2908 SCIP_EXPR* expr;
2909
2910 assert(revpropcollectit != NULL);
2911 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2912 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2913 {
2914 ownerdata = SCIPexprGetOwnerData(expr);
2915 assert(ownerdata != NULL);
2916
2917 if( ownerdata->auxvar == NULL )
2918 continue;
2919
2920 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2921 continue;
2922
2923 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2924 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2925 }
2926 }
2927
2928 if( cutoff )
2929 {
2930 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2931 *result = SCIP_CUTOFF;
2932 break;
2933 }
2934
2935 assert(ntightenings >= 0);
2936 if( ntightenings > 0 )
2937 {
2938 *nchgbds += ntightenings;
2939 *result = SCIP_REDUCEDDOM;
2940 }
2941
2942 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2943 consdata->ispropagated = TRUE;
2944 }
2945
2946 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2947 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2948 assert(ntightenings >= 0);
2949 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2950
2951 if( cutoff )
2952 {
2953 SCIPdebugMsg(scip, " -> cutoff\n");
2954 *result = SCIP_CUTOFF;
2955 break;
2956 }
2957
2958 if( ntightenings > 0 )
2959 {
2960 *nchgbds += ntightenings;
2961 *result = SCIP_REDUCEDDOM;
2962 }
2963 }
2964 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2965
2966 if( conshdlrdata->propauxvars )
2967 {
2968 SCIPfreeExpriter(&revpropcollectit);
2969 }
2970
2971 conshdlrdata->forceboundtightening = FALSE;
2972
2973 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2974 ++conshdlrdata->curpropboundstag;
2975
2976 return SCIP_OKAY;
2977 }
2978
2979 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2980 *
2981 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2982 *
2983 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2984 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2985 */
2986 static
2987 SCIP_RETCODE propExprDomains(
2988 SCIP* scip, /**< SCIP data structure */
2989 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2990 SCIP_CONS** conss, /**< constraints to propagate */
2991 int nconss, /**< total number of constraints */
2992 SCIP_RESULT* result, /**< pointer to store the result */
2993 int* nchgbds /**< buffer to add the number of changed bounds */
2994 )
2995 {
2996 SCIP_CONSDATA* consdata;
2997 SCIP_EXPRITER* it;
2998 SCIP_EXPR* expr;
2999 SCIP_EXPR_OWNERDATA* ownerdata;
3000 SCIP_Bool cutoff = FALSE;
3001 int ntightenings;
3002 int c;
3003 int e;
3004
3005 assert(scip != NULL);
3006 assert(conshdlr != NULL);
3007 assert(conss != NULL);
3008 assert(nconss >= 0);
3009 assert(result != NULL);
3010 assert(nchgbds != NULL);
3011 assert(*nchgbds >= 0);
3012
3013 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3014 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3015 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3016
3017 *result = SCIP_DIDNOTFIND;
3018
3019 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3020 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3021
3022 for( c = 0; c < nconss && !cutoff; ++c )
3023 {
3024 /* skip deleted, non-active, or propagation-disabled constraints */
3025 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3026 continue;
3027
3028 consdata = SCIPconsGetData(conss[c]);
3029 assert(consdata != NULL);
3030
3031 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3032 {
3033 ownerdata = SCIPexprGetOwnerData(expr);
3034 assert(ownerdata != NULL);
3035
3036 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3037 * this will propagate the current activity
3038 */
3039 for( e = 0; e < ownerdata->nenfos; ++e )
3040 {
3041 SCIP_NLHDLR* nlhdlr;
3042 assert(ownerdata->enfos[e] != NULL);
3043
3044 nlhdlr = ownerdata->enfos[e]->nlhdlr;
3045 assert(nlhdlr != NULL);
3046 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3047 continue;
3048
3049 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3050 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3051 ntightenings = 0;
3052 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3053 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3054
3055 if( cutoff )
3056 {
3057 /* stop everything if we detected infeasibility */
3058 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3059 *result = SCIP_CUTOFF;
3060 break;
3061 }
3062
3063 assert(ntightenings >= 0);
3064 if( ntightenings > 0 )
3065 {
3066 *nchgbds += ntightenings;
3067 *result = SCIP_REDUCEDDOM;
3068 }
3069 }
3070 }
3071 }
3072
3073 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3074 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3075 assert(ntightenings >= 0);
3076
3077 if( cutoff )
3078 {
3079 SCIPdebugMsg(scip, " -> cutoff\n");
3080 *result = SCIP_CUTOFF;
3081 }
3082 else if( ntightenings > 0 )
3083 {
3084 *nchgbds += ntightenings;
3085 *result = SCIP_REDUCEDDOM;
3086 }
3087
3088 SCIPfreeExpriter(&it);
3089
3090 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3091 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3092
3093 return SCIP_OKAY;
3094 }
3095
3096 /** propagates variable locks through expression and adds locks to variables */
3097 static
3098 SCIP_RETCODE propagateLocks(
3099 SCIP* scip, /**< SCIP data structure */
3100 SCIP_EXPR* expr, /**< expression */
3101 int nlockspos, /**< number of positive locks */
3102 int nlocksneg /**< number of negative locks */
3103 )
3104 {
3105 SCIP_EXPR_OWNERDATA* ownerdata;
3106 SCIP_EXPRITER* it;
3107 SCIP_EXPRITER_USERDATA ituserdata;
3108
3109 assert(expr != NULL);
3110
3111 /* if no locks, then nothing to propagate */
3112 if( nlockspos == 0 && nlocksneg == 0 )
3113 return SCIP_OKAY;
3114
3115 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3116 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
3117 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3118 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3119
3120 /* store locks in root node */
3121 ituserdata.intvals[0] = nlockspos;
3122 ituserdata.intvals[1] = nlocksneg;
3123 SCIPexpriterSetCurrentUserData(it, ituserdata);
3124
3125 while( !SCIPexpriterIsEnd(it) )
3126 {
3127 /* collect locks */
3128 ituserdata = SCIPexpriterGetCurrentUserData(it);
3129 nlockspos = ituserdata.intvals[0];
3130 nlocksneg = ituserdata.intvals[1];
3131
3132 ownerdata = SCIPexprGetOwnerData(expr);
3133
3134 switch( SCIPexpriterGetStageDFS(it) )
3135 {
3136 case SCIP_EXPRITER_ENTEREXPR:
3137 {
3138 if( SCIPisExprVar(scip, expr) )
3139 {
3140 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3141 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3142 }
3143
3144 /* add locks to expression */
3145 ownerdata->nlockspos += nlockspos;
3146 ownerdata->nlocksneg += nlocksneg;
3147
3148 /* add monotonicity information if expression has been locked for the first time */
3149 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3150 && SCIPexprhdlrHasMonotonicity(SCIPexprGetHdlr(expr)) )
3151 {
3152 int i;
3153
3154 assert(ownerdata->monotonicity == NULL);
3155 assert(ownerdata->monotonicitysize == 0);
3156
3157 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3158 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3159
3160 /* store the monotonicity for each child */
3161 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3162 {
3163 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3164 }
3165 }
3166 break;
3167 }
3168
3169 case SCIP_EXPRITER_LEAVEEXPR :
3170 {
3171 /* remove monotonicity information if expression has been unlocked */
3172 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3173 {
3174 assert(ownerdata->monotonicitysize > 0);
3175 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3176 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3177
3178 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3179 ownerdata->monotonicitysize = 0;
3180 }
3181 break;
3182 }
3183
3184 case SCIP_EXPRITER_VISITINGCHILD :
3185 {
3186 SCIP_MONOTONE monotonicity;
3187
3188 /* get monotonicity of child */
3189 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3190 * SCIPcallExprMonotonicity
3191 */
3192 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3193
3194 /* compute resulting locks of the child expression */
3195 switch( monotonicity )
3196 {
3197 case SCIP_MONOTONE_INC:
3198 ituserdata.intvals[0] = nlockspos;
3199 ituserdata.intvals[1] = nlocksneg;
3200 break;
3201 case SCIP_MONOTONE_DEC:
3202 ituserdata.intvals[0] = nlocksneg;
3203 ituserdata.intvals[1] = nlockspos;
3204 break;
3205 case SCIP_MONOTONE_UNKNOWN:
3206 ituserdata.intvals[0] = nlockspos + nlocksneg;
3207 ituserdata.intvals[1] = nlockspos + nlocksneg;
3208 break;
3209 case SCIP_MONOTONE_CONST:
3210 ituserdata.intvals[0] = 0;
3211 ituserdata.intvals[1] = 0;
3212 break;
3213 }
3214 /* set locks in child expression */
3215 SCIPexpriterSetChildUserData(it, ituserdata);
3216
3217 break;
3218 }
3219
3220 default :
3221 /* you should never be here */
3222 SCIPABORT();
3223 break;
3224 }
3225
3226 expr = SCIPexpriterGetNext(it);
3227 }
3228
3229 SCIPfreeExpriter(&it);
3230
3231 return SCIP_OKAY;
3232 }
3233
3234 /** main function for adding locks to expressions and variables
3235 *
3236 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3237 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3238 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3239 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3240 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3241 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3242 * which implies that updating the monotonicity information during the next locking of this expression does not
3243 * break existing locks.
3244 *
3245 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3246 * locks from an expression and repropagating them after the structural changes have been applied.
3247 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3248 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3249 */
3250 static
3251 SCIP_RETCODE addLocks(
3252 SCIP* scip, /**< SCIP data structure */
3253 SCIP_CONS* cons, /**< nonlinear constraint */
3254 int nlockspos, /**< number of positive rounding locks */
3255 int nlocksneg /**< number of negative rounding locks */
3256 )
3257 {
3258 SCIP_CONSDATA* consdata;
3259
3260 assert(cons != NULL);
3261
3262 if( nlockspos == 0 && nlocksneg == 0 )
3263 return SCIP_OKAY;
3264
3265 consdata = SCIPconsGetData(cons);
3266 assert(consdata != NULL);
3267
3268 /* no constraint sides -> nothing to lock */
3269 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3270 return SCIP_OKAY;
3271
3272 /* remember locks */
3273 consdata->nlockspos += nlockspos;
3274 consdata->nlocksneg += nlocksneg;
3275
3276 assert(consdata->nlockspos >= 0);
3277 assert(consdata->nlocksneg >= 0);
3278
3279 /* compute locks for lock propagation */
3280 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3281 {
3282 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3283 }
3284 else if( !SCIPisInfinity(scip, consdata->rhs) )
3285 {
3286 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3287 }
3288 else
3289 {
3290 assert(!SCIPisInfinity(scip, -consdata->lhs));
3291 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3292 }
3293
3294 return SCIP_OKAY;
3295 }
3296
3297 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3298 static
3299 SCIP_RETCODE createNlRow(
3300 SCIP* scip, /**< SCIP data structure */
3301 SCIP_CONS* cons /**< nonlinear constraint */
3302 )
3303 {
3304 SCIP_CONSDATA* consdata;
3305
3306 assert(scip != NULL);
3307 assert(cons != NULL);
3308
3309 consdata = SCIPconsGetData(cons);
3310 assert(consdata != NULL);
3311 assert(consdata->expr != NULL);
3312
3313 if( consdata->nlrow != NULL )
3314 {
3315 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3316 }
3317
3318 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3319 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3320 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3321
3322 if( SCIPisExprSum(scip, consdata->expr) )
3323 {
3324 /* if root is a sum, then split into linear and nonlinear terms */
3325 SCIP_EXPR* nonlinpart;
3326 SCIP_EXPR* child;
3327 SCIP_Real* coefs;
3328 int i;
3329
3330 coefs = SCIPgetCoefsExprSum(consdata->expr);
3331
3332 /* constant term of sum */
3333 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3334
3335 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3336 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3337
3338 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3339 {
3340 child = SCIPexprGetChildren(consdata->expr)[i];
3341 if( SCIPisExprVar(scip, child) )
3342 {
3343 /* linear term */
3344 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3345 }
3346 else
3347 {
3348 /* nonlinear term */
3349 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3350 }
3351 }
3352
3353 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3354 {
3355 /* add expression to nlrow (this will make a copy) */
3356 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3357 }
3358 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3359 }
3360 else
3361 {
3362 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3363 }
3364
3365 return SCIP_OKAY;
3366 }
3367
3368 /** compares enfodata by enforcement priority of nonlinear handler
3369 *
3370 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3371 */
3372 static
3373 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3374 {
3375 SCIP_NLHDLR* h1;
3376 SCIP_NLHDLR* h2;
3377
3378 assert(elem1 != NULL);
3379 assert(elem2 != NULL);
3380
3381 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3382 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3383
3384 assert(h1 != NULL);
3385 assert(h2 != NULL);
3386
3387 if( SCIPnlhdlrGetEnfoPriority(h1) != SCIPnlhdlrGetEnfoPriority(h2) )
3388 return SCIPnlhdlrGetEnfoPriority(h1) - SCIPnlhdlrGetEnfoPriority(h2);
3389
3390 if( SCIPnlhdlrGetDetectPriority(h1) != SCIPnlhdlrGetDetectPriority(h2) )
3391 return SCIPnlhdlrGetDetectPriority(h1) - SCIPnlhdlrGetDetectPriority(h2);
3392
3393 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3394 }
3395
3396 /** install nlhdlrs in one expression */
3397 static
3398 SCIP_RETCODE detectNlhdlr(
3399 SCIP* scip, /**< SCIP data structure */
3400 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3401 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3402 )
3403 {
3404 SCIP_EXPR_OWNERDATA* ownerdata;
3405 SCIP_CONSHDLRDATA* conshdlrdata;
3406 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3407 SCIP_NLHDLR_METHOD enforcemethods;
3408 SCIP_NLHDLR_METHOD enforcemethodsnew;
3409 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3410 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3411 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3412 int enfossize; /* allocated length of expr->enfos array */
3413 int h;
3414
3415 assert(expr != NULL);
3416
3417 ownerdata = SCIPexprGetOwnerData(expr);
3418 assert(ownerdata != NULL);
3419
3420 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3421 assert(conshdlrdata != NULL);
3422 assert(conshdlrdata->auxvarid >= 0);
3423 assert(!conshdlrdata->indetect);
3424
3425 /* there should be no enforcer yet and detection should not even have considered expr yet */
3426 assert(ownerdata->nenfos < 0);
3427 assert(ownerdata->enfos == NULL);
3428
3429 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3430 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3431 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3432 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3433 * - if no one uses activity, then do not need activity methods
3434 */
3435 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3436 if( ownerdata->nauxvaruses == 0 )
3437 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3438 else
3439 {
3440 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3441 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3442 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3443 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3444 }
3445 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3446 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3447
3448 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3449 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3450
3451 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3452 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3453
3454 ownerdata->nenfos = 0;
3455 enfossize = 2;
3456 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3457 conshdlrdata->indetect = TRUE;
3458
3459 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3460 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3461 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3462 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3463 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3464
3465 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3466 {
3467 SCIP_NLHDLR* nlhdlr;
3468
3469 nlhdlr = conshdlrdata->nlhdlrs[h];
3470 assert(nlhdlr != NULL);
3471
3472 /* skip disabled nlhdlrs */
3473 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3474 continue;
3475
3476 /* call detect routine of nlhdlr */
3477 nlhdlrexprdata = NULL;
3478 enforcemethodsnew = enforcemethods;
3479 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3480 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3481 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3482 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3483
3484 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3485 nlhdlrparticipating &= enforcemethodsallowed;
3486
3487 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3488 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3489
3490 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3491 * They are also cleaned up here to ensure that only the needed methods are claimed.
3492 */
3493 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3494
3495 /* nlhdlr needs to participate for the methods it is enforcing */
3496 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3497
3498 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3499 {
3500 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3501 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3502
3503 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3504 if( nlhdlrexprdata != NULL )
3505 {
3506 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3507 }
3508 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3509 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3510
3511 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3512
3513 continue;
3514 }
3515
3516 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3517 SCIPnlhdlrGetName(nlhdlr),
3518 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3519 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3520 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3521
3522 /* store nlhdlr and its data */
3523 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3524 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3525 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3526 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3527 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3528 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3529 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3530 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3531 ownerdata->nenfos++;
3532
3533 /* update enforcement flags */
3534 enforcemethods = enforcemethodsnew;
3535 }
3536
3537 conshdlrdata->indetect = FALSE;
3538
3539 /* stop if an enforcement method is missing but we are already in solving stage
3540 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3541 */
3542 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3543 {
3544 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3545 return SCIP_ERROR;
3546 }
3547
3548 assert(ownerdata->nenfos > 0);
3549
3550 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3551 if( ownerdata->nenfos > 1 )
3552 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3553
3554 /* resize enfos array to be nenfos long */
3555 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3556
3557 return SCIP_OKAY;
3558 }
3559
3560 /** detect nlhdlrs that can handle the expressions */
3561 static
3562 SCIP_RETCODE detectNlhdlrs(
3563 SCIP* scip, /**< SCIP data structure */
3564 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3565 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3566 int nconss /**< total number of constraints */
3567 )
3568 {
3569 SCIP_CONSHDLRDATA* conshdlrdata;
3570 SCIP_CONSDATA* consdata;
3571 SCIP_EXPR* expr;
3572 SCIP_EXPR_OWNERDATA* ownerdata;
3573 SCIP_EXPRITER* it;
3574 int i;
3575
3576 assert(conss != NULL || nconss == 0);
3577 assert(nconss >= 0);
3578 assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3579
3580 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3581 assert(conshdlrdata != NULL);
3582
3583 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3584 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
3585
3586 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3587 {
3588 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3589 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3590 */
3591 SCIPincrementCurBoundsTagNonlinear(conshdlr, TRUE);
3592 conshdlrdata->globalbounds = TRUE;
3593 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3594 }
3595
3596 for( i = 0; i < nconss; ++i )
3597 {
3598 assert(conss != NULL && conss[i] != NULL);
3599
3600 consdata = SCIPconsGetData(conss[i]);
3601 assert(consdata != NULL);
3602 assert(consdata->expr != NULL);
3603
3604 /* if a constraint is separated, we currently need it to be initial, too
3605 * this is because INITLP will create the auxiliary variables that are used for any separation
3606 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3607 */
3608 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3609
3610 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3611 assert(ownerdata != NULL);
3612
3613 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3614 * then we would normally skip to run DETECT again
3615 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3616 * thus, if expr is the root expression, we rerun DETECT
3617 */
3618 if( ownerdata->nenfos > 0 )
3619 {
3620 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3621 assert(ownerdata->nenfos < 0);
3622 }
3623
3624 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3625 * this way we can treat the root expression like any other expression when enforcing via separation
3626 * if constraint will be propagated, then register activity usage of root expression
3627 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3628 */
3629 conshdlrdata->indetect = TRUE;
3630 SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3631 SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3632 SCIPconsIsPropagated(conss[i]),
3633 FALSE, FALSE) );
3634 conshdlrdata->indetect = FALSE;
3635
3636 /* compute integrality information for all subexpressions */
3637 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3638
3639 /* run detectNlhdlr on all expr where required */
3640 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3641 {
3642 ownerdata = SCIPexprGetOwnerData(expr);
3643 assert(ownerdata != NULL);
3644
3645 /* skip exprs that we already looked at */
3646 if( ownerdata->nenfos >= 0 )
3647 continue;
3648
3649 /* if there is use of the auxvar, then someone requires that
3650 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3651 * thus, we need to find nlhdlrs that separate or estimate
3652 * if there is use of the activity, then there is someone requiring that
3653 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3654 * thus, we need to find nlhdlrs that do interval-evaluation
3655 */
3656 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3657 {
3658 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3659
3660 assert(ownerdata->nenfos >= 0);
3661 }
3662 else
3663 {
3664 /* remember that we looked at this expression during detectNlhdlrs
3665 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3666 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3667 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3668 */
3669 ownerdata->nenfos = 0;
3670 }
3671 }
3672
3673 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3674 if( SCIPconsIsPropagated(conss[i]) )
3675 consdata->ispropagated = FALSE;
3676 }
3677
3678 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3679 {
3680 /* ensure that the local bounds are used again when reevaluating the expressions later;
3681 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3682 */
3683 SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3684 conshdlrdata->globalbounds = FALSE;
3685 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3686 }
3687 else
3688 {
3689 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3690 SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3691 }
3692
3693 SCIPfreeExpriter(&it);
3694
3695 return SCIP_OKAY;
3696 }
3697
3698 /** initializes (pre)solving data of constraints
3699 *
3700 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3701 * not be modified.
3702 * In particular, this function
3703 * - runs the detection method of nlhldrs
3704 * - looks for unlocked linear variables
3705 * - checks curvature (if not in presolve)
3706 * - creates and add row to NLP (if not in presolve)
3707 *
3708 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3709 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3710 */
3711 static
3712 SCIP_RETCODE initSolve(
3713 SCIP* scip, /**< SCIP data structure */
3714 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3715 SCIP_CONS** conss, /**< constraints */
3716 int nconss /**< number of constraints */
3717 )
3718 {
3719 int c;
3720
3721 for( c = 0; c < nconss; ++c )
3722 {
3723 /* check for a linear variable that can be increase or decreased without harming feasibility */
3724 findUnlockedLinearVar(scip, conss[c]);
3725
3726 if( SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3727 {
3728 SCIP_CONSDATA* consdata;
3729 SCIP_Bool success = FALSE;
3730
3731 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3732 assert(consdata != NULL);
3733 assert(consdata->expr != NULL);
3734
3735 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3736 {
3737 /* call the curvature detection algorithm of the convex nonlinear handler
3738 * Check only for those curvature that may result in a convex inequality, i.e.,
3739 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3740 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3741 */
3742 if( !SCIPisInfinity(scip, -consdata->lhs) )
3743 {
3744 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3745 if( success )
3746 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3747 }
3748 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3749 {
3750 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3751 if( success )
3752 consdata->curv = SCIP_EXPRCURV_CONVEX;
3753 }
3754 }
3755 else
3756 {
3757 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3758 {
3759 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3760 consdata->curv = SCIP_EXPRCURV_LINEAR;
3761 }
3762 else
3763 {
3764 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3765 }
3766 }
3767 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3768
3769 /* add nlrow representation to NLP, if NLP had been constructed */
3770 if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3771 {
3772 if( consdata->nlrow == NULL )
3773 {
3774 SCIP_CALL( createNlRow(scip, conss[c]) );
3775 assert(consdata->nlrow != NULL);
3776 }
3777 SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3778 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3779 }
3780 }
3781 }
3782
3783 /* register non linear handlers */
3784 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3785
3786 return SCIP_OKAY;
3787 }
3788
3789 /** deinitializes (pre)solving data of constraints
3790 *
3791 * This removes the initialization data created in initSolve().
3792 *
3793 * This function can be called in presolve and solve.
3794 *
3795 * TODO At the moment, it should not be called for a constraint if there are other constraints
3796 * that use the same expressions but still require their nlhdlr.
3797 * We should probably only decrement the auxvar and activity usage for the root expr and then
3798 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3799 */
3800 static
3801 SCIP_RETCODE deinitSolve(
3802 SCIP* scip, /**< SCIP data structure */
3803 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3804 SCIP_CONS** conss, /**< constraints */
3805 int nconss /**< number of constraints */
3806 )
3807 {
3808 SCIP_EXPRITER* it;
3809 SCIP_EXPR* expr;
3810 SCIP_CONSDATA* consdata;
3811 SCIP_Bool rootactivityvalid;
3812 int c;
3813
3814 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3815 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3816 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
3817
3818 /* call deinitialization callbacks of expression and nonlinear handlers
3819 * free nonlinear handlers information from expressions
3820 * remove auxiliary variables and nactivityuses counts from expressions
3821 */
3822 for( c = 0; c < nconss; ++c )
3823 {
3824 assert(conss != NULL);
3825 assert(conss[c] != NULL);
3826
3827 consdata = SCIPconsGetData(conss[c]);
3828 assert(consdata != NULL);
3829 assert(consdata->expr != NULL);
3830
3831 /* check and remember whether activity in root is valid */
3832 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3833
3834 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3835 {
3836 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3837
3838 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3839 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3840
3841 /* remove quadratic info */
3842 SCIPfreeExprQuadratic(scip, expr);
3843
3844 if( rootactivityvalid )
3845 {
3846 /* ensure activity is valid if consdata->expr activity is valid
3847 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3848 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3849 * so this childs activity would be invalid, which can generate confusion
3850 */
3851 SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3852 }
3853 }
3854
3855 if( consdata->nlrow != NULL )
3856 {
3857 /* remove row from NLP, if still in solving
3858 * if we are in exitsolve, the whole NLP will be freed anyway
3859 */
3860 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3861 {
3862 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3863 }
3864
3865 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3866 }
3867
3868 /* forget about linear variables that can be increased or decreased without harming feasibility */
3869 consdata->linvardecr = NULL;
3870 consdata->linvarincr = NULL;
3871
3872 /* forget about curvature */
3873 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3874 }
3875
3876 SCIPfreeExpriter(&it);
3877
3878 return SCIP_OKAY;
3879 }
3880
3881 /** helper method to decide whether a given expression is product of at least two binary variables */
3882 static
3883 SCIP_Bool isBinaryProduct(
3884 SCIP* scip, /**< SCIP data structure */
3885 SCIP_EXPR* expr /**< expression */
3886 )
3887 {
3888 int i;
3889
3890 assert(expr != NULL);
3891
3892 /* check whether the expression is a product */
3893 if( !SCIPisExprProduct(scip, expr) )
3894 return FALSE;
3895
3896 /* don't consider products with a coefficient != 1 and products with a single child
3897 * simplification will take care of this expression later
3898 */
3899 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3900 return FALSE;
3901
3902 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3903 {
3904 SCIP_EXPR* child;
3905 SCIP_VAR* var;
3906 SCIP_Real ub;
3907 SCIP_Real lb;
3908
3909 child = SCIPexprGetChildren(expr)[i];
3910 assert(child != NULL);
3911
3912 if( !SCIPisExprVar(scip, child) )
3913 return FALSE;
3914
3915 var = SCIPgetVarExprVar(child);
3916 lb = SCIPvarGetLbLocal(var);
3917 ub = SCIPvarGetUbLocal(var);
3918
3919 /* check whether variable is integer and has [0,1] as variable bounds */
3920 if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3921 return FALSE;
3922 }
3923
3924 return TRUE;
3925 }
3926
3927 /** helper method to collect all bilinear binary product terms */
3928 static
3929 SCIP_RETCODE getBilinearBinaryTerms(
3930 SCIP* scip, /**< SCIP data structure */
3931 SCIP_EXPR* sumexpr, /**< sum expression */
3932 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3933 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3934 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3935 int* nterms /**< pointer to store the total number of bilinear binary terms */
3936 )
3937 {
3938 int i;
3939
3940 assert(sumexpr != NULL);
3941 assert(SCIPisExprSum(scip, sumexpr));
3942 assert(xs != NULL);
3943 assert(ys != NULL);
3944 assert(childidxs != NULL);
3945 assert(nterms != NULL);
3946
3947 *nterms = 0;
3948
3949 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3950 {
3951 SCIP_EXPR* child;
3952
3953 child = SCIPexprGetChildren(sumexpr)[i];
3954 assert(child != NULL);
3955
3956 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3957 {
3958 SCIP_VAR* x = SCIPgetVarExprVar(SCIPexprGetChildren(child)[0]);
3959 SCIP_VAR* y = SCIPgetVarExprVar(SCIPexprGetChildren(child)[1]);
3960
3961 assert(x != NULL);
3962 assert(y != NULL);
3963
3964 if( x != y )
3965 {
3966 xs[*nterms] = x;
3967 ys[*nterms] = y;
3968 childidxs[*nterms] = i;
3969 ++(*nterms);
3970 }
3971 }
3972 }
3973
3974 return SCIP_OKAY;
3975 }
3976
3977 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3978 static
3979 SCIP_RETCODE reformulateFactorizedBinaryQuadratic(
3980 SCIP* scip, /**< SCIP data structure */
3981 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3982 SCIP_CONS* cons, /**< constraint */
3983 SCIP_VAR* facvar, /**< variable that has been factorized */
3984 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3985 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3986 int nvars, /**< total number of variables in sum_j c_ij x_j */
3987 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3988 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3989 )
3990 {
3991 SCIP_VAR* auxvar;
3992 SCIP_CONS* newcons;
3993 SCIP_Real minact = 0.0;
3994 SCIP_Real maxact = 0.0;
3995 SCIP_Bool integral = TRUE;
3996 char name [SCIP_MAXSTRLEN];
3997 int i;
3998
3999 assert(facvar != NULL);
4000 assert(vars != NULL);
4001 assert(nvars > 1);
4002 assert(newexpr != NULL);
4003
4004 /* compute minimum and maximum activity of sum_j c_ij x_j */
4005 /* TODO could compute minact and maxact for facvar=0 and facvar=1 separately, taking implied bounds into account, allowing for possibly tighter big-M's below */
4006 for( i = 0; i < nvars; ++i )
4007 {
4008 minact += MIN(coefs[i], 0.0);
4009 maxact += MAX(coefs[i], 0.0);
4010 integral = integral && SCIPisIntegral(scip, coefs[i]);
4011 }
4012 assert(minact <= maxact);
4013
4014 /* create and add auxiliary variable */
4015 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4016 SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4017 SCIP_CALL( SCIPaddVar(scip, auxvar) );
4018
4019 /* create and add z - maxact x <= 0 */
4020 if( !SCIPisZero(scip, maxact) )
4021 {
4022 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4023 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4024 SCIP_CALL( SCIPaddCons(scip, newcons) );
4025 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4026 if( naddconss != NULL )
4027 ++(*naddconss);
4028 }
4029
4030 /* create and add 0 <= z - minact x */
4031 if( !SCIPisZero(scip, minact) )
4032 {
4033 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4034 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4035 SCIP_CALL( SCIPaddCons(scip, newcons) );
4036 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4037 if( naddconss != NULL )
4038 ++(*naddconss);
4039 }
4040
4041 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4042 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4043 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4044 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4045 if( !SCIPisZero(scip, minact) )
4046 {
4047 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4048 }
4049 SCIP_CALL( SCIPaddCons(scip, newcons) );
4050 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4051 if( naddconss != NULL )
4052 ++(*naddconss);
4053
4054 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4055 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4056 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4057 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4058 if( !SCIPisZero(scip, maxact) )
4059 {
4060 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4061 }
4062 SCIP_CALL( SCIPaddCons(scip, newcons) );
4063 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4064 if( naddconss != NULL )
4065 ++(*naddconss);
4066
4067 /* create variable expression */
4068 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4069
4070 /* release auxvar */
4071 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4072
4073 return SCIP_OKAY;
4074 }
4075
4076 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4077 static
4078 SCIP_RETCODE getFactorizedBinaryQuadraticExpr(
4079 SCIP* scip, /**< SCIP data structure */
4080 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4081 SCIP_CONS* cons, /**< constraint */
4082 SCIP_EXPR* sumexpr, /**< expression */
4083 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4084 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4085 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4086 )
4087 {
4088 SCIP_EXPR** exprs = NULL;
4089 SCIP_VAR** tmpvars = NULL;
4090 SCIP_VAR** vars = NULL;
4091 SCIP_VAR** xs = NULL;
4092 SCIP_VAR** ys = NULL;
4093 SCIP_Real* exprcoefs = NULL;
4094 SCIP_Real* tmpcoefs = NULL;
4095 SCIP_Real* sumcoefs;
4096 SCIP_Bool* isused = NULL;
4097 int* childidxs = NULL;
4098 int* count = NULL;
4099 int nchildren;
4100 int nexprs = 0;
4101 int nterms;
4102 int nvars;
4103 int ntotalvars;
4104 int i;
4105
4106 assert(sumexpr != NULL);
4107 assert(minterms > 1);
4108 assert(newexpr != NULL);
4109
4110 *newexpr = NULL;
4111
4112 /* check whether sumexpr is indeed a sum */
4113 if( !SCIPisExprSum(scip, sumexpr) )
4114 return SCIP_OKAY;
4115
4116 nchildren = SCIPexprGetNChildren(sumexpr);
4117 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4118 nvars = SCIPgetNVars(scip);
4119 ntotalvars = SCIPgetNTotalVars(scip);
4120
4121 /* check whether there are enough terms available */
4122 if( nchildren < minterms )
4123 return SCIP_OKAY;
4124
4125 /* allocate memory */
4126 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4127 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4128 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4129
4130 /* collect all bilinear binary product terms */
4131 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4132
4133 /* check whether there are enough terms available */
4134 if( nterms < minterms )
4135 goto TERMINATE;
4136
4137 /* store how often each variable appears in a bilinear binary product */
4138 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4139 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4140 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4141
4142 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4143 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4144 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4145 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4146
4147 for( i = 0; i < nterms; ++i )
4148 {
4149 int xidx;
4150 int yidx;
4151
4152 assert(xs[i] != NULL);
4153 assert(ys[i] != NULL);
4154
4155 xidx = SCIPvarGetIndex(xs[i]);
4156 assert(xidx < ntotalvars);
4157 yidx = SCIPvarGetIndex(ys[i]);
4158 assert(yidx < ntotalvars);
4159
4160 ++count[xidx];
4161 ++count[yidx];
4162
4163 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4164 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4165 }
4166
4167 /* sort variables; don't change order of count array because it depends on problem indices */
4168 {
4169 int* tmpcount;
4170
4171 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4172 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4173 SCIPfreeBufferArray(scip, &tmpcount);
4174 }
4175
4176 for( i = 0; i < nvars; ++i )
4177 {
4178 SCIP_VAR* facvar = vars[i];
4179 int ntmpvars = 0;
4180 int j;
4181
4182 /* skip candidate if there are not enough terms left */
4183 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4184 continue;
4185
4186 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4187
4188 /* collect variables for x_i * sum_j c_ij x_j */
4189 for( j = 0; j < nterms; ++j )
4190 {
4191 int childidx = childidxs[j];
4192 assert(childidx >= 0 && childidx < nchildren);
4193
4194 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4195 {
4196 SCIP_Real coef;
4197 int xidx;
4198 int yidx;
4199
4200 coef = sumcoefs[childidx];
4201 assert(coef != 0.0);
4202
4203 /* collect corresponding variable */
4204 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4205 tmpcoefs[ntmpvars] = coef;
4206 ++ntmpvars;
4207
4208 /* update counters */
4209 xidx = SCIPvarGetIndex(xs[j]);
4210 assert(xidx < ntotalvars);
4211 yidx = SCIPvarGetIndex(ys[j]);
4212 assert(yidx < ntotalvars);
4213 --count[xidx];
4214 --count[yidx];
4215 assert(count[xidx] >= 0);
4216 assert(count[yidx] >= 0);
4217
4218 /* mark term to be used */
4219 isused[childidx] = TRUE;
4220 }
4221 }
4222 assert(ntmpvars >= minterms);
4223 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4224 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4225
4226 /* create required constraints and store the generated expression */
4227 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4228 exprcoefs[nexprs] = 1.0;
4229 ++nexprs;
4230 }
4231
4232 /* factorization was only successful if at least one expression has been generated */
4233 if( nexprs > 0 )
4234 {
4235 int nexprsold = nexprs;
4236
4237 /* add all children of the sum that have not been used */
4238 for( i = 0; i < nchildren; ++i )
4239 {
4240 if( !isused[i] )
4241 {
4242 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4243 exprcoefs[nexprs] = sumcoefs[i];
4244 ++nexprs;
4245 }
4246 }
4247
4248 /* create a new sum expression */
4249 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4250
4251 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4252 for( i = 0; i < nexprsold; ++i )
4253 {
4254 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4255 }
4256 }
4257
4258 TERMINATE:
4259 /* free memory */
4260 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4261 SCIPfreeBufferArrayNull(scip, &tmpvars);
4262 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4263 SCIPfreeBufferArrayNull(scip, &exprs);
4264 SCIPfreeBufferArrayNull(scip, &vars);
4265 SCIPfreeBufferArrayNull(scip, &isused);
4266 SCIPfreeBufferArrayNull(scip, &count);
4267 SCIPfreeBufferArray(scip, &childidxs);
4268 SCIPfreeBufferArray(scip, &ys);
4269 SCIPfreeBufferArray(scip, &xs);
4270
4271 return SCIP_OKAY;
4272 }
4273
4274 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4275 static
4276 SCIP_RETCODE getBinaryProductExprDo(
4277 SCIP* scip, /**< SCIP data structure */
4278 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4279 SCIP_EXPR* prodexpr, /**< product expression */
4280 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4281 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4282 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4283 )
4284 {
4285 SCIP_VAR** vars;
4286 SCIP_CONS* cons;
4287 SCIP_Real* coefs;
4288 SCIP_VAR* w;
4289 char name[SCIP_MAXSTRLEN];
4290 int nchildren;
4291 int i;
4292
4293 assert(conshdlr != NULL);
4294 assert(prodexpr != NULL);
4295 assert(SCIPisExprProduct(scip, prodexpr));
4296 assert(newexpr != NULL);
4297
4298 nchildren = SCIPexprGetNChildren(prodexpr);
4299 assert(nchildren >= 2);
4300
4301 /* memory to store the variables of the variable expressions (+1 for w) */
(1) Event cond_false: |
Condition "(vars = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)(nchildren + 1), 8UL /* sizeof (*vars) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 4302)) == NULL", taking false branch. |
(2) Event cond_false: |
Condition "(_restat_ = (((vars = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)(nchildren + 1), 8UL /* sizeof (*vars) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 4302)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch. |
(3) Event if_end: |
End of if statement. |
4302 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
(4) Event cond_false: |
Condition "(coefs = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)(nchildren + 1), 8UL /* sizeof (*coefs) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 4303)) == NULL", taking false branch. |
(5) Event cond_false: |
Condition "(_restat_ = (((coefs = BMSallocBufferMemoryArray_call(SCIPbuffer(scip), (size_t)(ptrdiff_t)(nchildren + 1), 8UL /* sizeof (*coefs) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 4303)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch. |
(6) Event if_end: |
End of if statement. |
4303 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4304
4305 /* prepare the names of the variable and the constraints */
4306 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform");
(7) Event cond_true: |
Condition "i < nchildren", taking true branch. |
4307 for( i = 0; i < nchildren; ++i )
4308 {
4309 vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4310 coefs[i] = 1.0;
4311 assert(vars[i] != NULL);
4312 (void) strcat(name, "_");
(8) Event fixed_size_dest: |
You might overrun the 1024-character fixed-size string "name" by copying "vars[i]->name" without checking the length. |
4313 (void) strcat(name, SCIPvarGetName(vars[i]));
4314 }
4315
4316 /* create and add variable */
4317 SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4318 SCIP_CALL( SCIPaddVar(scip, w) );
4319 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4320
4321 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4322 if( nchildren == 2 && !empathy4and )
4323 {
4324 SCIP_VAR* x = vars[0];
4325 SCIP_VAR* y = vars[1];
4326
4327 assert(x != NULL);
4328 assert(y != NULL);
4329 assert(x != y);
4330
4331 /* create and add x - w >= 0 */
4332 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4333 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4334 SCIP_CALL( SCIPaddCons(scip, cons) );
4335 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4336
4337 /* create and add y - w >= 0 */
4338 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4339 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4340 SCIP_CALL( SCIPaddCons(scip, cons) );
4341 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4342
4343 /* create and add x + y - w <= 1 */
4344 vars[2] = w;
4345 coefs[2] = -1.0;
4346 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4347 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4348 SCIP_CALL( SCIPaddCons(scip, cons) );
4349 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4350
4351 /* update number of added constraints */
4352 if( naddconss != NULL )
4353 *naddconss += 3;
4354 }
4355 else
4356 {
4357 /* create, add, and release AND constraint */
4358 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4359 SCIP_CALL( SCIPaddCons(scip, cons) );
4360 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4361 SCIPdebugMsg(scip, " create AND constraint\n");
4362
4363 /* update number of added constraints */
4364 if( naddconss != NULL )
4365 *naddconss += 1;
4366 }
4367
4368 /* create variable expression */
4369 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4370
4371 /* release created variable */
4372 SCIP_CALL( SCIPreleaseVar(scip, &w) );
4373
4374 /* free memory */
4375 SCIPfreeBufferArray(scip, &coefs);
4376 SCIPfreeBufferArray(scip, &vars);
4377
4378 return SCIP_OKAY;
4379 }
4380
4381 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4382 static
4383 SCIP_RETCODE getBinaryProductExpr(
4384 SCIP* scip, /**< SCIP data structure */
4385 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4386 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4387 SCIP_EXPR* prodexpr, /**< product expression */
4388 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4389 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4390 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4391 )
4392 {
4393 SCIP_CONSHDLRDATA* conshdlrdata;
4394 int nchildren;
4395
4396 assert(prodexpr != NULL);
4397 assert(newexpr != NULL);
4398
4399 *newexpr = NULL;
4400
4401 /* only consider products of binary variables */
4402 if( !isBinaryProduct(scip, prodexpr) )
4403 return SCIP_OKAY;
4404
4405 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4406 assert(conshdlrdata != NULL);
4407 nchildren = SCIPexprGetNChildren(prodexpr);
4408 assert(nchildren >= 2);
4409
4410 /* check whether there is already an expression that represents the product */
4411 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4412 {
4413 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4414 assert(*newexpr != NULL);
4415
4416 /* capture expression */
4417 SCIPcaptureExpr(*newexpr);
4418 }
4419 else
4420 {
4421 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4422
4423 if( nchildren == 2 )
4424 {
4425 SCIP_CLIQUE** xcliques;
4426 SCIP_VAR* x;
4427 SCIP_VAR* y;
4428 SCIP_Bool found_clique = FALSE;
4429 int c;
4430
4431 /* get variables from the product expression */
4432 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4433 assert(x != NULL);
4434 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4435 assert(y != NULL);
4436 assert(x != y);
4437
4438 /* first try to find a clique containing both variables */
4439 xcliques = SCIPvarGetCliques(x, TRUE);
4440
4441 /* look in cliques containing x */
4442 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4443 {
4444 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4445 {
4446 /* create zero value expression */
4447 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4448
4449 if( nchgcoefs != NULL )
4450 *nchgcoefs += 1;
4451
4452 found_clique = TRUE;
4453 break;
4454 }
4455
4456 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4457 {
4458 /* create variable expression for x */
4459 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4460
4461 if( nchgcoefs != NULL )
4462 *nchgcoefs += 2;
4463
4464 found_clique = TRUE;
4465 break;
4466 }
4467 }
4468
4469 if( !found_clique )
4470 {
4471 xcliques = SCIPvarGetCliques(x, FALSE);
4472
4473 /* look in cliques containing complement of x */
4474 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4475 {
4476 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4477 {
4478 /* create variable expression for y */
4479 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4480
4481 if( nchgcoefs != NULL )
4482 *nchgcoefs += 1;
4483
4484 found_clique = TRUE;
4485 break;
4486 }
4487
4488 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4489 {
4490 /* create sum expression */
4491 SCIP_EXPR* sum_children[2];
4492 SCIP_Real sum_coefs[2];
4493 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4494 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4495 sum_coefs[0] = 1.0;
4496 sum_coefs[1] = 1.0;
4497 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4498
4499 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4500 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4501
4502 if( nchgcoefs != NULL )
4503 *nchgcoefs += 3;
4504
4505 found_clique = TRUE;
4506 break;
4507 }
4508 }
4509 }
4510
4511 /* if the variables are not in a clique, do standard linearization */
4512 if( !found_clique )
4513 {
4514 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4515 }
4516 }
4517 else
4518 {
4519 /* linearize binary product using an AND constraint because nchildren > 2 */
4520 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4521 }
4522
4523 /* hash variable expression */
4524 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4525 }
4526
4527 return SCIP_OKAY;
4528 }
4529
4530 /** helper function to replace binary products in a given constraint */
4531 static
4532 SCIP_RETCODE replaceBinaryProducts(
4533 SCIP* scip, /**< SCIP data structure */
4534 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4535 SCIP_CONS* cons, /**< constraint */
4536 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4537 SCIP_EXPRITER* it, /**< expression iterator */
4538 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4539 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4540 )
4541 {
4542 SCIP_CONSHDLRDATA* conshdlrdata;
4543 SCIP_CONSDATA* consdata;
4544 SCIP_EXPR* expr;
4545
4546 assert(conshdlr != NULL);
4547 assert(cons != NULL);
4548 assert(exprmap != NULL);
4549 assert(it != NULL);
4550
4551 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4552 assert(conshdlrdata != NULL);
4553
4554 consdata = SCIPconsGetData(cons);
4555 assert(consdata != NULL);
4556 assert(consdata->expr != NULL);
4557
4558 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4559
4560 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4561 {
4562 SCIP_EXPR* newexpr = NULL;
4563 SCIP_EXPR* childexpr;
4564 int childexpridx;
4565
4566 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4567 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4568 childexpr = SCIPexpriterGetChildExprDFS(it);
4569 assert(childexpr != NULL);
4570
4571 /* try to factorize variables in a sum expression that contains several products of binary variables */
4572 if( conshdlrdata->reformbinprodsfac > 1 )
4573 {
4574 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4575 }
4576
4577 /* try to create an expression that represents a product of binary variables */
4578 if( newexpr == NULL )
4579 {
4580 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4581 }
4582
4583 if( newexpr != NULL )
4584 {
4585 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4586
4587 /* replace product expression */
4588 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4589
4590 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4591 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4592
4593 /* mark the constraint to not be simplified anymore */
4594 consdata->issimplified = FALSE;
4595 }
4596 }
4597
4598 return SCIP_OKAY;
4599 }
4600
4601 /** reformulates products of binary variables during presolving in the following way:
4602 *
4603 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4604 * Each term \f$x_i x_j\f$ is reformulated with the help of an extra (implicit integer) variable \f$z_{ij}\f$ in {0,1}:
4605 * \f[
4606 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4607 * \f]
4608 *
4609 * Before reformulating \f$x_i x_j\f$ in this way, it is checked whether there is a clique that contains \f$x_i\f$ and \f$x_j\f$.
4610 * These cliques allow for a better reformulation. There are four cases:
4611 *
4612 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4613 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4614 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4615 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4616 *
4617 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4618 *
4619 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4620 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4621 * contains large (≥ `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4622 * Such a lower sum is reformulated with only one extra variable w_i:
4623 * \f{align}{
4624 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4625 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4626 * \text{minact}\, x_i & \leq w_i, \\
4627 * w_i &\leq \text{maxact}\, x_i, \\
4628 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4629 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4630 * \f}
4631 * We mark \f$w_i\f$ to be implicit integer if all \f$Q_{ij}\f$ are integer. After each replacement of a lower sum, it
4632 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4633 * of terms are prioritized.
4634 */
4635 static
4636 SCIP_RETCODE presolveBinaryProducts(
4637 SCIP* scip, /**< SCIP data structure */
4638 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4639 SCIP_CONS** conss, /**< constraints */
4640 int nconss, /**< total number of constraints */
4641 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4642 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4643 )
4644 {
4645 SCIP_CONSHDLRDATA* conshdlrdata;
4646 SCIP_HASHMAP* exprmap;
4647 SCIP_EXPRITER* it;
4648 int c;
4649
4650 assert(conshdlr != NULL);
4651
4652 /* no nonlinear constraints or binary variables -> skip */
4653 if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4654 return SCIP_OKAY;
4655 assert(conss != NULL);
4656
4657 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4658 assert(conshdlrdata != NULL);
4659
4660 /* create expression hash map */
4661 SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4662
4663 /* create expression iterator */
4664 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4665 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4666 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
4667
4668 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4669
4670 for( c = 0; c < nconss; ++c )
4671 {
4672 SCIP_CONSDATA* consdata;
4673 SCIP_EXPR* newexpr = NULL;
4674
4675 assert(conss[c] != NULL);
4676
4677 consdata = SCIPconsGetData(conss[c]);
4678 assert(consdata != NULL);
4679
4680 /* try to reformulate the root expression */
4681 if( conshdlrdata->reformbinprodsfac > 1 )
4682 {
4683 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4684 }
4685
4686 /* release the root node if another expression has been found */
4687 if( newexpr != NULL )
4688 {
4689 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4690 consdata->expr = newexpr;
4691
4692 /* mark constraint to be not simplified anymore */
4693 consdata->issimplified = FALSE;
4694 }
4695
4696 /* replace each product of binary variables separately */
4697 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4698 }
4699
4700 /* free memory */
4701 SCIPhashmapFree(&exprmap);
4702 SCIPfreeExpriter(&it);
4703
4704 return SCIP_OKAY;
4705 }
4706
4707 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4708 *
4709 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4710 * Then scale by -1 if
4711 * - \f$n_+ < n_-\f$, or
4712 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4713 */
4714 static
4715 SCIP_RETCODE scaleConsSides(
4716 SCIP* scip, /**< SCIP data structure */
4717 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4718 SCIP_CONS* cons, /**< nonlinear constraint */
4719 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4720 )
4721 {
4722 SCIP_CONSDATA* consdata;
4723 int i;
4724
4725 assert(cons != NULL);
4726
4727 consdata = SCIPconsGetData(cons);
4728 assert(consdata != NULL);
4729
4730 if( SCIPisExprSum(scip, consdata->expr) )
4731 {
4732 SCIP_Real* coefs;
4733 SCIP_Real constant;
4734 int nchildren;
4735 int counter = 0;
4736
4737 coefs = SCIPgetCoefsExprSum(consdata->expr);
4738 constant = SCIPgetConstantExprSum(consdata->expr);
4739 nchildren = SCIPexprGetNChildren(consdata->expr);
4740
4741 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4742 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4743 {
4744 SCIP_EXPR* expr;
4745 expr = consdata->expr;
4746
4747 consdata->expr = SCIPexprGetChildren(expr)[0];
4748 assert(!SCIPisExprSum(scip, consdata->expr));
4749
4750 SCIPcaptureExpr(consdata->expr);
4751
4752 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4753 consdata->lhs = -consdata->lhs;
4754 consdata->rhs = -consdata->rhs;
4755
4756 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4757 *changed = TRUE;
4758 return SCIP_OKAY;
4759 }
4760
4761 /* compute n_+ - n_i */
4762 for( i = 0; i < nchildren; ++i )
4763 counter += coefs[i] > 0 ? 1 : -1;
4764
4765 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4766 {
4767 SCIP_EXPR* expr;
4768 SCIP_Real* newcoefs;
4769
4770 /* allocate memory */
4771 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4772
4773 for( i = 0; i < nchildren; ++i )
4774 newcoefs[i] = -coefs[i];
4775
4776 /* create a new sum expression */
4777 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4778
4779 /* replace expression in constraint data and scale sides */
4780 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4781 consdata->expr = expr;
4782 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4783 consdata->lhs = -consdata->lhs;
4784 consdata->rhs = -consdata->rhs;
4785
4786 /* free memory */
4787 SCIPfreeBufferArray(scip, &newcoefs);
4788
4789 *changed = TRUE;
4790 }
4791 }
4792
4793 return SCIP_OKAY;
4794 }
4795
4796 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4797 static
4798 SCIP_RETCODE forbidNonlinearVariablesMultiaggration(
4799 SCIP* scip, /**< SCIP data structure */
4800 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4801 SCIP_CONS** conss, /**< constraints */
4802 int nconss /**< number of constraints */
4803 )
4804 {
4805 SCIP_EXPRITER* it;
4806 SCIP_CONSDATA* consdata;
4807 SCIP_EXPR* expr;
4808 int c;
4809
4810 assert(scip != NULL);
4811 assert(conshdlr != NULL);
4812
4813 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4814 return SCIP_OKAY;
4815
4816 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4817 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4818
4819 for( c = 0; c < nconss; ++c )
4820 {
4821 consdata = SCIPconsGetData(conss[c]);
4822 assert(consdata != NULL);
4823
4824 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4825 * i.e., skip children of sum that are variables
4826 */
4827 if( SCIPisExprSum(scip, consdata->expr) )
4828 {
4829 int i;
4830 SCIP_EXPR* child;
4831 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4832 {
4833 child = SCIPexprGetChildren(consdata->expr)[i];
4834
4835 /* skip variable expression, as they correspond to a linear term */
4836 if( SCIPisExprVar(scip, child) )
4837 continue;
4838
4839 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4840 if( SCIPisExprVar(scip, expr) )
4841 {
4842 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4843 }
4844 }
4845 }
4846 else
4847 {
4848 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4849 if( SCIPisExprVar(scip, expr) )
4850 {
4851 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4852 }
4853 }
4854 }
4855
4856 SCIPfreeExpriter(&it);
4857
4858 return SCIP_OKAY;
4859 }
4860
4861 /** simplifies expressions and replaces common subexpressions for a set of constraints
4862 * @todo put the constant to the constraint sides
4863 */
4864 static
4865 SCIP_RETCODE canonicalizeConstraints(
4866 SCIP* scip, /**< SCIP data structure */
4867 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4868 SCIP_CONS** conss, /**< constraints */
4869 int nconss, /**< total number of constraints */
4870 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4871 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4872 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4873 int* naddconss, /**< counter to add number of added constraints, or NULL */
4874 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4875 )
4876 {
4877 SCIP_CONSHDLRDATA* conshdlrdata;
4878 SCIP_CONSDATA* consdata;
4879 int* nlockspos;
4880 int* nlocksneg;
4881 SCIP_Bool havechange;
4882 int i;
4883
4884 assert(scip != NULL);
4885 assert(conshdlr != NULL);
4886 assert(conss != NULL);
4887 assert(nconss > 0);
4888 assert(infeasible != NULL);
4889
4890 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4891 assert(conshdlrdata != NULL);
4892
4893 /* update number of canonicalize calls */
4894 ++(conshdlrdata->ncanonicalizecalls);
4895
4896 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4897
4898 *infeasible = FALSE;
4899
4900 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4901 havechange = conshdlrdata->ncanonicalizecalls == 1;
4902
4903 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4904 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4905
4906 /* allocate memory for storing locks of each constraint */
4907 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4908 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4909
4910 /* unlock all constraints */
4911 for( i = 0; i < nconss; ++i )
4912 {
4913 assert(conss[i] != NULL);
4914
4915 consdata = SCIPconsGetData(conss[i]);
4916 assert(consdata != NULL);
4917
4918 /* remember locks */
4919 nlockspos[i] = consdata->nlockspos;
4920 nlocksneg[i] = consdata->nlocksneg;
4921
4922 /* remove locks */
4923 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4924 assert(consdata->nlockspos == 0);
4925 assert(consdata->nlocksneg == 0);
4926 }
4927
4928 #ifndef NDEBUG
4929 /* check whether all locks of each expression have been removed */
4930 for( i = 0; i < nconss; ++i )
4931 {
4932 SCIP_EXPR* expr;
4933 SCIP_EXPRITER* it;
4934
4935 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4936
4937 consdata = SCIPconsGetData(conss[i]);
4938 assert(consdata != NULL);
4939
4940 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4941 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4942 {
4943 assert(expr != NULL);
4944 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4945 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4946 }
4947 SCIPfreeExpriter(&it);
4948 }
4949 #endif
4950
4951 /* reformulate products of binary variables */
4952 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4953 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4954 {
4955 int tmpnaddconss = 0;
4956 int tmpnchgcoefs = 0;
4957
4958 /* call this function before simplification because expressions might not be simplified after reformulating
4959 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4960 */
4961 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4962
4963 /* update counters */
4964 if( naddconss != NULL )
4965 *naddconss = tmpnaddconss;
4966 if( nchgcoefs != NULL )
4967 *nchgcoefs = tmpnchgcoefs;
4968
4969 /* check whether at least one expression has changed */
4970 if( tmpnaddconss + tmpnchgcoefs > 0 )
4971 havechange = TRUE;
4972 }
4973
4974 for( i = 0; i < nconss; ++i )
4975 {
4976 consdata = SCIPconsGetData(conss[i]);
4977 assert(consdata != NULL);
4978
4979 /* call simplify for each expression */
4980 if( !consdata->issimplified && consdata->expr != NULL )
4981 {
4982 SCIP_EXPR* simplified;
4983 SCIP_Bool changed;
4984
4985 changed = FALSE;
4986 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4987 consdata->issimplified = TRUE;
4988
4989 if( changed )
4990 havechange = TRUE;
4991
4992 /* If root expression changed, then we need to take care updating the locks as well (the consdata is the one holding consdata->expr "as a child").
4993 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4994 */
4995 if( simplified != consdata->expr )
4996 {
4997 assert(changed);
4998
4999 /* release old expression */
5000 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5001
5002 /* store simplified expression */
5003 consdata->expr = simplified;
5004 }
5005 else
5006 {
5007 /* The simplify captures simplified in any case, also if nothing has changed.
5008 * Therefore, we have to release it here.
5009 */
5010 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5011 }
5012
5013 if( *infeasible )
5014 break;
5015
5016 /* scale constraint sides */
5017 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5018
5019 if( changed )
5020 havechange = TRUE;
5021
5022 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5023 if( SCIPisExprValue(scip, consdata->expr) )
5024 {
5025 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5026 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5027 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5028 {
5029 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5030 SCIPdebugPrintCons(scip, conss[i], NULL);
5031 *infeasible = TRUE;
5032 break;
5033 }
5034 else
5035 {
5036 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5037 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5038 if( ndelconss != NULL )
5039 ++*ndelconss;
5040 havechange = TRUE;
5041 }
5042 }
5043 }
5044 }
5045
5046 /* replace common subexpressions */
5047 if( havechange && !*infeasible )
5048 {
5049 SCIP_CONS** consssorted;
5050 SCIP_EXPR** rootexprs;
5051 SCIP_Bool replacedroot;
5052
5053 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5054 for( i = 0; i < nconss; ++i )
5055 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5056
5057 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5058
5059 /* update pointer to root expr in constraints, if any has changed
5060 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5061 */
5062 if( replacedroot )
5063 for( i = 0; i < nconss; ++i )
5064 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5065
5066 SCIPfreeBufferArray(scip, &rootexprs);
5067
5068 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5069 * been changed after simplification; now we completely recollect all variable expression and variable events
5070 */
5071
5072 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5073 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5074 */
5075 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5076 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5077
5078 for( i = nconss-1; i >= 0; --i )
5079 {
5080 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5081 if( SCIPconsIsDeleted(consssorted[i]) )
5082 continue;
5083
5084 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5085 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5086 }
5087 for( i = 0; i < nconss; ++i )
5088 {
5089 if( SCIPconsIsDeleted(consssorted[i]) )
5090 continue;
5091
5092 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5093 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5094 }
5095
5096 SCIPfreeBufferArray(scip, &consssorted);
5097
5098 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5099 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5100 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5101 */
5102 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5103 }
5104
5105 /* restore locks */
5106 for( i = 0; i < nconss; ++i )
5107 {
5108 if( SCIPconsIsDeleted(conss[i]) )
5109 continue;
5110
5111 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5112 }
5113
5114 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5115 * TODO can we skip this in presoltiming fast?
5116 */
5117 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5118 {
5119 /* reset one of the number of detections counter to count only current presolving round */
5120 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5121 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5122
5123 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5124 }
5125
5126 /* free allocated memory */
5127 SCIPfreeBufferArray(scip, &nlocksneg);
5128 SCIPfreeBufferArray(scip, &nlockspos);
5129
5130 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5131
5132 return SCIP_OKAY;
5133 }
5134
5135 /** merges constraints that have the same root expression */
5136 static
5137 SCIP_RETCODE presolveMergeConss(
5138 SCIP* scip, /**< SCIP data structure */
5139 SCIP_CONS** conss, /**< constraints to process */
5140 int nconss, /**< number of constraints */
5141 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5142 )
5143 {
5144 SCIP_HASHMAP* expr2cons;
5145 SCIP_Bool* updatelocks;
5146 int* nlockspos;
5147 int* nlocksneg;
5148 int c;
5149
5150 assert(success != NULL);
5151
5152 *success = FALSE;
5153
5154 /* not enough constraints available */
5155 if( nconss <= 1 )
5156 return SCIP_OKAY;
5157
5158 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5159 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5160 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5161 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5162
5163 for( c = 0; c < nconss; ++c )
5164 {
5165 SCIP_CONSDATA* consdata;
5166
5167 /* ignore deleted constraints */
5168 if( SCIPconsIsDeleted(conss[c]) )
5169 continue;
5170
5171 consdata = SCIPconsGetData(conss[c]);
5172 assert(consdata != NULL);
5173
5174 /* add expression to the hash map if not seen so far */
5175 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5176 {
5177 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5178 }
5179 else
5180 {
5181 SCIP_CONSDATA* imgconsdata;
5182 int idx;
5183
5184 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5185 assert(idx >= 0 && idx < nconss);
5186
5187 imgconsdata = SCIPconsGetData(conss[idx]);
5188 assert(imgconsdata != NULL);
5189 assert(imgconsdata->expr == consdata->expr);
5190
5191 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5192 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5193
5194 /* check whether locks need to be updated */
5195 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5196 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5197 {
5198 nlockspos[idx] = imgconsdata->nlockspos;
5199 nlocksneg[idx] = imgconsdata->nlocksneg;
5200 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5201 updatelocks[idx] = TRUE;
5202 }
5203
5204 /* update constraint sides */
5205 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5206 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5207
5208 /* delete constraint */
5209 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5210 *success = TRUE;
5211 }
5212 }
5213
5214 /* restore locks of updated constraints */
5215 if( *success )
5216 {
5217 for( c = 0; c < nconss; ++c )
5218 {
5219 if( updatelocks[c] )
5220 {
5221 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5222 }
5223 }
5224 }
5225
5226 /* free memory */
5227 SCIPfreeBufferArray(scip, &nlocksneg);
5228 SCIPfreeBufferArray(scip, &nlockspos);
5229 SCIPfreeBufferArray(scip, &updatelocks);
5230 SCIPhashmapFree(&expr2cons);
5231
5232 return SCIP_OKAY;
5233 }
5234
5235 /** interval evaluation of variables as used in redundancy check
5236 *
5237 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5238 */
5239 static
5240 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5241 { /*lint --e{715}*/
5242 SCIP_CONSHDLRDATA* conshdlrdata;
5243 SCIP_INTERVAL interval;
5244 SCIP_Real lb;
5245 SCIP_Real ub;
5246
5247 assert(scip != NULL);
5248 assert(var != NULL);
5249
5250 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5251 assert(conshdlrdata != NULL);
5252
5253 if( conshdlrdata->globalbounds )
5254 {
5255 lb = SCIPvarGetLbGlobal(var);
5256 ub = SCIPvarGetUbGlobal(var);
5257 }
5258 else
5259 {
5260 lb = SCIPvarGetLbLocal(var);
5261 ub = SCIPvarGetUbLocal(var);
5262 }
5263 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5264
5265 /* relax variable bounds, if there are bounds and variable is not fixed
5266 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5267 */
5268 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5269 {
5270 if( !SCIPisInfinity(scip, -lb) )
5271 lb -= SCIPfeastol(scip);
5272
5273 if( !SCIPisInfinity(scip, ub) )
5274 ub += SCIPfeastol(scip);
5275 }
5276
5277 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5278 lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5279 ub = infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, ub);
5280 assert(lb <= ub);
5281
5282 SCIPintervalSetBounds(&interval, lb, ub);
5283
5284 return interval;
5285 }
5286
5287 /** removes constraints that are always feasible or very simple
5288 *
5289 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5290 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5291 * might violate variable bounds by up to feastol, too.
5292 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5293 *
5294 * Also removes constraints of the form lhs ≤ variable ≤ rhs.
5295 *
5296 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5297 *
5298 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5299 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5300 * would appear as if the constraint is redundant.
5301 */
5302 static
5303 SCIP_RETCODE presolveRedundantConss(
5304 SCIP* scip, /**< SCIP data structure */
5305 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5306 SCIP_CONS** conss, /**< constraints to propagate */
5307 int nconss, /**< total number of constraints */
5308 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5309 int* ndelconss, /**< buffer to add the number of deleted constraints */
5310 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5311 )
5312 {
5313 SCIP_CONSHDLRDATA* conshdlrdata;
5314 SCIP_CONSDATA* consdata;
5315 SCIP_INTERVAL activity;
5316 SCIP_INTERVAL sides;
5317 int i;
5318
5319 assert(scip != NULL);
5320 assert(conshdlr != NULL);
5321 assert(conss != NULL);
5322 assert(nconss >= 0);
5323 assert(cutoff != NULL);
5324 assert(ndelconss != NULL);
5325 assert(nchgbds != NULL);
5326
5327 /* no constraints to check */
5328 if( nconss == 0 )
5329 return SCIP_OKAY;
5330
5331 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5332 assert(conshdlrdata != NULL);
5333
5334 /* increase curboundstag and set lastvaractivitymethodchange
5335 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5336 * for the redundancy check differently than for domain propagation
5337 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5338 */
5339 ++conshdlrdata->curboundstag;
5340 assert(conshdlrdata->curboundstag > 0);
5341 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5342 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5343 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5344
5345 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5346
5347 *cutoff = FALSE;
5348 for( i = 0; i < nconss; ++i )
5349 {
5350 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5351 continue;
5352
5353 consdata = SCIPconsGetData(conss[i]);
5354 assert(consdata != NULL);
5355
5356 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5357 if( SCIPisExprValue(scip, consdata->expr) )
5358 {
5359 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5360
5361 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5362 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5363 {
5364 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5365 *cutoff = TRUE;
5366
5367 goto TERMINATE;
5368 }
5369
5370 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5371
5372 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5373 ++*ndelconss;
5374
5375 continue;
5376 }
5377
5378 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5379 if( SCIPisExprVar(scip, consdata->expr) )
5380 {
5381 SCIP_VAR* var;
5382 SCIP_Bool tightened;
5383
5384 var = SCIPgetVarExprVar(consdata->expr);
5385 assert(var != NULL);
5386
5387 SCIPdebugMsg(scip, "variable constraint <%s> can be made redundant: <%s>[%g,%g] in [%g,%g]\n", SCIPconsGetName(conss[i]), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), consdata->lhs, consdata->rhs);
5388
5389 /* ensure that variable bounds are within constraint sides */
5390 if( !SCIPisInfinity(scip, -consdata->lhs) )
5391 {
5392 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5393
5394 if( tightened )
5395 ++*nchgbds;
5396
5397 if( *cutoff )
5398 goto TERMINATE;
5399 }
5400
5401 if( !SCIPisInfinity(scip, consdata->rhs) )
5402 {
5403 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5404
5405 if( tightened )
5406 ++*nchgbds;
5407
5408 if( *cutoff )
5409 goto TERMINATE;
5410 }
5411
5412 /* delete the (now) redundant constraint locally */
5413 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5414 ++*ndelconss;
5415
5416 continue;
5417 }
5418
5419 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5420 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5421 * variable bounds by up to feastol
5422 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5423 */
5424 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5425 SCIPdebugPrintCons(scip, conss[i], NULL);
5426
5427 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5428 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5429
5430 /* it is unlikely that we detect infeasibility by doing forward propagation */
5431 if( *cutoff )
5432 {
5433 SCIPdebugMsg(scip, " -> cutoff\n");
5434 goto TERMINATE;
5435 }
5436
5437 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5438 activity = SCIPexprGetActivity(consdata->expr);
5439
5440 /* relax sides by feastol
5441 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5442 */
5443 SCIPintervalSetBounds(&sides,
5444 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5445 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5446
5447 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5448 {
5449 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5450
5451 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5452 ++*ndelconss;
5453
5454 continue;
5455 }
5456
5457 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5458 }
5459
5460 TERMINATE:
5461 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5462 ++conshdlrdata->curboundstag;
5463 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5464 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5465 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5466
5467 return SCIP_OKAY;
5468 }
5469
5470 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5471 static
5472 SCIP_RETCODE presolveUpgrade(
5473 SCIP* scip, /**< SCIP data structure */
5474 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5475 SCIP_CONS* cons, /**< source constraint to try to convert */
5476 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5477 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5478 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5479 )
5480 {
5481 SCIP_CONSHDLRDATA* conshdlrdata;
5482 SCIP_CONSDATA* consdata;
5483 SCIP_CONS** upgdconss;
5484 int upgdconsssize;
5485 int nupgdconss_;
5486 int i;
5487
5488 assert(scip != NULL);
5489 assert(conshdlr != NULL);
5490 assert(cons != NULL);
5491 assert(!SCIPconsIsModifiable(cons));
5492 assert(upgraded != NULL);
5493 assert(nupgdconss != NULL);
5494 assert(naddconss != NULL);
5495
5496 *upgraded = FALSE;
5497
5498 nupgdconss_ = 0;
5499
5500 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5501 assert(conshdlrdata != NULL);
5502
5503 /* if there are no upgrade methods, we can stop */
5504 if( conshdlrdata->nconsupgrades == 0 )
5505 return SCIP_OKAY;
5506
5507 upgdconsssize = 2;
5508 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5509
5510 /* call the upgrading methods */
5511 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5512 SCIPdebugPrintCons(scip, cons, NULL);
5513
5514 consdata = SCIPconsGetData(cons);
5515 assert(consdata != NULL);
5516
5517 /* try all upgrading methods in priority order in case the upgrading step is enable */
5518 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5519 {
5520 if( !conshdlrdata->consupgrades[i]->active )
5521 continue;
5522
5523 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5524
5525 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5526
5527 while( nupgdconss_ < 0 )
5528 {
5529 /* upgrade function requires more memory: resize upgdconss and call again */
5530 assert(-nupgdconss_ > upgdconsssize);
5531 upgdconsssize = -nupgdconss_;
5532 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5533
5534 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5535
5536 assert(nupgdconss_ != 0);
5537 }
5538
5539 if( nupgdconss_ > 0 )
5540 {
5541 /* got upgrade */
5542 int j;
5543
5544 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5545
5546 /* add the upgraded constraints to the problem and forget them */
5547 for( j = 0; j < nupgdconss_; ++j )
5548 {
5549 SCIPdebugMsgPrint(scip, "\t");
5550 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5551
5552 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5553 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5554 }
5555
5556 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5557 *nupgdconss += 1;
5558 *naddconss += nupgdconss_ - 1;
5559 *upgraded = TRUE;
5560
5561 /* delete upgraded constraint */
5562 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5563 SCIP_CALL( SCIPdelCons(scip, cons) );
5564
5565 break;
5566 }
5567 }
5568
5569 SCIPfreeBufferArray(scip, &upgdconss);
5570
5571 return SCIP_OKAY;
5572 }
5573
5574 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5575 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5576 * variable bounds, and is not binary
5577 */
5578 static
5579 SCIP_Bool isSingleLockedCand(
5580 SCIP* scip, /**< SCIP data structure */
5581 SCIP_EXPR* expr /**< variable expression */
5582 )
5583 {
5584 SCIP_VAR* var;
5585 SCIP_EXPR_OWNERDATA* ownerdata;
5586
5587 assert(SCIPisExprVar(scip, expr));
5588
5589 var = SCIPgetVarExprVar(expr);
5590 assert(var != NULL);
5591
5592 ownerdata = SCIPexprGetOwnerData(expr);
5593 assert(ownerdata != NULL);
5594
5595 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5596 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5597 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5598 && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5599 && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY
5600 && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5601 }
5602
5603 /** removes all variable expressions that are contained in a given expression from a hash map */
5604 static
5605 SCIP_RETCODE removeSingleLockedVars(
5606 SCIP* scip, /**< SCIP data structure */
5607 SCIP_EXPR* expr, /**< expression */
5608 SCIP_EXPRITER* it, /**< expression iterator */
5609 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5610 )
5611 {
5612 SCIP_EXPR* e;
5613
5614 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5615 {
5616 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5617 {
5618 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5619 }
5620 }
5621
5622 return SCIP_OKAY;
5623 }
5624
5625 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5626 * nonlinear constraint g(x) ≤ rhs (≥ lhs) if g() is concave (convex) in \f$x_i\f$
5627 *
5628 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5629 * Otherwise, a bound disjunction constraint is added.
5630 *
5631 * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) ≤ rhs
5632 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5633 * g(x) to \f$\sum_i [a_i,b_i] x^{p_i}\f$ for a single variable \f$x\f$ and try to conclude montonicity or convexity/concavity
5634 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5635 */
5636 static
5637 SCIP_RETCODE presolveSingleLockedVars(
5638 SCIP* scip, /**< SCIP data structure */
5639 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5640 SCIP_CONS* cons, /**< nonlinear constraint */
5641 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5642 int* naddconss, /**< pointer to store the total number of added constraints */
5643 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5644 )
5645 {
5646 SCIP_CONSHDLRDATA* conshdlrdata;
5647 SCIP_CONSDATA* consdata;
5648 SCIP_EXPR** singlelocked;
5649 SCIP_HASHMAP* exprcands;
5650 SCIP_Bool hasbounddisj;
5651 SCIP_Bool haslhs;
5652 SCIP_Bool hasrhs;
5653 int nsinglelocked = 0;
5654 int i;
5655
5656 assert(conshdlr != NULL);
5657 assert(cons != NULL);
5658 assert(nchgvartypes != NULL);
5659 assert(naddconss != NULL);
5660 assert(infeasible != NULL);
5661
5662 *nchgvartypes = 0;
5663 *naddconss = 0;
5664 *infeasible = FALSE;
5665
5666 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5667 assert(conshdlrdata != NULL);
5668 consdata = SCIPconsGetData(cons);
5669 assert(consdata != NULL);
5670
5671 /* only consider constraints with one finite side */
5672 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5673 return SCIP_OKAY;
5674
5675 /* only consider sum expressions */
5676 if( !SCIPisExprSum(scip, consdata->expr) )
5677 return SCIP_OKAY;
5678
5679 /* remember which side is finite */
5680 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5681 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5682
5683 /* allocate memory */
5684 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5685 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5686
5687 /* check all variable expressions for single locked variables */
5688 for( i = 0; i < consdata->nvarexprs; ++i )
5689 {
5690 assert(consdata->varexprs[i] != NULL);
5691
5692 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5693 {
5694 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5695 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5696 }
5697 }
5698 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5699
5700 if( nsinglelocked > 0 )
5701 {
5702 SCIP_EXPR** children;
5703 SCIP_EXPRITER* it;
5704 int nchildren;
5705
5706 children = SCIPexprGetChildren(consdata->expr);
5707 nchildren = SCIPexprGetNChildren(consdata->expr);
5708
5709 /* create iterator */
5710 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5711 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
5712 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
5713
5714 for( i = 0; i < nchildren; ++i )
5715 {
5716 SCIP_EXPR* child;
5717 SCIP_Real coef;
5718
5719 child = children[i];
5720 assert(child != NULL);
5721 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5722
5723 /* ignore linear terms */
5724 if( SCIPisExprVar(scip, child) )
5725 continue;
5726
5727 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5728 * expression that represents f_j and remove each variable expression from exprcands
5729 */
5730 else if( SCIPisExprProduct(scip, child) )
5731 {
5732 int j;
5733
5734 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5735 {
5736 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5737
5738 if( !SCIPisExprVar(scip, grandchild) )
5739 {
5740 /* mark all variable expressions that are contained in the expression */
5741 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5742 }
5743 }
5744 }
5745 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5746 * for an integer k >= 1
5747 */
5748 else if( SCIPisExprPower(scip, child) )
5749 {
5750 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5751 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5752 SCIP_Bool valid;
5753
5754 /* check for even integral exponent */
5755 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5756
5757 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5758 {
5759 /* mark all variable expressions that are contained in the expression */
5760 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5761 }
5762 }
5763 /* all other cases cannot be handled */
5764 else
5765 {
5766 /* mark all variable expressions that are contained in the expression */
5767 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5768 }
5769 }
5770
5771 /* free expression iterator */
5772 SCIPfreeExpriter(&it);
5773 }
5774
5775 /* check whether the bound disjunction constraint handler is available */
5776 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5777
5778 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5779 for( i = 0; i < nsinglelocked; ++i )
5780 {
5781 /* only consider expressions that are still contained in the exprcands map */
5782 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5783 {
5784 SCIP_CONS* newcons;
5785 SCIP_VAR* vars[2];
5786 SCIP_BOUNDTYPE boundtypes[2];
5787 SCIP_Real bounds[2];
5788 char name[SCIP_MAXSTRLEN];
5789 SCIP_VAR* var;
5790
5791 var = SCIPgetVarExprVar(singlelocked[i]);
5792 assert(var != NULL);
5793 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5794 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5795
5796 /* try to change the variable type to binary */
5797 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5798 {
5799 assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5800 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5801 ++(*nchgvartypes);
5802
5803 if( *infeasible )
5804 {
5805 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5806 break;
5807 }
5808 }
5809 /* add bound disjunction constraint if bounds of the variable are finite */
5810 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5811 {
5812 vars[0] = var;
5813 vars[1] = var;
5814 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5815 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5816 bounds[0] = SCIPvarGetUbGlobal(var);
5817 bounds[1] = SCIPvarGetLbGlobal(var);
5818
5819 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5820
5821 /* create, add, and release bound disjunction constraint */
5822 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5823 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5824 TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5825 SCIP_CALL( SCIPaddCons(scip, newcons) );
5826 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5827 ++(*naddconss);
5828 }
5829 }
5830 }
5831
5832 /* free memory */
5833 SCIPfreeBufferArray(scip, &singlelocked);
5834 SCIPhashmapFree(&exprcands);
5835
5836 return SCIP_OKAY;
5837 }
5838
5839 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5840 static
5841 SCIP_RETCODE presolveImplint(
5842 SCIP* scip, /**< SCIP data structure */
5843 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5844 SCIP_CONS** conss, /**< nonlinear constraints */
5845 int nconss, /**< total number of nonlinear constraints */
5846 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5847 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5848 )
5849 {
5850 int c;
5851
5852 assert(scip != NULL);
5853 assert(conshdlr != NULL);
5854 assert(conss != NULL || nconss == 0);
5855 assert(nchgvartypes != NULL);
5856 assert(infeasible != NULL);
5857
5858 *infeasible = FALSE;
5859
5860 /* nothing can be done if there are no binary and integer variables available */
5861 if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5862 return SCIP_OKAY;
5863
5864 /* no continuous var can be made implicit-integer if there are no continuous variables */
5865 if( SCIPgetNContVars(scip) == 0 )
5866 return SCIP_OKAY;
5867
5868 for( c = 0; c < nconss; ++c )
5869 {
5870 SCIP_CONSDATA* consdata;
5871 SCIP_EXPR** children;
5872 int nchildren;
5873 SCIP_Real* coefs;
5874 SCIP_EXPR* cand = NULL;
5875 SCIP_Real candcoef = 0.0;
5876 int i;
5877
5878 assert(conss != NULL && conss[c] != NULL);
5879
5880 consdata = SCIPconsGetData(conss[c]);
5881 assert(consdata != NULL);
5882
5883 /* the constraint must be an equality constraint */
5884 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5885 continue;
5886
5887 /* the root expression needs to be a sum expression */
5888 if( !SCIPisExprSum(scip, consdata->expr) )
5889 continue;
5890
5891 children = SCIPexprGetChildren(consdata->expr);
5892 nchildren = SCIPexprGetNChildren(consdata->expr);
5893
5894 /* the sum expression must have at least two children
5895 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5896 */
5897 if( nchildren <= 1 )
5898 continue;
5899
5900 coefs = SCIPgetCoefsExprSum(consdata->expr);
5901
5902 /* find first continuous variable and get value of its coefficient */
5903 for( i = 0; i < nchildren; ++i )
5904 {
5905 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5906 continue;
5907
5908 candcoef = coefs[i];
5909 assert(candcoef != 0.0);
5910
5911 /* lhs/rhs - constant divided by candcoef must be integral
5912 * if not, break with cand == NULL, so give up
5913 */
5914 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5915 cand = children[i];
5916
5917 break;
5918 }
5919
5920 /* no suitable continuous variable found */
5921 if( cand == NULL )
5922 continue;
5923
5924 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5925 for( i = 0; i < nchildren; ++i )
5926 {
5927 if( children[i] == cand )
5928 continue;
5929
5930 /* child i must be integral */
5931 if( !SCIPexprIsIntegral(children[i]) )
5932 {
5933 cand = NULL;
5934 break;
5935 }
5936
5937 /* coefficient of child i must be integral if diving by candcoef */
5938 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5939 {
5940 cand = NULL;
5941 break;
5942 }
5943 }
5944
5945 if( cand == NULL )
5946 continue;
5947
5948 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5949 SCIPvarGetName(SCIPgetVarExprVar(cand)), SCIPconsGetName(conss[c]));
5950
5951 /* change variable type */
5952 SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5953
5954 if( *infeasible )
5955 return SCIP_OKAY;
5956
5957 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5958 SCIPexprSetIntegrality(cand, TRUE);
5959 }
5960
5961 return SCIP_OKAY;
5962 }
5963
5964 /** creates auxiliary variable for a given expression
5965 *
5966 * @note for a variable expression it does nothing
5967 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5968 */
5969 static
5970 SCIP_RETCODE createAuxVar(
5971 SCIP* scip, /**< SCIP data structure */
5972 SCIP_EXPR* expr /**< expression */
5973 )
5974 {
5975 SCIP_EXPR_OWNERDATA* ownerdata;
5976 SCIP_CONSHDLRDATA* conshdlrdata;
5977 SCIP_VARTYPE vartype;
5978 SCIP_INTERVAL activity;
5979 char name[SCIP_MAXSTRLEN];
5980
5981 assert(scip != NULL);
5982 assert(expr != NULL);
5983
5984 ownerdata = SCIPexprGetOwnerData(expr);
5985 assert(ownerdata != NULL);
5986 assert(ownerdata->nauxvaruses > 0);
5987
5988 /* if we already have auxvar, then do nothing */
5989 if( ownerdata->auxvar != NULL )
5990 return SCIP_OKAY;
5991
5992 /* if expression is a variable-expression, then do nothing */
5993 if( SCIPisExprVar(scip, expr) )
5994 return SCIP_OKAY;
5995
5996 if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5997 {
5998 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5999 return SCIP_INVALIDCALL;
6000 }
6001
6002 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6003 assert(conshdlrdata != NULL);
6004 assert(conshdlrdata->auxvarid >= 0);
6005
6006 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6007 * but it usually indicates a missing simplify
6008 * if we find situations where we need to have an auxvar for a constant, then remove this assert
6009 */
6010 assert(!SCIPisExprValue(scip, expr));
6011
6012 /* create and capture auxiliary variable */
6013 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6014 ++conshdlrdata->auxvarid;
6015
6016 /* type of auxiliary variable depends on integrality information of the expression */
6017 vartype = SCIPexprIsIntegral(expr) ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS;
6018
6019 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6020 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6021 {
6022 activity = SCIPexprGetActivity(expr);
6023 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6024 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6025 * and abort in debug mode only
6026 */
6027 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
6028 {
6029 SCIPABORT();
6030 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6031 }
6032 }
6033 else
6034 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6035
6036 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6037 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6038 */
6039 if( SCIPgetDepth(scip) == 0 )
6040 {
6041 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6042 }
6043 else
6044 {
6045 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6046 }
6047
6048 /* mark the auxiliary variable to be added for the relaxation only
6049 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6050 * or to copy the variable to a subscip
6051 */
6052 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6053
6054 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6055
6056 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6057
6058 /* add variable locks in both directions
6059 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6060 * but then we need to also update the auxvars locks when the expr locks change
6061 */
6062 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6063
6064 #ifdef WITH_DEBUG_SOLUTION
6065 if( SCIPdebugIsMainscip(scip) )
6066 {
6067 /* store debug solution value of auxiliary variable
6068 * assumes that expression has been evaluated in debug solution before
6069 */
6070 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6071 }
6072 #endif
6073
6074 if( SCIPgetDepth(scip) > 0 )
6075 {
6076 /* initialize local bounds to (locally valid) activity */
6077 SCIP_Bool cutoff;
6078 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6079 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6080 }
6081
6082 return SCIP_OKAY;
6083 }
6084
6085 /** initializes separation for constraint
6086 *
6087 * - ensures that activities are up to date in all expressions
6088 * - creates auxiliary variables where required
6089 * - calls propExprDomains() to possibly tighten auxvar bounds
6090 * - calls separation initialization callback of nlhdlrs
6091 */
6092 static
6093 SCIP_RETCODE initSepa(
6094 SCIP* scip, /**< SCIP data structure */
6095 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6096 SCIP_CONS** conss, /**< constraints */
6097 int nconss, /**< number of constraints */
6098 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6099 )
6100 {
6101 SCIP_CONSDATA* consdata;
6102 SCIP_CONSHDLRDATA* conshdlrdata;
6103 SCIP_EXPRITER* it;
6104 SCIP_EXPR* expr;
6105 SCIP_RESULT result;
6106 SCIP_VAR* auxvar;
6107 int nreductions = 0;
6108 int c, e;
6109
6110 assert(scip != NULL);
6111 assert(conshdlr != NULL);
6112 assert(conss != NULL || nconss == 0);
6113 assert(nconss >= 0);
6114 assert(infeasible != NULL);
6115
6116 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6117 assert(conshdlrdata != NULL);
6118
6119 /* start with new propbounds (just to be sure, should not be needed) */
6120 ++conshdlrdata->curpropboundstag;
6121
6122 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6123 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6124
6125 /* first ensure activities are up to date and create auxvars */
6126 *infeasible = FALSE;
6127 for( c = 0; c < nconss; ++c )
6128 {
6129 assert(conss != NULL);
6130 assert(conss[c] != NULL);
6131
6132 consdata = SCIPconsGetData(conss[c]);
6133 assert(consdata != NULL);
6134 assert(consdata->expr != NULL);
6135
6136 #ifdef WITH_DEBUG_SOLUTION
6137 if( SCIPdebugIsMainscip(scip) )
6138 {
6139 SCIP_SOL* debugsol;
6140
6141 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6142
6143 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6144 {
6145 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6146 * in createAuxVar()
6147 */
6148 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6149 }
6150 }
6151 #endif
6152
6153 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6154 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6155
6156 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6157 {
6158 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6159 {
6160 SCIP_CALL( createAuxVar(scip, expr) );
6161 }
6162 }
6163
6164 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6165 if( auxvar != NULL )
6166 {
6167 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6168 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6169 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6170 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6171 if( *infeasible )
6172 {
6173 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6174 break;
6175 }
6176
6177 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6178 if( *infeasible )
6179 {
6180 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6181 break;
6182 }
6183 }
6184 }
6185
6186 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6187 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6188 * (e.g., log(x*y), which becomes log(w), w=x*y
6189 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6190 */
6191 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6192 if( result == SCIP_CUTOFF )
6193 *infeasible = TRUE;
6194
6195 /* now call initsepa of nlhdlrs
6196 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6197 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6198 */
6199 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6200 for( c = 0; c < nconss && !*infeasible; ++c )
6201 {
6202 assert(conss != NULL);
6203 assert(conss[c] != NULL);
6204
6205 consdata = SCIPconsGetData(conss[c]);
6206 assert(consdata != NULL);
6207 assert(consdata->expr != NULL);
6208
6209 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6210 {
6211 SCIP_EXPR_OWNERDATA* ownerdata;
6212
6213 ownerdata = SCIPexprGetOwnerData(expr);
6214 assert(ownerdata != NULL);
6215
6216 if( ownerdata->nauxvaruses == 0 )
6217 continue;
6218
6219 for( e = 0; e < ownerdata->nenfos; ++e )
6220 {
6221 SCIP_NLHDLR* nlhdlr;
6222 SCIP_Bool underestimate;
6223 SCIP_Bool overestimate;
6224 assert(ownerdata->enfos[e] != NULL);
6225
6226 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6227 * which participated in a previous initSepa() call
6228 */
6229 if( ownerdata->enfos[e]->issepainit )
6230 continue;
6231
6232 /* only call initsepa if it will actually separate */
6233 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6234 continue;
6235
6236 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6237 assert(nlhdlr != NULL);
6238
6239 /* only init sepa if there is an initsepa callback */
6240 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6241 continue;
6242
6243 /* check whether expression needs to be under- or overestimated */
6244 overestimate = ownerdata->nlocksneg > 0;
6245 underestimate = ownerdata->nlockspos > 0;
6246 assert(underestimate || overestimate);
6247
6248 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6249
6250 /* call the separation initialization callback of the nonlinear handler */
6251 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6252 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6253 ownerdata->enfos[e]->issepainit = TRUE;
6254
6255 if( *infeasible )
6256 {
6257 /* stop everything if we detected infeasibility */
6258 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6259 break;
6260 }
6261 }
6262 }
6263 }
6264
6265 SCIPfreeExpriter(&it);
6266
6267 return SCIP_OKAY;
6268 }
6269
6270 /** returns whether we are ok to branch on auxiliary variables
6271 *
6272 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6273 */
6274 static
6275 SCIP_Bool branchAuxNonlinear(
6276 SCIP* scip, /**< SCIP data structure */
6277 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6278 )
6279 {
6280 SCIP_CONSHDLRDATA* conshdlrdata;
6281
6282 assert(conshdlr != NULL);
6283
6284 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6285 assert(conshdlrdata != NULL);
6286
6287 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6288 }
6289
6290 /** gets weight of variable when splitting violation score onto several variables in an expression */
6291 static
6292 SCIP_Real getViolSplitWeight(
6293 SCIP* scip, /**< SCIP data structure */
6294 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6295 SCIP_VAR* var, /**< variable */
6296 SCIP_SOL* sol /**< current solution */
6297 )
6298 {
6299 SCIP_CONSHDLRDATA* conshdlrdata;
6300
6301 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6302 assert(conshdlrdata != NULL);
6303
6304 switch( conshdlrdata->branchviolsplit )
6305 {
6306 case 'u' : /* uniform: everyone gets the same score */
6307 return 1.0;
6308
6309 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6310 {
6311 SCIP_Real weight;
6312 weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6313 return MAX(0.05, weight);
6314 }
6315
6316 case 'd' : /* domain width */
6317 return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6318
6319 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6320 {
6321 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6322 assert(width > 0.0);
6323 if( width > 10.0 )
6324 return 10.0*log10(width);
6325 if( width < 0.1 )
6326 return 0.1/(-log10(width));
6327 return width;
6328 }
6329
6330 default :
6331 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6332 SCIPABORT();
6333 return SCIP_INVALID;
6334 }
6335 }
6336
6337 /** adds violation-branching score to a set of expressions, thereby distributing the score
6338 *
6339 * Each expression must either be a variable expression or have an aux-variable.
6340 *
6341 * If unbounded variables are present, each unbounded var gets an even score.
6342 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6343 */
6344 static
6345 void addExprsViolScore(
6346 SCIP* scip, /**< SCIP data structure */
6347 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6348 int nexprs, /**< number of expressions */
6349 SCIP_Real violscore, /**< violation-branching score to add to expression */
6350 SCIP_SOL* sol, /**< current solution */
6351 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6352 )
6353 {
6354 SCIP_CONSHDLR* conshdlr;
6355 SCIP_VAR* var;
6356 SCIP_Real weight;
6357 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6358 int nunbounded = 0; /* number of candidates with unbounded domain */
6359 int i;
6360
6361 assert(exprs != NULL);
6362 assert(nexprs > 0);
6363 assert(success != NULL);
6364
6365 if( nexprs == 1 )
6366 {
6367 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6368 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6369 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetLbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetUbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])));
6370 *success = TRUE;
6371 return;
6372 }
6373
6374 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6375
6376 for( i = 0; i < nexprs; ++i )
6377 {
6378 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6379 assert(var != NULL);
6380
6381 if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6382 ++nunbounded;
6383 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6384 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6385 }
6386
6387 *success = FALSE;
6388 for( i = 0; i < nexprs; ++i )
6389 {
6390 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6391 assert(var != NULL);
6392
6393 if( nunbounded > 0 )
6394 {
6395 if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6396 {
6397 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6398 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6399 100.0/nunbounded, violscore,
6400 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6401 *success = TRUE;
6402 }
6403 }
6404 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6405 {
6406 assert(weightsum > 0.0);
6407
6408 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6409 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6410 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6411 100*weight / weightsum, violscore,
6412 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6413 *success = TRUE;
6414 }
6415 else
6416 {
6417 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6418 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6419 }
6420 }
6421 }
6422
6423 /** adds violation-branching score to children of expression for given auxiliary variables
6424 *
6425 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6426 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6427 *
6428 * @note This method may modify the given auxvars array by means of sorting.
6429 */
6430 static
6431 SCIP_RETCODE addExprViolScoresAuxVars(
6432 SCIP* scip, /**< SCIP data structure */
6433 SCIP_EXPR* expr, /**< expression where to start searching */
6434 SCIP_Real violscore, /**< violation score to add to expression */
6435 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6436 int nauxvars, /**< number of auxiliary variables */
6437 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6438 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6439 )
6440 {
6441 SCIP_EXPRITER* it;
6442 SCIP_VAR* auxvar;
6443 SCIP_EXPR** exprs;
6444 int nexprs;
6445 int pos;
6446
6447 assert(scip != NULL);
6448 assert(expr != NULL);
6449 assert(auxvars != NULL);
6450 assert(success != NULL);
6451
6452 /* sort variables to make lookup below faster */
6453 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6454
6455 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6456 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_BFS, FALSE) );
6457
6458 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6459 nexprs = 0;
6460
6461 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6462 {
6463 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6464 if( auxvar == NULL )
6465 continue;
6466
6467 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6468 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6469 {
6470 assert(auxvars[pos] == auxvar);
6471
6472 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6473 exprs[nexprs++] = expr;
6474
6475 if( nexprs == nauxvars )
6476 break;
6477 }
6478 }
6479
6480 SCIPfreeExpriter(&it);
6481
6482 if( nexprs > 0 )
6483 {
6484 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6485 }
6486 else
6487 *success = FALSE;
6488
6489 SCIPfreeBufferArray(scip, &exprs);
6490
6491 return SCIP_OKAY;
6492 }
6493
6494 /** registers all unfixed variables in violated constraints as branching candidates */
6495 static
6496 SCIP_RETCODE registerBranchingCandidatesAllUnfixed(
6497 SCIP* scip, /**< SCIP data structure */
6498 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6499 SCIP_CONS** conss, /**< constraints */
6500 int nconss, /**< number of constraints */
6501 int* nnotify /**< counter for number of notifications performed */
6502 )
6503 {
6504 SCIP_CONSDATA* consdata;
6505 SCIP_VAR* var;
6506 int c;
6507 int i;
6508
6509 assert(conshdlr != NULL);
6510 assert(conss != NULL || nconss == 0);
6511 assert(nnotify != NULL);
6512
6513 *nnotify = 0;
6514
6515 for( c = 0; c < nconss; ++c )
6516 {
6517 assert(conss != NULL && conss[c] != NULL);
6518
6519 consdata = SCIPconsGetData(conss[c]);
6520 assert(consdata != NULL);
6521
6522 /* consider only violated constraints */
6523 if( !isConsViolated(scip, conss[c]) )
6524 continue;
6525
6526 /* register all variables that have not been fixed yet */
6527 assert(consdata->varexprs != NULL);
6528 for( i = 0; i < consdata->nvarexprs; ++i )
6529 {
6530 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6531 assert(var != NULL);
6532
6533 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6534 {
6535 SCIP_CALL( SCIPaddExternBranchCand(scip, var, getConsAbsViolation(conss[c]), SCIP_INVALID) );
6536 ++(*nnotify);
6537 }
6538 }
6539 }
6540
6541 return SCIP_OKAY;
6542 }
6543
6544 /** registers all variables in violated constraints with branching scores as external branching candidates */
6545 static
6546 SCIP_RETCODE registerBranchingCandidates(
6547 SCIP* scip, /**< SCIP data structure */
6548 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6549 SCIP_CONS** conss, /**< constraints */
6550 int nconss, /**< number of constraints */
6551 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6552 )
6553 {
6554 SCIP_CONSDATA* consdata;
6555 SCIP_EXPRITER* it = NULL;
6556 int c;
6557
6558 assert(conshdlr != NULL);
6559 assert(success != NULL);
6560
6561 *success = FALSE;
6562
6563 if( branchAuxNonlinear(scip, conshdlr) )
6564 {
6565 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6566 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6567 }
6568
6569 /* register external branching candidates */
6570 for( c = 0; c < nconss; ++c )
6571 {
6572 assert(conss != NULL && conss[c] != NULL);
6573
6574 consdata = SCIPconsGetData(conss[c]);
6575 assert(consdata != NULL);
6576 assert(consdata->varexprs != NULL);
6577
6578 /* consider only violated constraints */
6579 if( !isConsViolated(scip, conss[c]) )
6580 continue;
6581
6582 if( !branchAuxNonlinear(scip, conshdlr) )
6583 {
6584 int i;
6585
6586 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6587 * only, so we can loop over variable expressions
6588 */
6589 for( i = 0; i < consdata->nvarexprs; ++i )
6590 {
6591 SCIP_Real violscore;
6592 SCIP_Real lb;
6593 SCIP_Real ub;
6594 SCIP_VAR* var;
6595
6596 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6597
6598 /* skip variable expressions that do not have a violation score */
6599 if( violscore == 0.0 )
6600 continue;
6601
6602 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6603 assert(var != NULL);
6604
6605 lb = SCIPvarGetLbLocal(var);
6606 ub = SCIPvarGetUbLocal(var);
6607
6608 /* consider variable for branching if it has not been fixed yet */
6609 if( !SCIPisEQ(scip, lb, ub) )
6610 {
6611 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6612 SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6613 *success = TRUE;
6614 }
6615 else
6616 {
6617 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6618 }
6619
6620 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6621 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6622 */
6623 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6624 }
6625 }
6626 else
6627 {
6628 SCIP_EXPR* expr;
6629 SCIP_VAR* var;
6630 SCIP_Real lb;
6631 SCIP_Real ub;
6632 SCIP_Real violscore;
6633
6634 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6635 {
6636 violscore = SCIPgetExprViolScoreNonlinear(expr);
6637 if( violscore == 0.0 )
6638 continue;
6639
6640 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6641 * variable, so this expression should either be an original variable or have an auxiliary variable
6642 */
6643 var = SCIPgetExprAuxVarNonlinear(expr);
6644 assert(var != NULL);
6645
6646 lb = SCIPvarGetLbLocal(var);
6647 ub = SCIPvarGetUbLocal(var);
6648
6649 /* consider variable for branching if it has not been fixed yet */
6650 if( !SCIPisEQ(scip, lb, ub) )
6651 {
6652 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6653
6654 SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6655 *success = TRUE;
6656 }
6657 else
6658 {
6659 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6660 }
6661 }
6662 }
6663 }
6664
6665 if( it != NULL )
6666 SCIPfreeExpriter(&it);
6667
6668 return SCIP_OKAY;
6669 }
6670
6671 /** collect branching candidates from violated constraints
6672 *
6673 * Fills array with expressions that serve as branching candidates.
6674 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6675 * branching candidate.
6676 *
6677 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6678 * through variable-expressions only.
6679 */
6680 static
6681 SCIP_RETCODE collectBranchingCandidates(
6682 SCIP* scip, /**< SCIP data structure */
6683 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6684 SCIP_CONS** conss, /**< constraints to process */
6685 int nconss, /**< number of constraints */
6686 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6687 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6688 SCIP_Longint soltag, /**< tag of solution */
6689 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6690 int* ncands /**< number of candidates found */
6691 )
6692 {
6693 SCIP_CONSHDLRDATA* conshdlrdata;
6694 SCIP_CONSDATA* consdata;
6695 SCIP_EXPRITER* it = NULL;
6696 int c;
6697 int attempt;
6698 SCIP_VAR* var;
6699
6700 assert(scip != NULL);
6701 assert(conshdlr != NULL);
6702 assert(cands != NULL);
6703 assert(ncands != NULL);
6704
6705 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6706 assert(conshdlrdata != NULL);
6707
6708 if( branchAuxNonlinear(scip, conshdlr) )
6709 {
6710 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6711 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6712 }
6713
6714 *ncands = 0;
6715 for( attempt = 0; attempt < 2; ++attempt )
6716 {
6717 /* collect branching candidates from violated constraints
6718 * in the first attempt, consider only constraints with large violation
6719 * in the second attempt, consider all remaining violated constraints
6720 */
6721 for( c = 0; c < nconss; ++c )
6722 {
6723 SCIP_Real consviol;
6724
6725 assert(conss != NULL && conss[c] != NULL);
6726
6727 /* consider only violated constraints */
6728 if( !isConsViolated(scip, conss[c]) )
6729 continue;
6730
6731 consdata = SCIPconsGetData(conss[c]);
6732 assert(consdata != NULL);
6733 assert(consdata->varexprs != NULL);
6734
6735 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6736
6737 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6738 continue;
6739 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6740 continue;
6741
6742 if( !branchAuxNonlinear(scip, conshdlr) )
6743 {
6744 int i;
6745
6746 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6747 * only, so we can loop over variable expressions
6748 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6749 * variable, therefore we invalidate the score of a variable after processing it.
6750 */
6751 for( i = 0; i < consdata->nvarexprs; ++i )
6752 {
6753 SCIP_Real lb;
6754 SCIP_Real ub;
6755
6756 /* skip variable expressions that do not have a valid violation score */
6757 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6758 continue;
6759
6760 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6761 assert(var != NULL);
6762
6763 lb = SCIPvarGetLbLocal(var);
6764 ub = SCIPvarGetUbLocal(var);
6765
6766 /* skip already fixed variable */
6767 if( SCIPisEQ(scip, lb, ub) )
6768 {
6769 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6770 continue;
6771 }
6772
6773 assert(*ncands + 1 < SCIPgetNVars(scip));
6774 cands[*ncands].expr = consdata->varexprs[i];
6775 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6776 ++(*ncands);
6777
6778 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6779 * several times as external branching candidate */
6780 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6781 }
6782 }
6783 else
6784 {
6785 SCIP_EXPR* expr;
6786 SCIP_Real lb;
6787 SCIP_Real ub;
6788
6789 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6790 {
6791 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6792 continue;
6793
6794 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6795 * variables, so this expression should either be an original variable or have an auxiliary variable
6796 */
6797 var = SCIPgetExprAuxVarNonlinear(expr);
6798 assert(var != NULL);
6799
6800 lb = SCIPvarGetLbLocal(var);
6801 ub = SCIPvarGetUbLocal(var);
6802
6803 /* skip already fixed variable */
6804 if( SCIPisEQ(scip, lb, ub) )
6805 {
6806 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6807 continue;
6808 }
6809
6810 assert(*ncands + 1 < SCIPgetNVars(scip));
6811 cands[*ncands].expr = expr;
6812 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6813 ++(*ncands);
6814 }
6815 }
6816 }
6817
6818 /* if we have branching candidates, then we don't need another attempt */
6819 if( *ncands > 0 )
6820 break;
6821 }
6822
6823 if( it != NULL )
6824 SCIPfreeExpriter(&it);
6825
6826 return SCIP_OKAY;
6827 }
6828
6829 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6830 * improving the dual bound from the LP relaxation
6831 *
6832 * Assume the Lagrangian for the current LP is something of the form
6833 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6834 * where x are the original variables, z the auxiliary variables,
6835 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6836 *
6837 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6838 * If we could have used not only an estimator, but the actual function f(x), then this would
6839 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6840 * Using a lot of handwaving, we claim that
6841 * lambda_i * (f(x) - a_i'x + b_i)
6842 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6843 * If an estimator depended on local bounds, then it could be improved by branching.
6844 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6845 *
6846 * To score a variable, we then sum the values lambda_i * (f(x) - a_i'x + b_i) for all rows in which the variable appears.
6847 * To scale, we divide by the LP objective value (if >1).
6848 *
6849 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6850 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6851 *
6852 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6853 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6854 * would also be branching candidates
6855 */
6856 static
6857 SCIP_Real getDualBranchscore(
6858 SCIP* scip, /**< SCIP data structure */
6859 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6860 SCIP_VAR* var /**< variable */
6861 )
6862 {
6863 SCIP_COL* col;
6864 SCIP_ROW** rows;
6865 int nrows;
6866 int r;
6867 SCIP_Real dualscore;
6868
6869 assert(scip != NULL);
6870 assert(conshdlr != NULL);
6871 assert(var != NULL);
6872
6873 /* if LP not solved, then the dual branching score is not available */
6874 if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
6875 return 0.0;
6876
6877 /* if var is not in the LP, then the dual branching score is not available */
6878 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
6879 return 0.0;
6880
6881 col = SCIPvarGetCol(var);
6882 assert(col != NULL);
6883
6884 if( !SCIPcolIsInLP(col) )
6885 return 0.0;
6886
6887 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6888 rows = SCIPcolGetRows(col);
6889
6890 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6891
6892 /* aggregate duals from all rows from consexpr with non-zero dual
6893 * TODO: this is a quick-and-dirty implementation, and not used by default
6894 * in the long run, this should be either removed or replaced by a proper implementation
6895 */
6896 dualscore = 0.0;
6897 for( r = 0; r < nrows; ++r )
6898 {
6899 SCIP_Real estimategap;
6900 const char* estimategapstr;
6901
6902 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6903 * these would typically be local, unless they are created at the root node
6904 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6905 if( !SCIProwIsLocal(rows[r]) )
6906 continue;
6907 */
6908 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6909 continue;
6910 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6911 continue;
6912
6913 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6914 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6915 continue;
6916 estimategap = atof(estimategapstr + 13);
6917 assert(estimategap >= 0.0);
6918 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6919 estimategap = SCIPgetHugeValue(scip);
6920
6921 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6922 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6923
6924 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6925 }
6926
6927 /* divide by optimal value of LP for scaling */
6928 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6929
6930 return dualscore;
6931 }
6932
6933 /** computes branching scores (including weighted score) for a set of candidates
6934 *
6935 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6936 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6937 *
6938 * For each score, compute the maximum over all candidates.
6939 *
6940 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6941 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6942 * score of all candidates.
6943 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6944 *
6945 * For example:
6946 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6947 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6948 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6949 * - Then the weighted scores for x will be (2.0 * 10.0/12.0 + 3.0 * 5.0/5.0) / (2.0 + 3.0) = 0.9333.
6950 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6951 */
6952 static
6953 void scoreBranchingCandidates(
6954 SCIP* scip, /**< SCIP data structure */
6955 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6956 BRANCHCAND* cands, /**< branching candidates */
6957 int ncands, /**< number of candidates */
6958 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6959 )
6960 {
6961 SCIP_CONSHDLRDATA* conshdlrdata;
6962 BRANCHCAND maxscore;
6963 int c;
6964
6965 assert(scip != NULL);
6966 assert(conshdlr != NULL);
6967 assert(cands != NULL);
6968 assert(ncands > 0);
6969
6970 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6971 assert(conshdlrdata != NULL);
6972
6973 /* initialize counts to 0 */
6974 memset(&maxscore, 0, sizeof(BRANCHCAND));
6975
6976 for( c = 0; c < ncands; ++c )
6977 {
6978 if( conshdlrdata->branchviolweight > 0.0 )
6979 {
6980 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6981 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6982 }
6983
6984 if( conshdlrdata->branchdomainweight > 0.0 )
6985 {
6986 SCIP_Real domainwidth;
6987 SCIP_VAR* var;
6988
6989 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6990 assert(var != NULL);
6991
6992 /* get domain width, taking infinity at 1e20 on purpose */
6993 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6994
6995 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6996 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6997 * the idea is to penalize very large and very small domains
6998 */
6999 if( domainwidth >= 1.0 )
7000 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7001 else
7002 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7003
7004 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7005 }
7006 else
7007 cands[c].domain = 0.0;
7008
7009 if( conshdlrdata->branchdualweight > 0.0 )
7010 {
7011 SCIP_VAR* var;
7012
7013 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7014 assert(var != NULL);
7015
7016 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7017 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7018 }
7019
7020 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7021 {
7022 SCIP_VAR* var;
7023
7024 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7025 assert(var != NULL);
7026
7027 if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7028 cands[c].pscost = SCIP_INVALID;
7029 else
7030 {
7031 SCIP_Real brpoint;
7032 SCIP_Real pscostdown;
7033 SCIP_Real pscostup;
7034 char strategy;
7035
7036 /* decide how to compute pseudo-cost scores
7037 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7038 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7039 */
7040 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
7041 strategy = conshdlrdata->branchpscostupdatestrategy;
7042 else
7043 strategy = 'l';
7044
7045 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7046
7047 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7048 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7049 * For here, I use a simple #counts >= branchpscostreliable.
7050 * TODO use SCIPgetVarPseudocostCount() instead?
7051 */
7052 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7053 {
7054 switch( strategy )
7055 {
7056 case 's' :
7057 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7058 break;
7059 case 'd' :
7060 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7061 break;
7062 case 'l' :
7063 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7064 pscostdown = SCIP_INVALID;
7065 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7066 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7067 else
7068 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7069 break;
7070 default :
7071 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7072 pscostdown = SCIP_INVALID;
7073 }
7074 }
7075 else
7076 pscostdown = SCIP_INVALID;
7077
7078 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7079 {
7080 switch( strategy )
7081 {
7082 case 's' :
7083 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7084 break;
7085 case 'd' :
7086 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7087 break;
7088 case 'l' :
7089 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7090 pscostup = SCIP_INVALID;
7091 else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7092 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7093 else
7094 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7095 break;
7096 default :
7097 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7098 pscostup = SCIP_INVALID;
7099 }
7100 }
7101 else
7102 pscostup = SCIP_INVALID;
7103
7104 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7105 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7106 */
7107 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7108 cands[c].pscost = SCIP_INVALID;
7109 else if( pscostdown == SCIP_INVALID )
7110 cands[c].pscost = pscostup;
7111 else if( pscostup == SCIP_INVALID )
7112 cands[c].pscost = pscostdown;
7113 else
7114 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7115 }
7116
7117 if( cands[c].pscost != SCIP_INVALID )
7118 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7119 }
7120
7121 if( conshdlrdata->branchvartypeweight > 0.0 )
7122 {
7123 SCIP_VAR* var;
7124
7125 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7126 assert(var != NULL);
7127
7128 switch( SCIPvarGetType(var) )
7129 {
7130 case SCIP_VARTYPE_BINARY :
7131 cands[c].vartype = 1.0;
7132 break;
7133 case SCIP_VARTYPE_INTEGER :
7134 cands[c].vartype = 0.1;
7135 break;
7136 case SCIP_VARTYPE_IMPLINT :
7137 cands[c].vartype = 0.01;
7138 break;
7139 case SCIP_VARTYPE_CONTINUOUS :
7140 default:
7141 cands[c].vartype = 0.0;
7142 }
7143 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7144 }
7145 }
7146
7147 /* now compute a weighted score for each candidate from the single scores
7148 * the single scores are scaled to be in [0,1] for this
7149 */
7150 for( c = 0; c < ncands; ++c )
7151 {
7152 SCIP_Real weightsum;
7153
7154 ENFOLOG(
7155 SCIP_VAR* var;
7156 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7157 SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7158 )
7159
7160 cands[c].weighted = 0.0;
7161 weightsum = 0.0;
7162
7163 if( maxscore.auxviol > 0.0 )
7164 {
7165 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7166 weightsum += conshdlrdata->branchviolweight;
7167
7168 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7169 }
7170
7171 if( maxscore.domain > 0.0 )
7172 {
7173 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7174 weightsum += conshdlrdata->branchdomainweight;
7175
7176 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7177 }
7178
7179 if( maxscore.dual > 0.0 )
7180 {
7181 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7182 weightsum += conshdlrdata->branchdualweight;
7183
7184 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7185 }
7186
7187 if( maxscore.pscost > 0.0 )
7188 {
7189 /* use pseudo-costs only if available */
7190 if( cands[c].pscost != SCIP_INVALID )
7191 {
7192 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7193 weightsum += conshdlrdata->branchpscostweight;
7194
7195 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7196 }
7197 else
7198 {
7199 /* do not add pscostscore, if not available, also do not add into weightsum */
7200 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7201 }
7202 }
7203
7204 if( maxscore.vartype > 0.0 )
7205 {
7206 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7207 weightsum += conshdlrdata->branchvartypeweight;
7208
7209 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7210 }
7211 assert(weightsum > 0.0); /* we should have got at least one valid score */
7212 cands[c].weighted /= weightsum;
7213
7214 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7215 }
7216 }
7217
7218 /** compare two branching candidates by their weighted score
7219 *
7220 * if weighted score is equal, use variable index of (aux)var
7221 */
7222 static
7223 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7224 {
7225 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7226
7227 if( cands[ind1].weighted != cands[ind2].weighted )
7228 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7229 else
7230 return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7231 }
7232
7233 /** do branching or register branching candidates */
7234 static
7235 SCIP_RETCODE branching(
7236 SCIP* scip, /**< SCIP data structure */
7237 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7238 SCIP_CONS** conss, /**< constraints to process */
7239 int nconss, /**< number of constraints */
7240 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7241 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7242 SCIP_Longint soltag, /**< tag of solution */
7243 SCIP_RESULT* result /**< pointer to store the result of branching */
7244 )
7245 {
7246 SCIP_CONSHDLRDATA* conshdlrdata;
7247 BRANCHCAND* cands;
7248 int ncands;
7249 SCIP_VAR* var;
7250 SCIP_NODE* downchild;
7251 SCIP_NODE* eqchild;
7252 SCIP_NODE* upchild;
7253
7254 assert(conshdlr != NULL);
7255 assert(result != NULL);
7256
7257 *result = SCIP_DIDNOTFIND;
7258
7259 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7260 assert(conshdlrdata != NULL);
7261
7262 if( conshdlrdata->branchexternal )
7263 {
7264 /* just register branching candidates as external */
7265 SCIP_Bool success;
7266
7267 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7268 if( success )
7269 *result = SCIP_INFEASIBLE;
7270
7271 return SCIP_OKAY;
7272 }
7273
7274 /* collect branching candidates and their auxviol-score */
7275 SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7276 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7277
7278 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7279 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7280 */
7281 if( ncands == 0 )
7282 goto TERMINATE;
7283
7284 if( ncands > 1 )
7285 {
7286 /* if there are more than one candidate, then compute scores and select */
7287 int* perm;
7288 int c;
7289 int left;
7290 int right;
7291 SCIP_Real threshold;
7292
7293 /* compute additional scores on branching candidates and weighted score */
7294 scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7295
7296 /* sort candidates by weighted score */
7297 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7298 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7299
7300 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7301 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7302 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7303
7304 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7305 left = 0;
7306 right = ncands - 1;
7307 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7308 while( left < right )
7309 {
7310 int mid = (left + right) / 2;
7311 if( cands[perm[mid]].weighted >= threshold )
7312 left = mid + 1;
7313 else
7314 right = mid;
7315 }
7316 assert(left <= ncands);
7317
7318 if( left < ncands )
7319 {
7320 if( cands[perm[left]].weighted >= threshold )
7321 {
7322 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7323 ncands = left + 1;
7324 }
7325 else
7326 {
7327 assert(cands[perm[left]].weighted < threshold);
7328 ncands = left;
7329 }
7330 }
7331 assert(ncands > 0);
7332
7333 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7334 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7335 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7336
7337 if( ncands > 1 )
7338 {
7339 /* choose at random from candidates 0..ncands-1 */
7340 if( conshdlrdata->branchrandnumgen == NULL )
7341 {
7342 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7343 }
7344 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7345 var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7346 }
7347 else
7348 var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7349
7350 SCIPfreeBufferArray(scip, &perm);
7351 }
7352 else
7353 {
7354 var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7355 }
7356 assert(var != NULL);
7357
7358 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7359 SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7360
7361 SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7362 &upchild) );
7363 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7364 *result = SCIP_BRANCHED;
7365 else
7366 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7367 *result = SCIP_REDUCEDDOM;
7368
7369 TERMINATE:
7370 SCIPfreeBufferArray(scip, &cands);
7371
7372 return SCIP_OKAY;
7373 }
7374
7375 /** call enforcement or estimate callback of nonlinear handler
7376 *
7377 * Calls the enforcement callback, if available.
7378 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7379 *
7380 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7381 */
7382 static
7383 SCIP_RETCODE enforceExprNlhdlr(
7384 SCIP* scip, /**< SCIP main data structure */
7385 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7386 SCIP_CONS* cons, /**< nonlinear constraint */
7387 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7388 SCIP_EXPR* expr, /**< expression */
7389 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7390 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7391 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7392 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7393 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7394 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7395 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7396 SCIP_RESULT* result /**< pointer to store the result */
7397 )
7398 {
7399 assert(result != NULL);
7400
7401 /* call enforcement callback of the nlhdlr */
7402 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7403 allowweakcuts, separated, inenforcement, result) );
7404
7405 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7406 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7407 {
7408 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7409 SCIPnlhdlrGetName(nlhdlr), *result); )
7410 return SCIP_OKAY;
7411 }
7412 else
7413 {
7414 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7415 }
7416
7417 *result = SCIP_DIDNOTFIND;
7418
7419 /* now call the estimator callback of the nlhdlr */
7420 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7421 {
7422 SCIP_VAR* auxvar;
7423 SCIP_Bool sepasuccess = FALSE;
7424 SCIP_Bool branchscoresuccess = FALSE;
7425 SCIP_PTRARRAY* rowpreps;
7426 int minidx;
7427 int maxidx;
7428 int r;
7429 SCIP_ROWPREP* rowprep;
7430
7431 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7432
7433 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7434 assert(auxvar != NULL);
7435
7436 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7437 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7438
7439 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7440 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7441
7442 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7443
7444 if( !sepasuccess )
7445 {
7446 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7447 SCIPnlhdlrGetName(nlhdlr)); )
7448 }
7449
7450 for( r = minidx; r <= maxidx; ++r )
7451 {
7452 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7453
7454 assert(rowprep != NULL);
7455 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7456
7457 /* complete estimator to cut */
7458 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7459
7460 /* add the cut and/or branching scores */
7461 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7462 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7463
7464 SCIPfreeRowprep(scip, &rowprep);
7465 }
7466
7467 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7468 }
7469
7470 return SCIP_OKAY;
7471 }
7472
7473 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7474 *
7475 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7476 */
7477 static
7478 SCIP_RETCODE enforceExpr(
7479 SCIP* scip, /**< SCIP data structure */
7480 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7481 SCIP_CONS* cons, /**< nonlinear constraint */
7482 SCIP_EXPR* expr, /**< expression */
7483 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7484 SCIP_Longint soltag, /**< tag of solution */
7485 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7486 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7487 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7488 )
7489 {
7490 SCIP_CONSHDLRDATA* conshdlrdata;
7491 SCIP_EXPR_OWNERDATA* ownerdata;
7492 SCIP_Real origviol;
7493 SCIP_Bool underestimate;
7494 SCIP_Bool overestimate;
7495 SCIP_Real auxviol;
7496 SCIP_Bool auxunderestimate;
7497 SCIP_Bool auxoverestimate;
7498 SCIP_RESULT hdlrresult;
7499 int e;
7500
7501 assert(scip != NULL);
7502 assert(expr != NULL);
7503 assert(result != NULL);
7504
7505 ownerdata = SCIPexprGetOwnerData(expr);
7506 assert(ownerdata != NULL);
7507 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7508
7509 *result = SCIP_DIDNOTFIND;
7510
7511 /* make sure that this expression has been evaluated */
7512 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7513
7514 /* decide whether under- or overestimate is required and get amount of violation */
7515 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7516
7517 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7518 assert(conshdlrdata != NULL);
7519
7520 /* no sufficient violation w.r.t. the original variables -> skip expression */
7521 if( !overestimate && !underestimate )
7522 {
7523 return SCIP_OKAY;
7524 }
7525
7526 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7527 for( e = 0; e < ownerdata->nenfos; ++e )
7528 {
7529 SCIP_NLHDLR* nlhdlr;
7530
7531 /* skip nlhdlr that do not want to participate in any separation */
7532 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7533 continue;
7534
7535 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7536 assert(nlhdlr != NULL);
7537
7538 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7539 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7540 ENFOLOG(
7541 SCIPinfoMessage(scip, enfologfile, " expr ");
7542 SCIPprintExpr(scip, expr, enfologfile);
7543 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7544 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7545 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7546 )
7547
7548 /* TODO if expr is root of constraint (consdata->expr == expr),
7549 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7550 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7551 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7552 * so we should enforce in these auxiliaries first
7553 * if changing this here, we must also adapt analyzeViolation()
7554 */
7555
7556 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7557 assert(auxviol >= 0.0);
7558
7559 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7560 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7561 {
7562 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7563 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7564 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7565
7566 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7567 continue;
7568 }
7569
7570 /* if aux-violation is small (below feastol) and we look only for strong cuts, then it's unlikely to give a strong cut, so skip it */
7571 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7572 {
7573 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7574 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7575 underestimate, overestimate); )
7576
7577 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7578 continue;
7579 }
7580
7581 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7582 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7583 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7584
7585 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7586 * wants to be called for separation on this side, then call separation of nlhdlr
7587 */
7588 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7589 {
7590 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7591 hdlrresult = SCIP_DIDNOTFIND;
7592 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7593 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7594
7595 if( hdlrresult == SCIP_CUTOFF )
7596 {
7597 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7598 *result = SCIP_CUTOFF;
7599 ownerdata->lastenforced = conshdlrdata->enforound;
7600 break;
7601 }
7602
7603 if( hdlrresult == SCIP_SEPARATED )
7604 {
7605 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7606 *result = SCIP_SEPARATED;
7607 ownerdata->lastenforced = conshdlrdata->enforound;
7608 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7609 break;
7610 }
7611
7612 if( hdlrresult == SCIP_REDUCEDDOM )
7613 {
7614 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7615 *result = SCIP_REDUCEDDOM;
7616 ownerdata->lastenforced = conshdlrdata->enforound;
7617 /* TODO or should we always just stop here? */
7618 }
7619
7620 if( hdlrresult == SCIP_BRANCHED )
7621 {
7622 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7623 assert(inenforcement);
7624
7625 /* separation and domain reduction takes precedence over branching */
7626 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7627 if( *result == SCIP_DIDNOTFIND )
7628 *result = SCIP_BRANCHED;
7629 ownerdata->lastenforced = conshdlrdata->enforound;
7630 }
7631 }
7632
7633 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7634 * wants to be called for separation on this side, then call separation of nlhdlr
7635 */
7636 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7637 {
7638 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7639 hdlrresult = SCIP_DIDNOTFIND;
7640 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7641 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7642
7643 if( hdlrresult == SCIP_CUTOFF )
7644 {
7645 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7646 *result = SCIP_CUTOFF;
7647 ownerdata->lastenforced = conshdlrdata->enforound;
7648 break;
7649 }
7650
7651 if( hdlrresult == SCIP_SEPARATED )
7652 {
7653 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7654 *result = SCIP_SEPARATED;
7655 ownerdata->lastenforced = conshdlrdata->enforound;
7656 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7657 break;
7658 }
7659
7660 if( hdlrresult == SCIP_REDUCEDDOM )
7661 {
7662 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7663 *result = SCIP_REDUCEDDOM;
7664 ownerdata->lastenforced = conshdlrdata->enforound;
7665 /* TODO or should we always just stop here? */
7666 }
7667
7668 if( hdlrresult == SCIP_BRANCHED )
7669 {
7670 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7671 assert(inenforcement);
7672
7673 /* separation takes precedence over branching */
7674 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7675 if( *result == SCIP_DIDNOTFIND )
7676 *result = SCIP_BRANCHED;
7677 ownerdata->lastenforced = conshdlrdata->enforound;
7678 }
7679 }
7680 }
7681
7682 return SCIP_OKAY;
7683 }
7684
7685 /** helper function to enforce a single constraint */
7686 static
7687 SCIP_RETCODE enforceConstraint(
7688 SCIP* scip, /**< SCIP data structure */
7689 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7690 SCIP_CONS* cons, /**< constraint to process */
7691 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7692 SCIP_Longint soltag, /**< tag of solution */
7693 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7694 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7695 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7696 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7697 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7698 )
7699 {
7700 SCIP_CONSDATA* consdata;
7701 SCIP_CONSHDLRDATA* conshdlrdata;
7702 SCIP_EXPR* expr;
7703
7704 assert(conshdlr != NULL);
7705 assert(cons != NULL);
7706 assert(it != NULL);
7707 assert(result != NULL);
7708 assert(success != NULL);
7709
7710 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7711 assert(conshdlrdata != NULL);
7712
7713 consdata = SCIPconsGetData(cons);
7714 assert(consdata != NULL);
7715 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7716
7717 *success = FALSE;
7718
7719 if( inenforcement && !consdata->ispropagated )
7720 {
7721 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7722 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7723 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7724 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7725 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7726 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7727 * confuse the stalling check for how long to do separation).
7728 */
7729 SCIP_Bool infeasible;
7730 int ntightenings;
7731
7732 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7733 if( infeasible )
7734 {
7735 *result = SCIP_CUTOFF;
7736 return SCIP_OKAY;
7737 }
7738 /* if we tightened an auxvar bound, we better communicate that */
7739 if( ntightenings > 0 )
7740 *result = SCIP_REDUCEDDOM;
7741 }
7742
7743 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7744 {
7745 SCIP_EXPR_OWNERDATA* ownerdata;
7746 SCIP_RESULT resultexpr;
7747
7748 ownerdata = SCIPexprGetOwnerData(expr);
7749 assert(ownerdata != NULL);
7750
7751 /* we can only enforce if there is an auxvar to compare with */
7752 if( ownerdata->auxvar == NULL )
7753 continue;
7754
7755 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7756 if( ownerdata->lastenforced == conshdlrdata->enforound )
7757 {
7758 ENFOLOG(
7759 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7760 SCIPprintExpr(scip, expr, enfologfile);
7761 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7762 )
7763 *success = TRUE;
7764 continue;
7765 }
7766
7767 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7768
7769 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7770 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7771 if( ownerdata->lastenforced == conshdlrdata->enforound )
7772 *success = TRUE;
7773
7774 if( resultexpr == SCIP_CUTOFF )
7775 {
7776 *result = SCIP_CUTOFF;
7777 break;
7778 }
7779
7780 if( resultexpr == SCIP_SEPARATED )
7781 *result = SCIP_SEPARATED;
7782
7783 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7784 *result = SCIP_REDUCEDDOM;
7785
7786 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7787 *result = SCIP_BRANCHED;
7788 }
7789
7790 return SCIP_OKAY;
7791 }
7792
7793 /** try to separate violated constraints and, if in enforcement, register branching scores
7794 *
7795 * Sets result to
7796 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7797 * - SCIP_CUTOFF, if node can be cutoff,
7798 * - SCIP_SEPARATED, if a cut has been added,
7799 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7800 * - SCIP_BRANCHED, if branching has been done,
7801 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7802 * - SCIP_INFEASIBLE, if external branching candidates were registered
7803 */
7804 static
7805 SCIP_RETCODE enforceConstraints(
7806 SCIP* scip, /**< SCIP data structure */
7807 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7808 SCIP_CONS** conss, /**< constraints to process */
7809 int nconss, /**< number of constraints */
7810 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7811 SCIP_Longint soltag, /**< tag of solution */
7812 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7813 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7814 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7815 )
7816 {
7817 SCIP_CONSHDLRDATA* conshdlrdata;
7818 SCIP_EXPRITER* it;
7819 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7820 int c;
7821
7822 assert(conshdlr != NULL);
7823 assert(conss != NULL || nconss == 0);
7824 assert(result != NULL);
7825
7826 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7827 assert(conshdlrdata != NULL);
7828
7829 /* increase tag to tell whether branching scores in expression belong to this sweep
7830 * and which expressions have already been enforced in this sweep
7831 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7832 */
7833 ++(conshdlrdata->enforound);
7834
7835 *result = SCIP_DIDNOTFIND;
7836
7837 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7838 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
7839
7840 for( c = 0; c < nconss; ++c )
7841 {
7842 assert(conss != NULL && conss[c] != NULL);
7843
7844 /* skip constraints that are not enabled or deleted */
7845 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7846 continue;
7847 assert(SCIPconsIsActive(conss[c]));
7848
7849 /* skip constraints that have separation disabled if we are only in separation */
7850 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7851 continue;
7852
7853 /* skip non-violated constraints */
7854 if( !isConsViolated(scip, conss[c]) )
7855 continue;
7856
7857 ENFOLOG(
7858 {
7859 SCIP_CONSDATA* consdata;
7860 int i;
7861 consdata = SCIPconsGetData(conss[c]);
7862 assert(consdata != NULL);
7863 SCIPinfoMessage(scip, enfologfile, " constraint ");
7864 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7865 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7866 for( i = 0; i < consdata->nvarexprs; ++i )
7867 {
7868 SCIP_VAR* var;
7869 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7870 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7871 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7872 }
7873 })
7874
7875 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7876
7877 if( *result == SCIP_CUTOFF )
7878 break;
7879
7880 if( !consenforced && inenforcement )
7881 {
7882 SCIP_Real viol;
7883
7884 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7885 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7886 {
7887 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7888 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7889
7890 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7891
7892 if( consenforced )
7893 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7894
7895 if( *result == SCIP_CUTOFF )
7896 break;
7897 }
7898 }
7899 }
7900
7901 SCIPfreeExpriter(&it);
7902
7903 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7904
7905 /* if having branching scores, then propagate them from expressions with children to variable expressions */
7906 if( *result == SCIP_BRANCHED )
7907 {
7908 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7909 * branching
7910 */
7911 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7912
7913 /* branching should either have branched: result == SCIP_BRANCHED,
7914 * or fixed a variable: result == SCIP_REDUCEDDOM,
7915 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7916 * or have not done anything: result == SCIP_DIDNOTFIND
7917 */
7918 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7919 }
7920
7921 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7922
7923 return SCIP_OKAY;
7924 }
7925
7926 /** collect (and print (if debugging enfo)) information on violation in expressions
7927 *
7928 * assumes that constraint violations have been computed
7929 */
7930 static
7931 SCIP_RETCODE analyzeViolation(
7932 SCIP* scip, /**< SCIP data structure */
7933 SCIP_CONS** conss, /**< constraints */
7934 int nconss, /**< number of constraints */
7935 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7936 SCIP_Longint soltag, /**< tag of solution */
7937 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7938 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7939 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7940 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7941 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7942 )
7943 {
7944 SCIP_CONSDATA* consdata;
7945 SCIP_EXPRITER* it;
7946 SCIP_EXPR* expr;
7947 SCIP_Real v;
7948 int c;
7949
7950 assert(conss != NULL || nconss == 0);
7951 assert(maxabsconsviol != NULL);
7952 assert(maxrelconsviol != NULL);
7953 assert(maxauxviol != NULL);
7954 assert(maxvarboundviol != NULL);
7955
7956 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7957 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
7958
7959 *maxabsconsviol = 0.0;
7960 *maxrelconsviol = 0.0;
7961 *minauxviol = SCIPinfinity(scip);
7962 *maxauxviol = 0.0;
7963 *maxvarboundviol = 0.0;
7964
7965 for( c = 0; c < nconss; ++c )
7966 {
7967 assert(conss != NULL && conss[c] != NULL);
7968
7969 consdata = SCIPconsGetData(conss[c]);
7970 assert(consdata != NULL);
7971
7972 /* skip constraints that are not enabled, deleted, or have separation disabled */
7973 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7974 continue;
7975 assert(SCIPconsIsActive(conss[c]));
7976
7977 v = getConsAbsViolation(conss[c]);
7978 *maxabsconsviol = MAX(*maxabsconsviol, v);
7979
7980 /* skip non-violated constraints */
7981 if( !isConsViolated(scip, conss[c]) )
7982 continue;
7983
7984 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7985 *maxrelconsviol = MAX(*maxrelconsviol, v);
7986
7987 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7988 {
7989 SCIP_EXPR_OWNERDATA* ownerdata;
7990 SCIP_Real auxvarvalue;
7991 SCIP_Real auxvarlb;
7992 SCIP_Real auxvarub;
7993 SCIP_Bool violunder;
7994 SCIP_Bool violover;
7995 SCIP_Real origviol;
7996 SCIP_Real auxviol;
7997 int e;
7998
7999 ownerdata = SCIPexprGetOwnerData(expr);
8000 assert(ownerdata != NULL);
8001
8002 if( ownerdata->auxvar == NULL )
8003 {
8004 /* check violation of variable bounds of original variable */
8005 if( SCIPisExprVar(scip, expr) )
8006 {
8007 SCIP_VAR* var;
8008 var = SCIPgetVarExprVar(expr);
8009 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8010 auxvarlb = SCIPvarGetLbLocal(var);
8011 auxvarub = SCIPvarGetUbLocal(var);
8012
8013 origviol = 0.0;
8014 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8015 origviol = auxvarlb - auxvarvalue;
8016 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8017 origviol = auxvarvalue - auxvarub;
8018 if( origviol <= 0.0 )
8019 continue;
8020
8021 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8022
8023 ENFOLOG(
8024 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8025 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8026 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8027 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8028 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8029 SCIPinfoMessage(scip, enfologfile, "\n");
8030 )
8031 }
8032
8033 continue;
8034 }
8035
8036 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8037 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8038 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8039
8040 /* check violation of variable bounds of auxiliary variable */
8041 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8042 *maxvarboundviol = auxvarlb - auxvarvalue;
8043 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8044 *maxvarboundviol = auxvarvalue - auxvarub;
8045
8046 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8047
8048 ENFOLOG(
8049 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8050 {
8051 SCIPinfoMessage(scip, enfologfile, "expr ");
8052 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8053 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8054
8055 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8056 if( origviol > 0.0 )
8057 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8058 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8059 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8060 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8061 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8062 SCIPinfoMessage(scip, enfologfile, "\n");
8063 }
8064 )
8065
8066 /* no violation w.r.t. the original variables -> skip expression */
8067 if( origviol == 0.0 )
8068 continue;
8069
8070 /* compute aux-violation for each nonlinear handlers */
8071 for( e = 0; e < ownerdata->nenfos; ++e )
8072 {
8073 SCIP_NLHDLR* nlhdlr;
8074
8075 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8076 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8077 continue;
8078
8079 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8080 assert(nlhdlr != NULL);
8081
8082 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8083 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8084
8085 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8086
8087 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8088
8089 if( auxviol > 0.0 )
8090 {
8091 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8092 *maxauxviol = MAX(*maxauxviol, auxviol);
8093 *minauxviol = MIN(*minauxviol, auxviol);
8094 }
8095 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8096 }
8097 }
8098 }
8099
8100 SCIPfreeExpriter(&it);
8101
8102 return SCIP_OKAY;
8103 } /*lint !e715*/
8104
8105 /** enforcement of constraints called by enfolp and enforelax */
8106 static
8107 SCIP_RETCODE consEnfo(
8108 SCIP* scip, /**< SCIP data structure */
8109 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8110 SCIP_CONS** conss, /**< constraints to process */
8111 int nconss, /**< number of constraints */
8112 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8113 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8114 )
8115 {
8116 SCIP_CONSHDLRDATA* conshdlrdata;
8117 SCIP_Real maxabsconsviol;
8118 SCIP_Real maxrelconsviol;
8119 SCIP_Real minauxviol;
8120 SCIP_Real maxauxviol;
8121 SCIP_Real maxvarboundviol;
8122 SCIP_Longint soltag;
8123 int nnotify;
8124 int c;
8125
8126 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8127 assert(conshdlr != NULL);
8128
8129 soltag = SCIPgetExprNewSoltag(scip);
8130
8131 *result = SCIP_FEASIBLE;
8132 for( c = 0; c < nconss; ++c )
8133 {
8134 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8135
8136 if( isConsViolated(scip, conss[c]) )
8137 *result = SCIP_INFEASIBLE;
8138 }
8139
8140 if( *result == SCIP_FEASIBLE )
8141 {
8142 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8143 SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8144 return SCIP_OKAY;
8145 }
8146
8147 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8148 &minauxviol, &maxauxviol, &maxvarboundviol) );
8149
8150 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8151 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8152 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8153 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8154
8155 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8156
8157 /* try to propagate */
8158 if( conshdlrdata->propinenforce )
8159 {
8160 SCIP_RESULT propresult;
8161 int nchgbds = 0;
8162
8163 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8164
8165 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8166 {
8167 *result = propresult;
8168 return SCIP_OKAY;
8169 }
8170 }
8171
8172 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8173 * all violated expr/auxvar in violated constraints)
8174 */
8175 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8176 sol == NULL )
8177 {
8178 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8179 ++conshdlrdata->ntightenlp;
8180
8181 *result = SCIP_SOLVELP;
8182
8183 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8184 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8185
8186 return SCIP_OKAY;
8187 }
8188
8189 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8190 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8191 */
8192 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8193 {
8194 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8195 ++conshdlrdata->ntightenlp;
8196
8197 *result = SCIP_SOLVELP;
8198
8199 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8200
8201 return SCIP_OKAY;
8202 }
8203
8204 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8205
8206 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8207 *result == SCIP_INFEASIBLE )
8208 return SCIP_OKAY;
8209
8210 assert(*result == SCIP_DIDNOTFIND);
8211
8212 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8213 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8214
8215 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8216 {
8217 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8218 ++conshdlrdata->ntightenlp;
8219
8220 *result = SCIP_SOLVELP;
8221
8222 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8223 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8224
8225 return SCIP_OKAY;
8226 }
8227
8228 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8229 SCIPgetLPFeastol(scip)) && sol == NULL )
8230 {
8231 /* try whether tighten the LP feasibility tolerance could help
8232 * maybe it is just some cut that hasn't been taken into account sufficiently
8233 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8234 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8235 * until the LP feastol reaches epsilon
8236 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8237 * when maxauxviol is above LP feastol)
8238 */
8239 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8240 ++conshdlrdata->ndesperatetightenlp;
8241
8242 *result = SCIP_SOLVELP;
8243
8244 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8245
8246 return SCIP_OKAY;
8247 }
8248
8249 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8250 if( !conshdlrdata->propinenforce )
8251 {
8252 SCIP_RESULT propresult;
8253 int nchgbds = 0;
8254
8255 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8256
8257 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8258 {
8259 *result = propresult;
8260 return SCIP_OKAY;
8261 }
8262 }
8263
8264 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8265 * now look if we find any unfixed variable that we could still branch on
8266 */
8267 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8268
8269 if( nnotify > 0 )
8270 {
8271 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8272 ++conshdlrdata->ndesperatebranch;
8273
8274 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8275
8276 return SCIP_OKAY;
8277 }
8278
8279 /* if everything is fixed in violated constraints, then let's cut off the node
8280 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8281 * result may not be conclusive (when constraint violations are small)
8282 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8283 * sufficiently (see st_e40)
8284 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8285 * not "desperate", but a pretty obvious thing to do
8286 */
8287 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8288 *result = SCIP_CUTOFF;
8289
8290 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8291 if( !SCIPisZero(scip, maxvarboundviol) )
8292 ++conshdlrdata->ndesperatecutoff;
8293
8294 return SCIP_OKAY;
8295 }
8296
8297 /** separation for all violated constraints to be used by SEPA callbacks */
8298 static
8299 SCIP_RETCODE consSepa(
8300 SCIP* scip, /**< SCIP data structure */
8301 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8302 SCIP_CONS** conss, /**< constraints to process */
8303 int nconss, /**< number of constraints */
8304 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8305 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8306 )
8307 {
8308 SCIP_Longint soltag;
8309 SCIP_Bool haveviol = FALSE;
8310 int c;
8311
8312 *result = SCIP_DIDNOTFIND;
8313
8314 soltag = SCIPgetExprNewSoltag(scip);
8315
8316 /* compute violations */
8317 for( c = 0; c < nconss; ++c )
8318 {
8319 assert(conss[c] != NULL);
8320
8321 /* skip constraints that are not enabled, deleted, or have separation disabled */
8322 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8323 continue;
8324 assert(SCIPconsIsActive(conss[c]));
8325
8326 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8327
8328 if( isConsViolated(scip, conss[c]) )
8329 haveviol = TRUE;
8330 }
8331
8332 /* if none of our constraints are violated, don't attempt separation */
8333 if( !haveviol )
8334 {
8335 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8336 return SCIP_OKAY;
8337 }
8338
8339 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8340
8341 /* call separation */
8342 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8343
8344 return SCIP_OKAY;
8345 }
8346
8347 /** hash key retrieval function for bilinear term entries */
8348 static
8349 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8350 { /*lint --e{715}*/
8351 SCIP_CONSHDLRDATA* conshdlrdata;
8352 int idx;
8353
8354 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8355 assert(conshdlrdata != NULL);
8356
8357 idx = ((int)(size_t)elem) - 1;
8358 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8359
8360 return (void*)&conshdlrdata->bilinterms[idx];
8361 }
8362
8363 /** returns TRUE iff the bilinear term entries are equal */
8364 static
8365 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8366 { /*lint --e{715}*/
8367 SCIP_CONSNONLINEAR_BILINTERM* entry1;
8368 SCIP_CONSNONLINEAR_BILINTERM* entry2;
8369
8370 /* get corresponding entries */
8371 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8372 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8373 assert(entry1->x != NULL && entry1->y != NULL);
8374 assert(entry2->x != NULL && entry2->y != NULL);
8375 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8376 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8377
8378 return entry1->x == entry2->x && entry1->y == entry2->y;
8379 }
8380
8381 /** returns the hash value of the key */
8382 static
8383 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8384 { /*lint --e{715}*/
8385 SCIP_CONSNONLINEAR_BILINTERM* entry;
8386
8387 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8388 assert(entry->x != NULL && entry->y != NULL);
8389 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8390
8391 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8392 }
8393
8394 /** compare two auxiliary expressions
8395 *
8396 * Compares auxiliary variables, followed by coefficients, and then constants.
8397 */
8398 static
8399 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8400 {
8401 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr1 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem1;
8402 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr2 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem2;
8403 int compvars;
8404 int i;
8405
8406 /* compare the auxiliary variables */
8407 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8408
8409 if( compvars != 0 )
8410 return compvars;
8411
8412 /* compare the coefficients and constants */
8413 for( i = 0; i < 3; ++i )
8414 {
8415 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8416 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8417 }
8418
8419 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8420 }
8421
8422 /* add an auxiliary expression to a bilinear term */
8423 static
8424 SCIP_RETCODE bilinTermAddAuxExpr(
8425 SCIP* scip, /**< SCIP data structure */
8426 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8427 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8428 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8429 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8430 )
8431 {
8432 SCIP_Bool found;
8433 int pos;
8434 int i;
8435
8436 *added = FALSE;
8437
8438 /* check if auxexpr has already been added to term */
8439 if( term->nauxexprs == 0 )
8440 {
8441 found = FALSE;
8442 pos = 0;
8443 }
8444 else
8445 {
8446 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8447 }
8448
8449 if( !found )
8450 {
8451 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8452 return SCIP_OKAY;
8453
8454 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8455 assert(term->auxexprssize >= term->nauxexprs + 1);
8456
8457 /* insert expression at the correct position */
8458 for( i = term->nauxexprs; i > pos; --i )
8459 {
8460 term->aux.exprs[i] = term->aux.exprs[i-1];
8461 }
8462 term->aux.exprs[pos] = auxexpr;
8463 ++(term->nauxexprs);
8464 *added = TRUE;
8465 }
8466 else
8467 {
8468 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8469 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8470 }
8471
8472 return SCIP_OKAY;
8473 }
8474
8475 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8476 static
8477 SCIP_RETCODE bilinearTermsInsertAll(
8478 SCIP* scip, /**< SCIP data structure */
8479 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8480 SCIP_CONS** conss, /**< nonlinear constraints */
8481 int nconss /**< total number of nonlinear constraints */
8482 )
8483 {
8484 SCIP_CONSHDLRDATA* conshdlrdata;
8485 SCIP_EXPRITER* it;
8486 int c;
8487
8488 assert(conss != NULL || nconss == 0);
8489
8490 if( nconss == 0 )
8491 return SCIP_OKAY;
8492
8493 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8494 assert(conshdlrdata != NULL);
8495
8496 /* check whether the bilinear terms have been stored already */
8497 if( conshdlrdata->bilinterms != NULL )
8498 return SCIP_OKAY;
8499
8500 /* create and initialize iterator */
8501 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8502 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
8503 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
8504
8505 /* iterate through all constraints */
8506 for( c = 0; c < nconss; ++c )
8507 {
8508 SCIP_CONSDATA* consdata;
8509 SCIP_EXPR* expr;
8510
8511 assert(conss != NULL && conss[c] != NULL);
8512 consdata = SCIPconsGetData(conss[c]);
8513 assert(consdata != NULL);
8514
8515 /* iterate through all expressions */
8516 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8517 {
8518 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8519 SCIP_VAR* x = NULL;
8520 SCIP_VAR* y = NULL;
8521
8522 /* check whether the expression is of the form f(..)^2 */
8523 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8524 {
8525 x = SCIPgetExprAuxVarNonlinear(children[0]);
8526 y = x;
8527 }
8528 /* check whether the expression is of the form f(..) * g(..) */
8529 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8530 {
8531 x = SCIPgetExprAuxVarNonlinear(children[0]);
8532 y = SCIPgetExprAuxVarNonlinear(children[1]);
8533 }
8534
8535 /* add variables to the hash table */
8536 if( x != NULL && y != NULL )
8537 {
8538 SCIP_CALL( SCIPinsertBilinearTermExistingNonlinear(scip, conshdlr, x, y, SCIPgetExprAuxVarNonlinear(expr),
8539 SCIPgetExprNLocksPosNonlinear(expr), SCIPgetExprNLocksNegNonlinear(expr)) );
8540 }
8541 }
8542 }
8543
8544 /* release iterator */
8545 SCIPfreeExpriter(&it);
8546
8547 return SCIP_OKAY;
8548 }
8549
8550 /** store x, y and the locks in a new bilinear term */
8551 static
8552 SCIP_RETCODE bilinearTermsInsertEntry(
8553 SCIP* scip, /**< SCIP data structure */
8554 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8555 SCIP_VAR* x, /**< the first variable */
8556 SCIP_VAR* y, /**< the second variable */
8557 int nlockspos, /**< number of positive locks of the bilinear term */
8558 int nlocksneg, /**< number of negative locks of the bilinear term */
8559 int* idx, /**< pointer to store the position of the term in bilinterms array */
8560 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8561 )
8562 {
8563 SCIP_CONSHDLRDATA* conshdlrdata;
8564 SCIP_CONSNONLINEAR_BILINTERM* term;
8565
8566 assert(conshdlr != NULL);
8567 assert(x != NULL);
8568 assert(y != NULL);
8569 assert(nlockspos >= 0);
8570 assert(nlocksneg >= 0);
8571
8572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8573 assert(conshdlrdata != NULL);
8574
8575 /* ensure that x.index <= y.index */
8576 if( SCIPvarCompare(x, y) == 1 )
8577 {
8578 SCIPswapPointers((void**)&x, (void**)&y);
8579 }
8580 assert(SCIPvarCompare(x, y) < 1);
8581
8582 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8583
8584 /* update or create the term */
8585 if( *idx >= 0 )
8586 { /* the term has already been added */
8587 assert(conshdlrdata->bilinterms[*idx].x == x);
8588 assert(conshdlrdata->bilinterms[*idx].y == y);
8589
8590 /* get term and add locks */
8591 term = &conshdlrdata->bilinterms[*idx];
8592 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8593 term->nlockspos += nlockspos;
8594 term->nlocksneg += nlocksneg;
8595 }
8596 else
8597 { /* this is the first time we encounter this product */
8598 /* ensure size of bilinterms array */
8599 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8600
8601 *idx = conshdlrdata->nbilinterms;
8602
8603 /* get term and set values in the created bilinear term */
8604 term = &conshdlrdata->bilinterms[*idx];
8605 assert(term != NULL);
8606 term->x = x;
8607 term->y = y;
8608 term->nauxexprs = 0;
8609 term->auxexprssize = 0;
8610 term->nlockspos = nlockspos;
8611 term->nlocksneg = nlocksneg;
8612 term->existing = existing;
8613 if( existing )
8614 term->aux.var = NULL;
8615 else
8616 term->aux.exprs = NULL;
8617
8618 /* increase the total number of bilinear terms */
8619 ++(conshdlrdata->nbilinterms);
8620
8621 /* save to the hashtable */
8622 if( conshdlrdata->bilinhashtable == NULL )
8623 {
8624 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8625 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8626 (void*)conshdlrdata) );
8627 }
8628 assert(conshdlrdata->bilinhashtable != NULL);
8629
8630 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8631 * because zero can not be inserted into hash table
8632 */
8633 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8634
8635 /* capture product variables */
8636 SCIP_CALL( SCIPcaptureVar(scip, x) );
8637 SCIP_CALL( SCIPcaptureVar(scip, y) );
8638 }
8639
8640 return SCIP_OKAY;
8641 }
8642
8643 /** frees array of bilinear terms and hash table */
8644 static
8645 SCIP_RETCODE bilinearTermsFree(
8646 SCIP* scip, /**< SCIP data structure */
8647 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8648 )
8649 {
8650 int i;
8651 int j;
8652
8653 assert(conshdlrdata != NULL);
8654
8655 /* check whether bilinear terms have been stored */
8656 if( conshdlrdata->bilinterms == NULL )
8657 {
8658 assert(conshdlrdata->bilinterms == NULL);
8659 assert(conshdlrdata->nbilinterms == 0);
8660 assert(conshdlrdata->bilintermssize == 0);
8661
8662 return SCIP_OKAY;
8663 }
8664
8665 /* release variables */
8666 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8667 {
8668 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8669 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8670
8671 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8672 {
8673 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8674 {
8675 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8676 }
8677 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8678 }
8679
8680 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8681 {
8682 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8683 continue;
8684 }
8685
8686 /* the rest is for simple terms with a single auxvar */
8687
8688 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8689 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8690 {
8691 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8692 }
8693 }
8694
8695 /* free hash table */
8696 if( conshdlrdata->bilinhashtable != NULL )
8697 {
8698 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8699 }
8700
8701 /* free bilinterms array; reset counters */
8702 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8703 conshdlrdata->nbilinterms = 0;
8704 conshdlrdata->bilintermssize = 0;
8705
8706 return SCIP_OKAY;
8707 }
8708
8709 /*
8710 * vertex polyhedral separation
8711 */
8712
8713 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8714 static
8715 SCIP_RETCODE buildVertexPolyhedralSeparationLP(
8716 SCIP* scip, /**< SCIP data structure */
8717 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8718 SCIP_LPI** lp /**< pointer to store created LP */
8719 )
8720 {
8721 SCIP_Real* obj;
8722 SCIP_Real* lb;
8723 SCIP_Real* ub;
8724 SCIP_Real* val;
8725 int* beg;
8726 int* ind;
8727 unsigned int nnonz;
8728 unsigned int ncols;
8729 unsigned int nrows;
8730 unsigned int i;
8731 unsigned int k;
8732
8733 assert(scip != NULL);
8734 assert(lp != NULL);
8735 assert(nvars > 0);
8736 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8737
8738 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8739
8740 /* create lpi to store the LP */
8741 SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8742
8743 nrows = (unsigned int)nvars + 1;
8744 ncols = POWEROFTWO((unsigned int)nvars);
8745 nnonz = (ncols * (nrows + 1)) / 2;
8746
8747 /* allocate necessary memory; set obj, lb, and ub to zero */
8748 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8749 SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8750 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8751 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8752 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8753 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8754
8755 /* calculate nonzero entries in the LP */
8756 for( i = 0, k = 0; i < ncols; ++i )
8757 {
8758 int row;
8759 unsigned int a;
8760
8761 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8762 ub[i] = SCIPlpiInfinity(*lp);
8763
8764 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8765 beg[i] = (int)k;
8766 row = 0;
8767
8768 /* iterate through the bit representation of i */
8769 a = 1;
8770 while( a <= i )
8771 {
8772 if( (a & i) != 0 )
8773 {
8774 val[k] = 1.0;
8775 ind[k] = row;
8776
8777 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8778
8779 ++k;
8780 }
8781
8782 a <<= 1;
8783 ++row;
8784 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8785 assert(POWEROFTWO(row) == a);
8786 }
8787
8788 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8789 val[k] = 1.0;
8790 ind[k] = (int)nrows - 1;
8791 ++k;
8792 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8793 }
8794 assert(k == nnonz);
8795
8796 /* load all data into LP interface
8797 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8798 */
8799 assert(nrows <= ncols);
8800 SCIP_CALL( SCIPlpiLoadColLP(*lp, SCIP_OBJSEN_MINIMIZE,
8801 (int)ncols, obj, lb, ub, NULL,
8802 (int)nrows, lb, lb, NULL,
8803 (int)nnonz, beg, ind, val) );
8804
8805 /* for the last row, we can set the rhs to 1.0 already */
8806 ind[0] = (int)nrows - 1;
8807 val[0] = 1.0;
8808 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8809
8810 /* free allocated memory */
8811 SCIPfreeBufferArray(scip, &ind);
8812 SCIPfreeBufferArray(scip, &val);
8813 SCIPfreeBufferArray(scip, &beg);
8814 SCIPfreeBufferArray(scip, &ub);
8815 SCIPfreeBufferArray(scip, &lb);
8816 SCIPfreeBufferArray(scip, &obj);
8817
8818 return SCIP_OKAY;
8819 }
8820
8821 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8822 * \max_{v \in V} f(v) - (\alpha v + \beta) \f$ (\f$\max_{v \in V} \alpha v + \beta - f(v) \f$) where \f$ V \f$ is the
8823 * set of vertices of the domain
8824 */
8825 static
8826 SCIP_Real computeVertexPolyhedralMaxFacetError(
8827 SCIP* scip, /**< SCIP data structure */
8828 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8829 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8830 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8831 int nallvars, /**< number of all variables */
8832 int nvars, /**< number of unfixed variables */
8833 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8834 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8835 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8836 )
8837 {
8838 SCIP_Real maxerror;
8839 SCIP_Real facetval;
8840 SCIP_Real funval;
8841 SCIP_Real error;
8842 unsigned int i;
8843 unsigned int ncorners;
8844 unsigned int prev;
8845
8846 assert(scip != NULL);
8847 assert(funvals != NULL);
8848 assert(box != NULL);
8849 assert(nonfixedpos != NULL);
8850 assert(facetcoefs != NULL);
8851
8852 ncorners = POWEROFTWO(nvars);
8853 maxerror = 0.0;
8854
8855 /* check the origin (all variables at lower bound) */
8856 facetval = facetconstant;
8857 for( i = 0; i < (unsigned int) nallvars; ++i )
8858 facetval += facetcoefs[i] * box[2*i];
8859
8860 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8861 funval = funvals[0];
8862 if( overestimate )
8863 error = funval - facetval;
8864 else
8865 error = facetval - funval;
8866
8867 /* update maximum error */
8868 maxerror = MAX(error, maxerror);
8869
8870 prev = 0;
8871 for( i = 1; i < ncorners; ++i )
8872 {
8873 unsigned int gray;
8874 unsigned int diff;
8875 unsigned int pos;
8876 int origpos;
8877
8878 gray = i ^ (i >> 1);
8879 diff = gray ^ prev;
8880
8881 /* compute position of unique 1 of diff */
8882 pos = 0;
8883 while( (diff >>= 1) != 0 )
8884 ++pos;
8885 assert(pos < (unsigned int)nvars);
8886
8887 origpos = nonfixedpos[pos];
8888
8889 if( gray > prev )
8890 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8891 else
8892 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8893
8894 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8895 funval = funvals[gray];
8896 if( overestimate )
8897 error = funval - facetval;
8898 else
8899 error = facetval - funval;
8900
8901 /* update maximum error */
8902 maxerror = MAX(error, maxerror);
8903
8904 prev = gray;
8905 }
8906
8907 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8908
8909 return maxerror;
8910 }
8911
8912 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8913 static
8914 SCIP_RETCODE computeVertexPolyhedralFacetLP(
8915 SCIP* scip, /**< SCIP data structure */
8916 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8917 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8918 SCIP_Real* xstar, /**< point to be separated */
8919 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8920 int nallvars, /**< half of the length of box */
8921 int* nonfixedpos, /**< indices of nonfixed variables */
8922 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8923 int nvars, /**< number of nonfixed variables */
8924 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8925 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8926 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8927 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8928 )
8929 { /*lint --e{715}*/
8930 SCIP_CONSHDLRDATA* conshdlrdata;
8931 SCIP_LPI* lp;
8932 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8933 int* inds;
8934 int ncols;
8935 int nrows;
8936 int i;
8937 SCIP_Real facetvalue;
8938 SCIP_Real mindomwidth;
8939 SCIP_RETCODE lpsolveretcode;
8940
8941 assert(scip != NULL);
8942 assert(conshdlr != NULL);
8943 assert(xstar != NULL);
8944 assert(box != NULL);
8945 assert(nonfixedpos != NULL);
8946 assert(funvals != NULL);
8947 assert(nvars >= 0);
8948 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8949 assert(success != NULL);
8950 assert(facetcoefs != NULL);
8951 assert(facetconstant != NULL);
8952
8953 *success = FALSE;
8954
8955 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8956 assert(conshdlrdata != NULL);
8957
8958 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8959 {
8960 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8961 }
8962
8963 /* construct an LP for this size, if not having one already */
8964 if( conshdlrdata->vp_lp[nvars] == NULL )
8965 {
8966 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8967 }
8968 lp = conshdlrdata->vp_lp[nvars];
8969 assert(lp != NULL);
8970
8971 /* get number of cols and rows of separation lp */
8972 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8973 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8974
8975 /* number of columns should equal the number of corners = 2^nvars */
8976 assert(ncols == (int)POWEROFTWO(nvars));
8977
8978 /* allocate necessary memory */
8979 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8980 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8981
8982 /*
8983 * set up the described LP on the transformed space
8984 */
8985
8986 for( i = 0; i < ncols; ++i )
8987 inds[i] = i;
8988
8989 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8990 mindomwidth = 2*SCIPinfinity(scip);
8991 for( i = 0; i < nrows-1; ++i )
8992 {
8993 SCIP_Real solval;
8994 SCIP_Real lb;
8995 SCIP_Real ub;
8996 int varpos;
8997
8998 assert(i < nvars);
8999
9000 varpos = nonfixedpos[i];
9001 lb = box[2 * varpos];
9002 ub = box[2 * varpos + 1];
9003 solval = xstar[varpos];
9004
9005 if( ub - lb < mindomwidth )
9006 mindomwidth = ub - lb;
9007
9008 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9009 if( solval <= lb )
9010 aux[i] = 0.0;
9011 else if( solval >= ub )
9012 aux[i] = 1.0;
9013 else
9014 aux[i] = (solval - lb) / (ub - lb);
9015
9016 /* perturb point to hopefully obtain a facet of the convex envelope */
9017 if( conshdlrdata->vp_maxperturb > 0.0 )
9018 {
9019 assert(conshdlrdata->vp_randnumgen != NULL);
9020
9021 if( aux[i] == 1.0 )
9022 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9023 else if( aux[i] == 0.0 )
9024 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9025 else
9026 {
9027 SCIP_Real perturbation;
9028
9029 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9030 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9031 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9032 }
9033 assert(0.0 < aux[i] && aux[i] < 1.0);
9034 }
9035
9036 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9037 }
9038
9039 /* update LP */
9040 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9041 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9042 SCIP_CALL( SCIPlpiChgObjsen(lp, overestimate ? SCIP_OBJSEN_MAXIMIZE : SCIP_OBJSEN_MINIMIZE) );
9043
9044 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9045 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9046 {
9047 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9048 }
9049 /* set an iteration limit so we do not run forever */
9050 SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9051 /* since we work with the dual of the LP, primal feastol determines how much we want the computed facet to be the best possible one */
9052 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_FEASTOL, SCIPfeastol(scip)) );
9053 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9054 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9055 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9056 */
9057 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9058
9059 #ifdef SCIP_DEBUG
9060 SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPINFO, 1) );
9061 #endif
9062
9063 /*
9064 * solve the LP and store the resulting facet for the transformed space
9065 */
9066 if( conshdlrdata->vp_dualsimplex )
9067 {
9068 lpsolveretcode = SCIPlpiSolveDual(lp);
9069 }
9070 else
9071 {
9072 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9073 }
9074 if( lpsolveretcode == SCIP_LPERROR )
9075 {
9076 SCIPdebugMsg(scip, "LP error, aborting.\n");
9077 goto CLEANUP;
9078 }
9079 SCIP_CALL( lpsolveretcode );
9080
9081 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9082 if( !SCIPlpiIsDualFeasible(lp) )
9083 {
9084 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9085 goto CLEANUP;
9086 }
9087
9088 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9089 * columns than needed, in particular, \bar \beta is the last dual multiplier
9090 */
9091 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9092
9093 for( i = 0; i < nvars; ++i )
9094 facetcoefs[nonfixedpos[i]] = aux[i];
9095 /* last dual multiplier is the constant */
9096 *facetconstant = aux[nrows - 1];
9097
9098 #ifdef SCIP_DEBUG
9099 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9100 for( i = 0; i < nallvars; ++i )
9101 {
9102 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9103 }
9104 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9105 #endif
9106
9107 /*
9108 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9109 */
9110
9111 SCIPdebugMsg(scip, "facet in orig. space: ");
9112
9113 facetvalue = 0.0;
9114 for( i = 0; i < nvars; ++i )
9115 {
9116 SCIP_Real lb;
9117 SCIP_Real ub;
9118 int varpos;
9119
9120 varpos = nonfixedpos[i];
9121 lb = box[2 * varpos];
9122 ub = box[2 * varpos + 1];
9123 assert(!SCIPisEQ(scip, lb, ub));
9124
9125 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9126 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9127
9128 /* beta = beta_bar - sum_i alpha_i * lb_i */
9129 *facetconstant -= facetcoefs[varpos] * lb;
9130
9131 /* evaluate */
9132 facetvalue += facetcoefs[varpos] * xstar[varpos];
9133
9134 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9135 }
9136 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9137
9138 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9139 facetvalue += *facetconstant;
9140
9141 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9142
9143 /* if overestimate, then we want facetvalue < targetvalue
9144 * if underestimate, then we want facetvalue > targetvalue
9145 * if none holds, give up
9146 * so maybe here we should check against the minimal violation
9147 */
9148 if( overestimate == (facetvalue > targetvalue) )
9149 {
9150 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9151 goto CLEANUP;
9152 }
9153
9154 /* if we made it until here, then we have a nice facet */
9155 *success = TRUE;
9156
9157 CLEANUP:
9158 /* free allocated memory */
9159 SCIPfreeBufferArray(scip, &inds);
9160 SCIPfreeBufferArray(scip, &aux);
9161
9162 return SCIP_OKAY;
9163 }
9164
9165 /** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9166 *
9167 * In other words, compute the line that passes through two given points.
9168 */
9169 static
9170 SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(
9171 SCIP* scip, /**< SCIP data structure */
9172 SCIP_Real left, /**< left coordinate */
9173 SCIP_Real right, /**< right coordinate */
9174 SCIP_Real funleft, /**< value of function in left coordinate */
9175 SCIP_Real funright, /**< value of function in right coordinate */
9176 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9177 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9178 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9179 )
9180 {
9181 assert(scip != NULL);
9182 assert(SCIPisLE(scip, left, right));
9183 assert(!SCIPisInfinity(scip, -left));
9184 assert(!SCIPisInfinity(scip, right));
9185 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9186 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9187 assert(success != NULL);
9188 assert(facetcoef != NULL);
9189 assert(facetconstant != NULL);
9190
9191 *facetcoef = (funright - funleft) / (right - left);
9192 *facetconstant = funleft - *facetcoef * left;
9193
9194 *success = TRUE;
9195
9196 return SCIP_OKAY;
9197 }
9198
9199 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9200 *
9201 * Three points a, b, and c are given.
9202 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9203 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9204 */
9205 static
9206 SCIP_RETCODE computeHyperplaneThreePoints(
9207 SCIP* scip, /**< SCIP data structure */
9208 SCIP_Real a1, /**< first coordinate of a */
9209 SCIP_Real a2, /**< second coordinate of a */
9210 SCIP_Real a3, /**< third coordinate of a */
9211 SCIP_Real b1, /**< first coordinate of b */
9212 SCIP_Real b2, /**< second coordinate of b */
9213 SCIP_Real b3, /**< third coordinate of b */
9214 SCIP_Real c1, /**< first coordinate of c */
9215 SCIP_Real c2, /**< second coordinate of c */
9216 SCIP_Real c3, /**< third coordinate of c */
9217 SCIP_Real* alpha, /**< coefficient of first coordinate */
9218 SCIP_Real* beta, /**< coefficient of second coordinate */
9219 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9220 SCIP_Real* delta /**< constant right-hand side */
9221 )
9222 {
9223 assert(scip != NULL);
9224 assert(alpha != NULL);
9225 assert(beta != NULL);
9226 assert(gamma_ != NULL);
9227 assert(delta != NULL);
9228
9229 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9230 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9231 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9232 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9233
9234 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9235
9236 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9237 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9238 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9239 {
9240 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9241 *delta = 0.0;
9242 *alpha = 0.0;
9243 *beta = 0.0;
9244 *gamma_ = 0.0;
9245 return SCIP_OKAY;
9246 }
9247
9248 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9249 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9250 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9251 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9252 {
9253 SCIP_Real m[9];
9254 SCIP_Real rhs[3];
9255 SCIP_Real x[3];
9256 SCIP_Bool success;
9257
9258 /*
9259 SCIPdebugMsg(scip, "a = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", a1, a2, a3, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3, SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3));
9260 SCIPdebugMsg(scip, "b = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", b1, b2, b3, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3, SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3));
9261 SCIPdebugMsg(scip, "c = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", c1, c2, c3, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3, SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3));
9262 */
9263
9264 /* initialize matrix column-wise */
9265 m[0] = a1;
9266 m[1] = b1;
9267 m[2] = c1;
9268 m[3] = a2;
9269 m[4] = b2;
9270 m[5] = c2;
9271 m[6] = a3;
9272 m[7] = b3;
9273 m[8] = c3;
9274
9275 rhs[0] = 1.0;
9276 rhs[1] = 1.0;
9277 rhs[2] = 1.0;
9278
9279 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9280
9281 /* solve the linear problem */
9282 SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9283
9284 *delta = rhs[0];
9285 *alpha = x[0];
9286 *beta = x[1];
9287 *gamma_ = x[2];
9288
9289 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9290 * not add a cut to SCIP and that all assertions are trivially fulfilled
9291 */
9292 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9293 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9294 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9295 {
9296 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9297 *delta = 0.0;
9298 *alpha = 0.0;
9299 *beta = 0.0;
9300 *gamma_ = 0.0;
9301 }
9302 }
9303
9304 if( *gamma_ < 0.0 )
9305 {
9306 *alpha = -*alpha;
9307 *beta = -*beta;
9308 *gamma_ = -*gamma_;
9309 *delta = -*delta;
9310 }
9311
9312 return SCIP_OKAY;
9313 }
9314
9315 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9316 static
9317 SCIP_RETCODE computeVertexPolyhedralFacetBivariate(
9318 SCIP* scip, /**< SCIP data structure */
9319 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9320 SCIP_Real p1[2], /**< first vertex of box */
9321 SCIP_Real p2[2], /**< second vertex of box */
9322 SCIP_Real p3[2], /**< third vertex of box */
9323 SCIP_Real p4[2], /**< forth vertex of box */
9324 SCIP_Real p1val, /**< value in p1 */
9325 SCIP_Real p2val, /**< value in p2 */
9326 SCIP_Real p3val, /**< value in p3 */
9327 SCIP_Real p4val, /**< value in p4 */
9328 SCIP_Real xstar[2], /**< point to be separated */
9329 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9330 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9331 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9332 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9333 )
9334 {
9335 SCIP_Real alpha, beta, gamma_, delta;
9336 SCIP_Real xstarval, candxstarval = 0.0;
9337 int leaveout;
9338
9339 assert(scip != NULL);
9340 assert(success != NULL);
9341 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9342 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9343 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9344 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9345 assert(facetcoefs != NULL);
9346 assert(facetconstant != NULL);
9347
9348 *success = FALSE;
9349
9350 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9351 if( !overestimate )
9352 {
9353 p1val = -p1val;
9354 p2val = -p2val;
9355 p3val = -p3val;
9356 p4val = -p4val;
9357 targetvalue = -targetvalue;
9358 }
9359
9360 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9361 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9362 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9363 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9364
9365 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9366 * alpha*x + beta*y + gamma*z = delta
9367 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9368 * the fourth corner point lies below this hyperplane.
9369 * Since we assume that f is vertex-polyhedral, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
9370 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9371 * or, equivalently,
9372 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9373 */
9374 for( leaveout = 1; leaveout <= 4; ++leaveout )
9375 {
9376 switch( leaveout)
9377 {
9378 case 1 :
9379 /* get hyperplane through p2, p3, p4 */
9380 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9381 &alpha, &beta, &gamma_, &delta) );
9382 /* if not underestimating in p1, then go to next candidate */
9383 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9384 continue;
9385 break;
9386
9387 case 2 :
9388 /* get hyperplane through p1, p3, p4 */
9389 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9390 &alpha, &beta, &gamma_, &delta) );
9391 /* if not underestimating in p2, then go to next candidate */
9392 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9393 continue;
9394 break;
9395
9396 case 3 :
9397 /* get hyperplane through p1, p2, p4 */
9398 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9399 &alpha, &beta, &gamma_, &delta) );
9400 /* if not underestimating in p3, then go to next candidate */
9401 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9402 continue;
9403 break;
9404
9405 case 4 :
9406 /* get hyperplane through p1, p2, p3 */
9407 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9408 &alpha, &beta, &gamma_, &delta) );
9409 /* if not underestimating in p4, then stop */
9410 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9411 continue;
9412 break;
9413
9414 default: /* only for lint */
9415 alpha = SCIP_INVALID;
9416 beta = SCIP_INVALID;
9417 gamma_ = SCIP_INVALID;
9418 delta = SCIP_INVALID;
9419 break;
9420 }
9421
9422 /* check if bad luck: should not happen if numerics are fine */
9423 if( SCIPisZero(scip, gamma_) )
9424 continue;
9425 assert(!SCIPisNegative(scip, gamma_));
9426
9427 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9428 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9429 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9430 continue;
9431
9432 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9433
9434 /* value of hyperplane candidate in xstar */
9435 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9436
9437 /* if reaching target and first or better than previous candidate, then update */
9438 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9439 {
9440 /* flip hyperplane */
9441 if( !overestimate )
9442 gamma_ = -gamma_;
9443
9444 facetcoefs[0] = -alpha/gamma_;
9445 facetcoefs[1] = -beta/gamma_;
9446 *facetconstant = delta/gamma_;
9447
9448 *success = TRUE;
9449 candxstarval = xstarval;
9450 }
9451 }
9452
9453 return SCIP_OKAY;
9454 }
9455
9456 /*
9457 * Callback methods of constraint handler
9458 */
9459
9460 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9461 static
9462 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9463 { /*lint --e{715}*/
9464 SCIP_CONSHDLR* targetconshdlr;
9465 SCIP_CONSHDLRDATA* sourceconshdlrdata;
9466 int i;
9467
9468 assert(scip != NULL);
9469 assert(conshdlr != NULL);
9470 assert(valid != NULL);
9471 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9472
9473 /* create basic data of constraint handler and include it to scip */
9474 SCIP_CALL( SCIPincludeConshdlrNonlinear(scip) );
9475
9476 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9477 assert(targetconshdlr != NULL);
9478 assert(targetconshdlr != conshdlr);
9479
9480 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9481 assert(sourceconshdlrdata != NULL);
9482
9483 /* copy nonlinear handlers */
9484 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9485 {
9486 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9487 }
9488
9489 *valid = TRUE;
9490
9491 return SCIP_OKAY;
9492 }
9493
9494 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9495 static
9496 SCIP_DECL_CONSFREE(consFreeNonlinear)
9497 { /*lint --e{715}*/
9498 SCIP_CONSHDLRDATA* conshdlrdata;
9499 int i;
9500
9501 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9502 assert(conshdlrdata != NULL);
9503
9504 /* free nonlinear handlers */
9505 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9506 {
9507 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9508 assert(conshdlrdata->nlhdlrs[i] == NULL);
9509 }
9510 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9511 conshdlrdata->nlhdlrssize = 0;
9512
9513 /* free upgrade functions */
9514 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9515 {
9516 assert(conshdlrdata->consupgrades[i] != NULL);
9517 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9518 }
9519 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9520
9521 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9522
9523 SCIPqueueFree(&conshdlrdata->reversepropqueue);
9524
9525 if( conshdlrdata->vp_randnumgen != NULL )
9526 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9527
9528 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9529 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9530 {
9531 if( conshdlrdata->vp_lp[i] != NULL )
9532 {
9533 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9534 }
9535 }
9536
9537 assert(conshdlrdata->branchrandnumgen == NULL);
9538
9539 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9540 SCIPhashmapFree(&conshdlrdata->var2expr);
9541
9542 SCIPfreeMemory(scip, &conshdlrdata);
9543 SCIPconshdlrSetData(conshdlr, NULL);
9544
9545 return SCIP_OKAY;
9546 }
9547
9548
9549 /** initialization method of constraint handler (called after problem was transformed) */
9550 static
9551 SCIP_DECL_CONSINIT(consInitNonlinear)
9552 { /*lint --e{715}*/
9553 SCIP_CONSHDLRDATA* conshdlrdata;
9554 int i;
9555
9556 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9557 assert(conshdlrdata != NULL);
9558
9559 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9560 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9561 /* set to 1 so it is larger than initial value of lastenforound in exprs */
9562 conshdlrdata->enforound = 1;
9563 /* reset numbering for auxiliary variables */
9564 conshdlrdata->auxvarid = 0;
9565
9566 for( i = 0; i < nconss; ++i )
9567 {
9568 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9569 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9570 }
9571
9572 /* sort nonlinear handlers by detection priority, in decreasing order */
9573 if( conshdlrdata->nnlhdlrs > 1 )
9574 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9575
9576 /* get heuristics for later use */
9577 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9578 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9579
9580 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9581 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9582 {
9583 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9584 }
9585
9586 /* reset statistics in constraint handler */
9587 conshdlrdata->nweaksepa = 0;
9588 conshdlrdata->ntightenlp = 0;
9589 conshdlrdata->ndesperatebranch = 0;
9590 conshdlrdata->ndesperatecutoff = 0;
9591 conshdlrdata->ndesperatetightenlp = 0;
9592 conshdlrdata->nforcelp = 0;
9593 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9594 conshdlrdata->ncanonicalizecalls = 0;
9595
9596 #ifdef ENFOLOGFILE
9597 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9598 #endif
9599
9600 return SCIP_OKAY;
9601 }
9602
9603
9604 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9605 static
9606 SCIP_DECL_CONSEXIT(consExitNonlinear)
9607 { /*lint --e{715}*/
9608 SCIP_CONSHDLRDATA* conshdlrdata;
9609 SCIP_CONS** consssorted;
9610 int i;
9611
9612 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9613 assert(conshdlrdata != NULL);
9614
9615 if( nconss > 0 )
9616 {
9617 /* for better performance of dropVarEvents, we sort by index, descending */
9618 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9619 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9620
9621 for( i = 0; i < nconss; ++i )
9622 {
9623 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9624 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9625 }
9626
9627 SCIPfreeBufferArray(scip, &consssorted);
9628 }
9629
9630 conshdlrdata->subnlpheur = NULL;
9631 conshdlrdata->trysolheur = NULL;
9632
9633 if( conshdlrdata->vp_randnumgen != NULL )
9634 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9635
9636 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9637 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9638 {
9639 if( conshdlrdata->vp_lp[i] != NULL )
9640 {
9641 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9642 }
9643 }
9644
9645 if( conshdlrdata->branchrandnumgen != NULL )
9646 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9647
9648 /* deinitialize nonlinear handlers */
9649 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9650 {
9651 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9652 }
9653
9654 ENFOLOG(
9655 if( enfologfile != NULL )
9656 {
9657 fclose(enfologfile);
9658 enfologfile = NULL;
9659 })
9660
9661 return SCIP_OKAY;
9662 }
9663
9664
9665 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9666 #ifdef SCIP_DISABLED_CODE
9667 static
9668 SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
9669 { /*lint --e{715}*/
9670 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9671 SCIPABORT(); /*lint --e{527}*/
9672
9673 return SCIP_OKAY;
9674 }
9675 #else
9676 #define consInitpreNonlinear NULL
9677 #endif
9678
9679
9680 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9681 static
9682 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9683 { /*lint --e{715}*/
9684 SCIP_Bool infeasible;
9685
9686 if( nconss == 0 )
9687 return SCIP_OKAY;
9688
9689 /* skip some extra work if already known to be infeasible */
9690 if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9691 return SCIP_OKAY;
9692
9693 /* simplify constraints and replace common subexpressions */
9694 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9695
9696 /* currently SCIP does not offer to communicate this,
9697 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9698 * or if a constraint expression became constant
9699 */
9700 assert(!infeasible);
9701
9702 /* tell SCIP that we have something nonlinear */
9703 SCIPenableNLP(scip);
9704
9705 return SCIP_OKAY;
9706 }
9707
9708
9709 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9710 static
9711 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9712 { /*lint --e{715}*/
9713 SCIP_CONSHDLRDATA* conshdlrdata;
9714 int i;
9715
9716 /* skip remaining initializations if we have solved already
9717 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9718 * assumes nonempty activities in expressions
9719 */
9720 switch( SCIPgetStatus(scip) )
9721 {
9722 case SCIP_STATUS_OPTIMAL:
9723 case SCIP_STATUS_INFEASIBLE:
9724 case SCIP_STATUS_UNBOUNDED:
9725 case SCIP_STATUS_INFORUNBD:
9726 return SCIP_OKAY;
9727 default: ;
9728 } /*lint !e788 */
9729
9730 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9731 assert(conshdlrdata != NULL);
9732
9733 /* reset one of the number of detections counter to count only current round */
9734 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9735 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9736
9737 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9738
9739 /* catch new solution event */
9740 if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9741 {
9742 SCIP_EVENTHDLR* eventhdlr;
9743
9744 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9745 assert(eventhdlr != NULL);
9746
9747 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9748 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9749 }
9750
9751 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9752 if( conshdlrdata->branchpscostweight > 0.0 )
9753 {
9754 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9755 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9756 {
9757 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9758 SCIPABORT();
9759 return SCIP_INVALIDDATA;
9760 }
9761 }
9762
9763 return SCIP_OKAY;
9764 }
9765
9766
9767 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9768 static
9769 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9770 { /*lint --e{715}*/
9771 SCIP_CONSHDLRDATA* conshdlrdata;
9772
9773 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9774
9775 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9776 assert(conshdlrdata != NULL);
9777
9778 /* free hash table for bilinear terms */
9779 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9780
9781 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9782 conshdlrdata->checkedvarlocks = FALSE;
9783
9784 /* drop catching new solution event, if catched before */
9785 if( conshdlrdata->newsoleventfilterpos >= 0 )
9786 {
9787 SCIP_EVENTHDLR* eventhdlr;
9788
9789 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9790 assert(eventhdlr != NULL);
9791
9792 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9793 conshdlrdata->newsoleventfilterpos = -1;
9794 }
9795
9796 return SCIP_OKAY;
9797 }
9798
9799
9800 /** frees specific constraint data */
9801 static
9802 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9803 { /*lint --e{715}*/
9804 assert(consdata != NULL);
9805 assert(*consdata != NULL);
9806 assert((*consdata)->expr != NULL);
9807
9808 /* constraint locks should have been removed */
9809 assert((*consdata)->nlockspos == 0);
9810 assert((*consdata)->nlocksneg == 0);
9811
9812 /* free variable expressions */
9813 SCIP_CALL( freeVarExprs(scip, *consdata) );
9814
9815 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9816
9817 /* free nonlinear row representation */
9818 if( (*consdata)->nlrow != NULL )
9819 {
9820 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9821 }
9822
9823 SCIPfreeBlockMemory(scip, consdata);
9824
9825 return SCIP_OKAY;
9826 }
9827
9828
9829 /** transforms constraint data into data belonging to the transformed problem */
9830 static
9831 SCIP_DECL_CONSTRANS(consTransNonlinear)
9832 { /*lint --e{715}*/
9833 SCIP_EXPR* targetexpr;
9834 SCIP_CONSDATA* sourcedata;
9835
9836 sourcedata = SCIPconsGetData(sourcecons);
9837 assert(sourcedata != NULL);
9838
9839 /* get a copy of sourceexpr with transformed vars */
9840 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9841 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9842
9843 /* create transformed cons (only captures targetexpr, no need to copy again) */
9844 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9845 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9846 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9847 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9848 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9849 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9850
9851 /* release target expr */
9852 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9853
9854 return SCIP_OKAY;
9855 }
9856
9857
9858 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9859 static
9860 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9861 { /*lint --e{715}*/
9862 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9863 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9864 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9865 * for now, there is an assert in detectNlhdlrs to require initial if separated
9866 */
9867 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9868
9869 /* collect all bilinear terms for which an auxvar is present
9870 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9871 * addition (and removal?) of constraints during solve
9872 * this is typically the majority of constraints, but the method should be made more flexible
9873 */
9874 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9875
9876 return SCIP_OKAY;
9877 }
9878
9879
9880 /** separation method of constraint handler for LP solutions */
9881 static
9882 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9883 { /*lint --e{715}*/
9884 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9885
9886 return SCIP_OKAY;
9887 }
9888
9889
9890 /** separation method of constraint handler for arbitrary primal solutions */
9891 static
9892 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9893 { /*lint --e{715}*/
9894 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9895
9896 return SCIP_OKAY;
9897 }
9898
9899
9900 /** constraint enforcing method of constraint handler for LP solutions */
9901 static
9902 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9903 { /*lint --e{715}*/
9904 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9905
9906 return SCIP_OKAY;
9907 }
9908
9909
9910 /** constraint enforcing method of constraint handler for relaxation solutions */
9911 static
9912 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9913 { /*lint --e{715}*/
9914 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9915
9916 return SCIP_OKAY;
9917 }
9918
9919
9920 /** constraint enforcing method of constraint handler for pseudo solutions */
9921 static
9922 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9923 { /*lint --e{715}*/
9924 SCIP_RESULT propresult;
9925 SCIP_Longint soltag;
9926 int nchgbds;
9927 int nnotify;
9928 int c;
9929
9930 soltag = SCIPgetExprNewSoltag(scip);
9931
9932 *result = SCIP_FEASIBLE;
9933 for( c = 0; c < nconss; ++c )
9934 {
9935 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9936
9937 if( isConsViolated(scip, conss[c]) )
9938 *result = SCIP_INFEASIBLE;
9939 }
9940
9941 if( *result == SCIP_FEASIBLE )
9942 return SCIP_OKAY;
9943
9944 /* try to propagate
9945 * TODO obey propinenfo parameter, but we need something to recognize cutoff
9946 */
9947 nchgbds = 0;
9948 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9949
9950 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9951 {
9952 *result = propresult;
9953 return SCIP_OKAY;
9954 }
9955
9956 /* register all unfixed variables in all violated constraints as branching candidates */
9957 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9958 if( nnotify > 0 )
9959 {
9960 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9961
9962 return SCIP_OKAY;
9963 }
9964
9965 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9966 *result = SCIP_SOLVELP;
9967 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9968
9969 return SCIP_OKAY;
9970 }
9971
9972
9973 /** feasibility check method of constraint handler for integral solutions */
9974 static
9975 SCIP_DECL_CONSCHECK(consCheckNonlinear)
9976 { /*lint --e{715}*/
9977 SCIP_CONSHDLRDATA* conshdlrdata;
9978 SCIP_CONSDATA* consdata;
9979 SCIP_Real maxviol;
9980 SCIP_Bool maypropfeasible;
9981 SCIP_Longint soltag;
9982 int c;
9983
9984 assert(scip != NULL);
9985 assert(conshdlr != NULL);
9986 assert(conss != NULL || nconss == 0);
9987 assert(result != NULL);
9988
9989 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9990 assert(conshdlrdata != NULL);
9991
9992 *result = SCIP_FEASIBLE;
9993 soltag = SCIPgetExprNewSoltag(scip);
9994 maxviol = 0.0;
9995 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
9996 && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
9997
9998 /* check nonlinear constraints for feasibility */
9999 for( c = 0; c < nconss; ++c )
10000 {
10001 assert(conss != NULL && conss[c] != NULL);
10002 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10003
10004 if( isConsViolated(scip, conss[c]) )
10005 {
10006 *result = SCIP_INFEASIBLE;
10007 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10008
10009 consdata = SCIPconsGetData(conss[c]);
10010 assert(consdata != NULL);
10011
10012 /* print reason for infeasibility */
10013 if( printreason )
10014 {
10015 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10016 SCIPinfoMessage(scip, NULL, ";\n");
10017
10018 if( consdata->lhsviol > SCIPfeastol(scip) )
10019 {
10020 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10021 }
10022 if( consdata->rhsviol > SCIPfeastol(scip) )
10023 {
10024 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10025 }
10026 }
10027 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10028 {
10029 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10030 return SCIP_OKAY;
10031 }
10032
10033 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10034 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10035 maypropfeasible = FALSE;
10036
10037 if( maypropfeasible )
10038 {
10039 if( consdata->lhsviol > SCIPfeastol(scip) )
10040 {
10041 /* check if there is a variable which may help to get the left hand side satisfied
10042 * if there is no such variable, then we cannot get feasible
10043 */
10044 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10045 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10046 maypropfeasible = FALSE;
10047 }
10048 else
10049 {
10050 assert(consdata->rhsviol > SCIPfeastol(scip));
10051 /* check if there is a variable which may help to get the right hand side satisfied
10052 * if there is no such variable, then we cannot get feasible
10053 */
10054 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10055 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10056 maypropfeasible = FALSE;
10057 }
10058 }
10059 }
10060 }
10061
10062 if( *result == SCIP_INFEASIBLE && maypropfeasible )
10063 {
10064 SCIP_Bool success;
10065
10066 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10067
10068 /* do not pass solution to NLP heuristic if we made it feasible this way */
10069 if( success )
10070 return SCIP_OKAY;
10071 }
10072
10073 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10074 {
10075 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10076 }
10077
10078 return SCIP_OKAY;
10079 }
10080
10081
10082 /** domain propagation method of constraint handler */
10083 static
10084 SCIP_DECL_CONSPROP(consPropNonlinear)
10085 { /*lint --e{715}*/
10086 int nchgbds = 0;
10087
10088 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10089 assert(nchgbds >= 0);
10090
10091 /* TODO would it make sense to check for redundant constraints? */
10092
10093 return SCIP_OKAY;
10094 }
10095
10096
10097 /** presolving method of constraint handler */
10098 static
10099 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10100 { /*lint --e{715}*/
10101 SCIP_CONSHDLRDATA* conshdlrdata;
10102 SCIP_Bool infeasible;
10103 int c;
10104
10105 *result = SCIP_DIDNOTFIND;
10106
10107 if( nconss == 0 )
10108 {
10109 *result = SCIP_DIDNOTRUN;
10110 return SCIP_OKAY;
10111 }
10112
10113 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10114 assert(conshdlrdata != NULL);
10115
10116 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10117 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10118 if( infeasible )
10119 {
10120 *result = SCIP_CUTOFF;
10121 return SCIP_OKAY;
10122 }
10123
10124 /* merge constraints with the same root expression */
10125 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10126 {
10127 SCIP_Bool success;
10128
10129 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10130 if( success )
10131 *result = SCIP_SUCCESS;
10132 }
10133
10134 /* propagate constraints */
10135 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10136 if( *result == SCIP_CUTOFF )
10137 return SCIP_OKAY;
10138
10139 /* propagate function domains (TODO integrate with simplify?) */
10140 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10141 {
10142 SCIP_RESULT localresult;
10143 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10144 if( localresult == SCIP_CUTOFF )
10145 {
10146 *result = SCIP_CUTOFF;
10147 return SCIP_OKAY;
10148 }
10149 if( localresult == SCIP_REDUCEDDOM )
10150 *result = SCIP_REDUCEDDOM;
10151 }
10152
10153 /* check for redundant constraints, remove constraints that are a value expression */
10154 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10155 if( infeasible )
10156 {
10157 *result = SCIP_CUTOFF;
10158 return SCIP_OKAY;
10159 }
10160
10161 /* try to upgrade constraints */
10162 for( c = 0; c < nconss; ++c )
10163 {
10164 SCIP_Bool upgraded;
10165
10166 /* skip inactive and deleted constraints */
10167 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10168 continue;
10169
10170 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10171 }
10172
10173 /* try to change continuous variables that appear linearly to be implicit integer */
10174 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10175 {
10176 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10177
10178 if( infeasible )
10179 {
10180 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10181 *result = SCIP_CUTOFF;
10182 return SCIP_OKAY;
10183 }
10184 }
10185
10186 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10187 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10188 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10189 {
10190 /* run this presolving technique only once because we don't want to generate identical bound disjunction
10191 * constraints multiple times
10192 */
10193 conshdlrdata->checkedvarlocks = TRUE;
10194
10195 for( c = 0; c < nconss; ++c )
10196 {
10197 int tmpnchgvartypes = 0;
10198 int tmpnaddconss = 0;
10199
10200 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10201 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10202 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10203
10204 if( infeasible )
10205 {
10206 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10207 *result = SCIP_CUTOFF;
10208 return SCIP_OKAY;
10209 }
10210
10211 (*nchgvartypes) += tmpnchgvartypes;
10212 (*naddconss) += tmpnaddconss;
10213 }
10214 }
10215
10216 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10217 *result = SCIP_SUCCESS;
10218 else
10219 *result = SCIP_DIDNOTFIND;
10220
10221 return SCIP_OKAY;
10222 }
10223
10224
10225 /** propagation conflict resolving method of constraint handler */
10226 #ifdef SCIP_DISABLED_CODE
10227 static
10228 SCIP_DECL_CONSRESPROP(consRespropNonlinear)
10229 { /*lint --e{715}*/
10230 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10231 SCIPABORT(); /*lint --e{527}*/
10232
10233 return SCIP_OKAY;
10234 }
10235 #else
10236 #define consRespropNonlinear NULL
10237 #endif
10238
10239
10240 /** variable rounding lock method of constraint handler */
10241 static
10242 SCIP_DECL_CONSLOCK(consLockNonlinear)
10243 { /*lint --e{715}*/
10244 SCIP_CONSDATA* consdata;
10245 SCIP_EXPR_OWNERDATA* ownerdata;
10246 SCIP_Bool reinitsolve = FALSE;
10247
10248 assert(conshdlr != NULL);
10249 assert(cons != NULL);
10250
10251 consdata = SCIPconsGetData(cons);
10252 assert(consdata != NULL);
10253 assert(consdata->expr != NULL);
10254
10255 ownerdata = SCIPexprGetOwnerData(consdata->expr);
10256
10257 /* check whether we need to initSolve again because
10258 * - we have enfo initialized (nenfos >= 0)
10259 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10260 */
10261 if( ownerdata->nenfos >= 0 )
10262 {
10263 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10264 reinitsolve = TRUE;
10265 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10266 reinitsolve = TRUE;
10267 }
10268
10269 if( reinitsolve )
10270 {
10271 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10272 }
10273
10274 /* add locks */
10275 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10276
10277 if( reinitsolve )
10278 {
10279 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10280 }
10281
10282 return SCIP_OKAY;
10283 }
10284
10285
10286 /** constraint activation notification method of constraint handler */
10287 static
10288 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10289 { /*lint --e{715}*/
10290 SCIP_CONSDATA* consdata;
10291 SCIP_Bool infeasible = FALSE;
10292
10293 consdata = SCIPconsGetData(cons);
10294 assert(consdata != NULL);
10295
10296 /* simplify root expression if the constraint has been added after presolving */
10297 if( SCIPgetStage(scip) > SCIP_STAGE_EXITPRESOLVE )
10298 {
10299 SCIP_Bool replacedroot;
10300
10301 if( !consdata->issimplified )
10302 {
10303 SCIP_EXPR* simplified;
10304 SCIP_Bool changed;
10305
10306 /* simplify constraint */
10307 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10308 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10309 assert(simplified != NULL);
10310 consdata->expr = simplified;
10311 consdata->issimplified = TRUE;
10312 }
10313
10314 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10315 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10316 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10317
10318 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10319 {
10320 SCIP_CONSHDLRDATA* conshdlrdata;
10321 SCIP_EXPRITER* it;
10322 SCIP_EXPR* expr;
10323
10324 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10325 assert(conshdlrdata != NULL);
10326
10327 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10328 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10329 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
10330 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10331 {
10332 SCIP_EXPR* child;
10333 SCIP_EXPR* hashmapexpr;
10334
10335 child = SCIPexpriterGetChildExprDFS(it);
10336 if( !SCIPisExprVar(scip, child) )
10337 continue;
10338
10339 /* check which expression is stored in the hashmap for the var of child */
10340 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10341 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10342 if( hashmapexpr != NULL && hashmapexpr != child )
10343 {
10344 SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10345 }
10346 }
10347 SCIPfreeExpriter(&it);
10348 }
10349 }
10350
10351 /* store variable expressions */
10352 if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10353 {
10354 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10355 }
10356
10357 /* add manually locks to constraints that are not checked for feasibility */
10358 if( !SCIPconsIsChecked(cons) )
10359 {
10360 assert(consdata->nlockspos == 0);
10361 assert(consdata->nlocksneg == 0);
10362
10363 SCIP_CALL( addLocks(scip, cons, 1, 0) );
10364 }
10365
10366 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10367 {
10368 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10369 }
10370
10371 /* TODO deal with infeasibility */
10372 assert(!infeasible);
10373
10374 return SCIP_OKAY;
10375 }
10376
10377
10378 /** constraint deactivation notification method of constraint handler */
10379 static
10380 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10381 { /*lint --e{715}*/
10382 SCIP_CONSHDLRDATA* conshdlrdata;
10383
10384 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10385 assert(conshdlrdata != NULL);
10386
10387 if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10388 {
10389 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10390 }
10391
10392 if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10393 {
10394 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10395 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10396 }
10397
10398 /* remove locks that have been added in consActiveExpr() */
10399 if( !SCIPconsIsChecked(cons) )
10400 {
10401 SCIP_CALL( addLocks(scip, cons, -1, 0) );
10402
10403 assert(SCIPconsGetData(cons)->nlockspos == 0);
10404 assert(SCIPconsGetData(cons)->nlocksneg == 0);
10405 }
10406
10407 return SCIP_OKAY;
10408 }
10409
10410
10411 /** constraint enabling notification method of constraint handler */
10412 static
10413 SCIP_DECL_CONSENABLE(consEnableNonlinear)
10414 { /*lint --e{715}*/
10415 SCIP_CONSHDLRDATA* conshdlrdata;
10416
10417 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10418 assert(conshdlrdata != NULL);
10419
10420 if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10421 {
10422 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10423 }
10424
10425 return SCIP_OKAY;
10426 }
10427
10428
10429 /** constraint disabling notification method of constraint handler */
10430 static
10431 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10432 { /*lint --e{715}*/
10433 SCIP_CONSHDLRDATA* conshdlrdata;
10434
10435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10436 assert(conshdlrdata != NULL);
10437
10438 if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10439 {
10440 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10441 }
10442
10443 return SCIP_OKAY;
10444 }
10445
10446 /** variable deletion of constraint handler */
10447 #ifdef SCIP_DISABLED_CODE
10448 static
10449 SCIP_DECL_CONSDELVARS(consDelvarsNonlinear)
10450 { /*lint --e{715}*/
10451 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10452 SCIPABORT(); /*lint --e{527}*/
10453
10454 return SCIP_OKAY;
10455 }
10456 #else
10457 #define consDelvarsNonlinear NULL
10458 #endif
10459
10460
10461 /** constraint display method of constraint handler */
10462 static
10463 SCIP_DECL_CONSPRINT(consPrintNonlinear)
10464 { /*lint --e{715}*/
10465 SCIP_CONSDATA* consdata;
10466
10467 consdata = SCIPconsGetData(cons);
10468 assert(consdata != NULL);
10469 assert(consdata->expr != NULL);
10470
10471 /* print left hand side for ranged constraints */
10472 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10473 {
10474 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10475 }
10476
10477 /* print expression */
10478 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10479
10480 /* print right hand side */
10481 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10482 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10483 else if( !SCIPisInfinity(scip, consdata->rhs) )
10484 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10485 else if( !SCIPisInfinity(scip, -consdata->lhs) )
10486 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10487 else
10488 SCIPinfoMessage(scip, file, " [free]");
10489
10490 return SCIP_OKAY;
10491 }
10492
10493
10494 /** constraint copying method of constraint handler */
10495 static
10496 SCIP_DECL_CONSCOPY(consCopyNonlinear)
10497 { /*lint --e{715}*/
10498 SCIP_CONSHDLR* targetconshdlr;
10499 SCIP_EXPR* targetexpr = NULL;
10500 SCIP_CONSDATA* sourcedata;
10501
10502 assert(cons != NULL);
10503
10504 sourcedata = SCIPconsGetData(sourcecons);
10505 assert(sourcedata != NULL);
10506
10507 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10508 assert(targetconshdlr != NULL);
10509
10510 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10511
10512 if( targetexpr == NULL )
10513 *valid = FALSE;
10514
10515 *cons = NULL;
10516 if( *valid )
10517 {
10518 /* create copy (only capture targetexpr, no need to copy again) */
10519 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10520 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10521 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10522 }
10523
10524 if( targetexpr != NULL )
10525 {
10526 /* release target expr */
10527 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10528 }
10529
10530 return SCIP_OKAY;
10531 }
10532
10533
10534 /** constraint parsing method of constraint handler */
10535 static
10536 SCIP_DECL_CONSPARSE(consParseNonlinear)
10537 { /*lint --e{715}*/
10538 SCIP_Real lhs;
10539 SCIP_Real rhs;
10540 const char* endptr;
10541 SCIP_EXPR* consexprtree;
10542
10543 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10544
10545 assert(scip != NULL);
10546 assert(success != NULL);
10547 assert(str != NULL);
10548 assert(name != NULL);
10549 assert(cons != NULL);
10550
10551 *success = FALSE;
10552
10553 /* return if string empty */
10554 if( !*str )
10555 return SCIP_OKAY;
10556
10557 endptr = str;
10558
10559 /* set left and right hand side to their default values */
10560 lhs = -SCIPinfinity(scip);
10561 rhs = SCIPinfinity(scip);
10562
10563 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10564
10565 /* check for left hand side */
10566 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10567 {
10568 /* there is a number coming, maybe it is a left-hand-side */
10569 if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10570 {
10571 SCIPerrorMessage("error parsing number from <%s>\n", str);
10572 return SCIP_READERROR;
10573 }
10574
10575 /* ignore whitespace */
10576 while( isspace((unsigned char)*endptr) )
10577 ++endptr;
10578
10579 if( endptr[0] != '<' || endptr[1] != '=' )
10580 {
10581 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10582 lhs = -SCIPinfinity(scip);
10583 }
10584 else
10585 {
10586 /* it was indeed a left-hand-side, so continue parsing after it */
10587 str = endptr + 2;
10588
10589 /* ignore whitespace */
10590 while( isspace((unsigned char)*str) )
10591 ++str;
10592 }
10593 }
10594
10595 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10596
10597 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10598 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10599
10600 /* check for left or right hand side */
10601 while( isspace((unsigned char)*str) )
10602 ++str;
10603
10604 /* check for free constraint */
10605 if( strncmp(str, "[free]", 6) == 0 )
10606 {
10607 if( !SCIPisInfinity(scip, -lhs) )
10608 {
10609 SCIPerrorMessage("cannot have left hand side and [free] status \n");
10610 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10611 return SCIP_OKAY;
10612 }
10613 *success = TRUE;
10614 }
10615 else
10616 {
10617 switch( *str )
10618 {
10619 case '<':
10620 *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10621 break;
10622 case '=':
10623 if( !SCIPisInfinity(scip, -lhs) )
10624 {
10625 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10626 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10627 return SCIP_OKAY;
10628 }
10629 else
10630 {
10631 *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10632 lhs = rhs;
10633 }
10634 break;
10635 case '>':
10636 if( !SCIPisInfinity(scip, -lhs) )
10637 {
10638 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10639 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10640 return SCIP_OKAY;
10641 }
10642 else
10643 {
10644 *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10645 break;
10646 }
10647 case '\0':
10648 *success = TRUE;
10649 break;
10650 default:
10651 SCIPerrorMessage("unexpected character %c\n", *str);
10652 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10653 return SCIP_OKAY;
10654 }
10655 }
10656
10657 /* create constraint */
10658 SCIP_CALL( createCons(scip, conshdlr, cons, name,
10659 consexprtree, lhs, rhs, FALSE,
10660 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10661 assert(*cons != NULL);
10662
10663 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10664
10665 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10666
10667 return SCIP_OKAY;
10668 }
10669
10670
10671 /** constraint method of constraint handler which returns the variables (if possible) */
10672 static
10673 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10674 { /*lint --e{715}*/
10675 SCIP_CONSDATA* consdata;
10676 int i;
10677
10678 consdata = SCIPconsGetData(cons);
10679 assert(consdata != NULL);
10680
10681 /* store variable expressions if not done so far */
10682 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10683
10684 /* check whether array is too small in order to store all variables */
10685 if( varssize < consdata->nvarexprs )
10686 {
10687 *success = FALSE;
10688 return SCIP_OKAY;
10689 }
10690
10691 for( i = 0; i < consdata->nvarexprs; ++i )
10692 {
10693 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10694 assert(vars[i] != NULL);
10695 }
10696
10697 *success = TRUE;
10698
10699 return SCIP_OKAY;
10700 }
10701
10702 /** constraint method of constraint handler which returns the number of variables (if possible) */
10703 static
10704 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10705 { /*lint --e{715}*/
10706 SCIP_CONSDATA* consdata;
10707
10708 consdata = SCIPconsGetData(cons);
10709 assert(consdata != NULL);
10710
10711 /* store variable expressions if not done so far */
10712 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10713
10714 *nvars = consdata->nvarexprs;
10715 *success = TRUE;
10716
10717 return SCIP_OKAY;
10718 }
10719
10720 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10721 #ifdef SCIP_DISABLED_CODE
10722 static
10723 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsNonlinear)
10724 { /*lint --e{715}*/
10725 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10726 SCIPABORT(); /*lint --e{527}*/
10727
10728 return SCIP_OKAY;
10729 }
10730 #else
10731 #define consGetDiveBdChgsNonlinear NULL
10732 #endif
10733
10734 /** output method of statistics table to output file stream 'file' */
10735 static
10736 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10737 { /*lint --e{715}*/
10738 SCIP_CONSHDLR* conshdlr;
10739 SCIP_CONSHDLRDATA* conshdlrdata;
10740
10741 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10742 assert(conshdlr != NULL);
10743
10744 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10745 assert(conshdlrdata != NULL);
10746
10747 /* print statistics for constraint handler */
10748 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10749 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10750 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10751 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10752 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10753 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10754 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10755 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10756 SCIPinfoMessage(scip, file, "\n");
10757 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10758 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10759 SCIPinfoMessage(scip, file, "\n");
10760
10761 return SCIP_OKAY;
10762 }
10763
10764 /** output method of statistics table to output file stream 'file' */
10765 static
10766 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10767 { /*lint --e{715}*/
10768 SCIP_CONSHDLR* conshdlr;
10769 SCIP_CONSHDLRDATA* conshdlrdata;
10770
10771 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10772 assert(conshdlr != NULL);
10773
10774 /* skip nlhdlr table if there never were active nonlinear constraints */
10775 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10776 return SCIP_OKAY;
10777
10778 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10779 assert(conshdlrdata != NULL);
10780
10781 /* print statistics for nonlinear handlers */
10782 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10783
10784 return SCIP_OKAY;
10785 }
10786
10787 /** execution method of display nlhdlrs dialog */
10788 static
10789 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10790 { /*lint --e{715}*/
10791 SCIP_CONSHDLR* conshdlr;
10792 SCIP_CONSHDLRDATA* conshdlrdata;
10793 int i;
10794
10795 /* add dialog to history of dialogs that have been executed */
10796 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10797
10798 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10799 assert(conshdlr != NULL);
10800
10801 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10802 assert(conshdlrdata != NULL);
10803
10804 /* display list of nonlinear handler */
10805 SCIPdialogMessage(scip, NULL, "\n");
10806 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10807 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10808 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10809 {
10810 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10811 assert(nlhdlr != NULL);
10812
10813 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10814 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10815 SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10816 SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10817 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10818 SCIPdialogMessage(scip, NULL, "\n");
10819 }
10820 SCIPdialogMessage(scip, NULL, "\n");
10821
10822 /* next dialog will be root dialog again */
10823 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10824
10825 return SCIP_OKAY;
10826 }
10827
10828 /*
10829 * constraint handler specific interface methods
10830 */
10831
10832 /** creates the handler for nonlinear constraints and includes it in SCIP */
10833 SCIP_RETCODE SCIPincludeConshdlrNonlinear(
10834 SCIP* scip /**< SCIP data structure */
10835 )
10836 {
10837 SCIP_CONSHDLRDATA* conshdlrdata;
10838 SCIP_DIALOG* parentdialog;
10839
10840 /* create nonlinear constraint handler data */
10841 SCIP_CALL( SCIPallocClearMemory(scip, &conshdlrdata) );
10842 conshdlrdata->intevalvar = intEvalVarBoundTightening;
10843 conshdlrdata->curboundstag = 1;
10844 conshdlrdata->lastboundrelax = 1;
10845 conshdlrdata->curpropboundstag = 1;
10846 conshdlrdata->newsoleventfilterpos = -1;
10847 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10848 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10849 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10850
10851 /* include constraint handler */
10852 SCIP_CALL( SCIPincludeConshdlr(scip, CONSHDLR_NAME, CONSHDLR_DESC,
10853 CONSHDLR_SEPAPRIORITY, CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY,
10854 CONSHDLR_SEPAFREQ, CONSHDLR_PROPFREQ, CONSHDLR_EAGERFREQ, CONSHDLR_MAXPREROUNDS,
10855 CONSHDLR_DELAYSEPA, CONSHDLR_DELAYPROP, CONSHDLR_NEEDSCONS,
10856 CONSHDLR_PROP_TIMING, CONSHDLR_PRESOLTIMING,
10857 conshdlrCopyNonlinear,
10858 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10859 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10860 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10861 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10862 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10863 consActiveNonlinear, consDeactiveNonlinear,
10864 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10865 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10866 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10867
10868 /* add nonlinear constraint handler parameters */
10869 /* TODO organize into more subcategories */
10870 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10871 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10872 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10873
10874 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10875 "whether to check bounds of all auxiliary variable to seed reverse propagation",
10876 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10877
10878 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10879 "strategy on how to relax variable bounds during bound tightening: relax (n)ot, relax by (a)bsolute value, relax always by a(b)solute value, relax by (r)relative value",
10880 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10881
10882 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10883 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10884 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10885
10886 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10887 "by how much to relax constraint sides during bound tightening",
10888 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10889
10890 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10891 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10892 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10893
10894 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10895 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10896 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10897
10898 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10899 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10900 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10901
10902 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10903 "maximal number of auxiliary expressions per bilinear term",
10904 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10905
10906 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10907 "whether to reformulate products of binary variables during presolving",
10908 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10909
10910 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10911 "whether to use the AND constraint handler for reformulating binary products",
10912 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10913
10914 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10915 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10916 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10917
10918 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10919 "whether to forbid multiaggregation of nonlinear variables",
10920 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10921
10922 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10923 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10924 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10925
10926 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10927 "whether to (re)run propagation in enforcement",
10928 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10929
10930 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10931 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10932 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10933
10934 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10935 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10936 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10937
10938 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10939 "consider efficacy requirement when deciding whether a cut is \"strong\"",
10940 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10941
10942 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10943 "whether to force \"strong\" cuts in enforcement",
10944 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10945
10946 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10947 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10948 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10949
10950 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10951 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10952 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10953
10954 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10955 "whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways",
10956 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10957
10958 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10959 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10960 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10961
10962 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10963 "whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction)",
10964 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10965
10966 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10967 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10968 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10969
10970 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10971 "whether to use external branching candidates and branching rules for branching",
10972 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10973
10974 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10975 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10976 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10977
10978 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10979 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10980 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10981
10982 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10983 "weight by how much to consider the violation assigned to a variable for its branching score",
10984 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10985
10986 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
10987 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
10988 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10989
10990 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
10991 "weight by how much to consider the pseudo cost of a variable for its branching score",
10992 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10993
10994 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
10995 "weight by how much to consider the domain width in branching score",
10996 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10997
10998 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
10999 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11000 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11001
11002 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11003 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11004 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11005
11006 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11007 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11008 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11009
11010 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11011 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11012 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11013
11014 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11015 "whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution)",
11016 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11017
11018 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11019 "whether to assume that any constraint is convex",
11020 &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11021
11022 /* include handler for bound change events */
11023 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11024 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11025 assert(conshdlrdata->eventhdlr != NULL);
11026
11027 /* include tables for statistics */
11028 assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11029 SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NONLINEAR, TABLE_DESC_NONLINEAR, FALSE,
11030 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11031 NULL, TABLE_POSITION_NONLINEAR, TABLE_EARLIEST_STAGE_NONLINEAR) );
11032
11033 assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11034 SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NLHDLR, TABLE_DESC_NLHDLR, TRUE,
11035 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11036 NULL, TABLE_POSITION_NLHDLR, TABLE_EARLIEST_STAGE_NLHDLR) );
11037
11038 /* create, include, and release display nlhdlrs dialog */
11039 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11040 {
11041 SCIP_DIALOG* dialog;
11042
11043 assert(parentdialog != NULL);
11044 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11045
11046 SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11047 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11048 DIALOG_NAME, DIALOG_DESC, DIALOG_ISSUBMENU, NULL) );
11049 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11050 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11051 }
11052
11053 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11054 processNewSolutionEvent, NULL) );
11055
11056 return SCIP_OKAY;
11057 }
11058
11059 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11060 SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(
11061 SCIP* scip, /**< SCIP data structure */
11062 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11063 int priority, /**< priority of upgrading method */
11064 SCIP_Bool active, /**< should the upgrading method by active by default? */
11065 const char* conshdlrname /**< name of the constraint handler */
11066 )
11067 {
11068 SCIP_CONSHDLR* conshdlr;
11069 SCIP_CONSHDLRDATA* conshdlrdata;
11070 CONSUPGRADE* consupgrade;
11071 char paramname[SCIP_MAXSTRLEN];
11072 char paramdesc[SCIP_MAXSTRLEN];
11073 int i;
11074
11075 assert(conshdlrname != NULL );
11076 assert(nlconsupgd != NULL);
11077
11078 /* find the nonlinear constraint handler */
11079 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11080 if( conshdlr == NULL )
11081 {
11082 SCIPerrorMessage("nonlinear constraint handler not found\n");
11083 return SCIP_PLUGINNOTFOUND;
11084 }
11085
11086 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11087 assert(conshdlrdata != NULL);
11088
11089 /* check whether upgrade method exists already */
11090 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11091 {
11092 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11093 {
11094 #ifdef SCIP_DEBUG
11095 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11096 #endif
11097 return SCIP_OKAY;
11098 }
11099 }
11100
11101 /* create a nonlinear constraint upgrade data object */
11102 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11103 consupgrade->consupgd = nlconsupgd;
11104 consupgrade->priority = priority;
11105 consupgrade->active = active;
11106
11107 /* insert nonlinear constraint upgrade method into constraint handler data */
11108 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11109 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11110
11111 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11112 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11113 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11114 conshdlrdata->consupgrades[i] = consupgrade;
11115 conshdlrdata->nconsupgrades++;
11116
11117 /* adds parameter to turn on and off the upgrading step */
11118 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11119 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11120 SCIP_CALL( SCIPaddBoolParam(scip,
11121 paramname, paramdesc,
11122 &consupgrade->active, FALSE, active, NULL, NULL) );
11123
11124 return SCIP_OKAY;
11125 }
11126
11127 /** creates and captures a nonlinear constraint
11128 *
11129 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11130 */
11131 SCIP_RETCODE SCIPcreateConsNonlinear(
11132 SCIP* scip, /**< SCIP data structure */
11133 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11134 const char* name, /**< name of constraint */
11135 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11136 SCIP_Real lhs, /**< left hand side of constraint */
11137 SCIP_Real rhs, /**< right hand side of constraint */
11138 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11139 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11140 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11141 * Usually set to TRUE. */
11142 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11143 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11144 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11145 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11146 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11147 * Usually set to TRUE. */
11148 SCIP_Bool local, /**< is constraint only valid locally?
11149 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11150 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11151 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11152 * adds coefficients to this constraint. */
11153 SCIP_Bool dynamic, /**< is constraint subject to aging?
11154 * Usually set to FALSE. Set to TRUE for own cuts which
11155 * are separated as constraints. */
11156 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11157 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11158 )
11159 {
11160 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11161 SCIP_CONSHDLR* conshdlr;
11162
11163 /* find the nonlinear constraint handler */
11164 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11165 if( conshdlr == NULL )
11166 {
11167 SCIPerrorMessage("nonlinear constraint handler not found\n");
11168 return SCIP_PLUGINNOTFOUND;
11169 }
11170
11171 /* create constraint */
11172 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11173 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11174
11175 return SCIP_OKAY;
11176 }
11177
11178 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11179 *
11180 * All flags can be set via SCIPconsSetFLAGNAME-methods.
11181 *
11182 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11183 *
11184 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11185 */
11186 SCIP_RETCODE SCIPcreateConsBasicNonlinear(
11187 SCIP* scip, /**< SCIP data structure */
11188 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11189 const char* name, /**< name of constraint */
11190 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11191 SCIP_Real lhs, /**< left hand side of constraint */
11192 SCIP_Real rhs /**< right hand side of constraint */
11193 )
11194 {
11195 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11196 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11197
11198 return SCIP_OKAY;
11199 }
11200
11201 /** creates and captures a quadratic nonlinear constraint
11202 *
11203 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11204 */
11205 SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(
11206 SCIP* scip, /**< SCIP data structure */
11207 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11208 const char* name, /**< name of constraint */
11209 int nlinvars, /**< number of linear terms */
11210 SCIP_VAR** linvars, /**< array with variables in linear part */
11211 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11212 int nquadterms, /**< number of quadratic terms */
11213 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11214 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11215 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11216 SCIP_Real lhs, /**< left hand side of quadratic equation */
11217 SCIP_Real rhs, /**< right hand side of quadratic equation */
11218 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11219 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11220 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11221 * Usually set to TRUE. */
11222 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11223 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11224 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11225 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11226 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11227 * Usually set to TRUE. */
11228 SCIP_Bool local, /**< is constraint only valid locally?
11229 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11230 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11231 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11232 * adds coefficients to this constraint. */
11233 SCIP_Bool dynamic, /**< is constraint subject to aging?
11234 * Usually set to FALSE. Set to TRUE for own cuts which
11235 * are separated as constraints. */
11236 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11237 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11238 )
11239 {
11240 SCIP_CONSHDLR* conshdlr;
11241 SCIP_EXPR* expr;
11242
11243 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11244 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11245
11246 /* get nonlinear constraint handler */
11247 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11248 if( conshdlr == NULL )
11249 {
11250 SCIPerrorMessage("nonlinear constraint handler not found\n");
11251 return SCIP_PLUGINNOTFOUND;
11252 }
11253
11254 /* create quadratic expression */
11255 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11256 assert(expr != NULL);
11257
11258 /* create nonlinear constraint */
11259 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11260 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11261
11262 /* release quadratic expression (captured by constraint now) */
11263 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11264
11265 return SCIP_OKAY;
11266 }
11267
11268 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11269 *
11270 * All flags can be set via SCIPconsSetFLAGNAME-methods.
11271 *
11272 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11273 *
11274 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11275 */
11276 SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(
11277 SCIP* scip, /**< SCIP data structure */
11278 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11279 const char* name, /**< name of constraint */
11280 int nlinvars, /**< number of linear terms */
11281 SCIP_VAR** linvars, /**< array with variables in linear part */
11282 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11283 int nquadterms, /**< number of quadratic terms */
11284 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11285 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11286 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11287 SCIP_Real lhs, /**< left hand side of quadratic equation */
11288 SCIP_Real rhs /**< right hand side of quadratic equation */
11289 )
11290 {
11291 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11292 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11293
11294 return SCIP_OKAY;
11295 }
11296
11297 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11298 *
11299 * \f$\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1})\f$
11300 *
11301 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11302 */
11303 SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(
11304 SCIP* scip, /**< SCIP data structure */
11305 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11306 const char* name, /**< name of constraint */
11307 int nvars, /**< number of variables on left hand side of constraint (n) */
11308 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11309 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11310 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11311 SCIP_Real constant, /**< constant on left hand side (gamma) */
11312 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11313 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11314 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11315 )
11316 {
11317 SCIP_EXPR* expr;
11318 SCIP_EXPR* lhssum;
11319 SCIP_EXPR* terms[2];
11320 SCIP_Real termcoefs[2];
11321 int i;
11322
11323 assert(vars != NULL || nvars == 0);
11324
11325 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11326 for( i = 0; i < nvars; ++i )
11327 {
11328 SCIP_EXPR* varexpr;
11329 SCIP_EXPR* powexpr;
11330
11331 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11332 if( offsets != NULL && offsets[i] != 0.0 )
11333 {
11334 SCIP_EXPR* sum;
11335 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11336 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11337 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11338 }
11339 else
11340 {
11341 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11342 }
11343
11344 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11345 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11346 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11347 }
11348
11349 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11350 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11351 termcoefs[0] = 1.0;
11352
11353 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11354 termcoefs[1] = -rhscoeff;
11355
11356 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11357
11358 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11359 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11360
11361 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11362
11363 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11364
11365 return SCIP_OKAY;
11366 }
11367
11368 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11369 *
11370 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11371 *
11372 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11373 */
11374 SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(
11375 SCIP* scip, /**< SCIP data structure */
11376 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11377 const char* name, /**< name of constraint */
11378 SCIP_VAR* x, /**< nonlinear variable x in constraint */
11379 SCIP_VAR* z, /**< linear variable z in constraint */
11380 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11381 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11382 SCIP_Real zcoef, /**< coefficient of z in constraint */
11383 SCIP_Real lhs, /**< left hand side of constraint */
11384 SCIP_Real rhs /**< right hand side of constraint */
11385 )
11386 {
11387 SCIP_EXPR* xexpr;
11388 SCIP_EXPR* terms[2];
11389 SCIP_Real coefs[2];
11390 SCIP_EXPR* sumexpr;
11391
11392 assert(x != NULL);
11393 assert(z != NULL);
11394
11395 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11396 if( xoffset != 0.0 )
11397 {
11398 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11399 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11400
11401 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11402 }
11403 else
11404 {
11405 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11406 }
11407 coefs[0] = 1.0;
11408
11409 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11410 coefs[1] = zcoef;
11411
11412 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11413
11414 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11415
11416 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11417 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11418 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11419 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11420
11421 return SCIP_OKAY;
11422 }
11423
11424 /** gets tag indicating current local variable bounds */
11425 SCIP_Longint SCIPgetCurBoundsTagNonlinear(
11426 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11427 )
11428 {
11429 SCIP_CONSHDLRDATA* conshdlrdata;
11430
11431 assert(conshdlr != NULL);
11432 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11433
11434 return conshdlrdata->curboundstag;
11435 }
11436
11437 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
11438 SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(
11439 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11440 )
11441 {
11442 SCIP_CONSHDLRDATA* conshdlrdata;
11443
11444 assert(conshdlr != NULL);
11445 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11446
11447 return conshdlrdata->lastboundrelax;
11448 }
11449
11450 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11451 *
11452 * @attention This method is not intended for normal use.
11453 * These tags are maintained by the event handler for variable bound change events.
11454 * This method is used by some unittests.
11455 */
11456 void SCIPincrementCurBoundsTagNonlinear(
11457 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11458 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11459 )
11460 {
11461 SCIP_CONSHDLRDATA* conshdlrdata;
11462
11463 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11464 assert(conshdlrdata != NULL);
11465
11466 ++conshdlrdata->curboundstag;
11467 assert(conshdlrdata->curboundstag > 0);
11468
11469 if( boundrelax )
11470 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11471 }
11472
11473 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11474 SCIP_HASHMAP* SCIPgetVarExprHashmapNonlinear(
11475 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11476 )
11477 {
11478 assert(conshdlr != NULL);
11479
11480 return SCIPconshdlrGetData(conshdlr)->var2expr;
11481 }
11482
11483 /** processes a rowprep for cut addition and maybe report branchscores */
11484 SCIP_RETCODE SCIPprocessRowprepNonlinear(
11485 SCIP* scip, /**< SCIP data structure */
11486 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11487 SCIP_CONS* cons, /**< nonlinear constraint */
11488 SCIP_EXPR* expr, /**< expression */
11489 SCIP_ROWPREP* rowprep, /**< cut to be added */
11490 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11491 SCIP_VAR* auxvar, /**< auxiliary variable */
11492 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11493 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11494 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11495 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11496 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11497 SCIP_RESULT* result /**< pointer to store the result */
11498 )
11499 {
11500 SCIP_Real cutviol;
11501 SCIP_CONSHDLRDATA* conshdlrdata;
11502 SCIP_Real auxvarvalue = SCIP_INVALID;
11503 SCIP_Bool sepasuccess;
11504 SCIP_Real estimateval = SCIP_INVALID;
11505 SCIP_Real mincutviolation;
11506
11507 assert(nlhdlr != NULL);
11508 assert(cons != NULL);
11509 assert(expr != NULL);
11510 assert(rowprep != NULL);
11511 assert(auxvar != NULL);
11512 assert(result != NULL);
11513
11514 /* decide on minimal violation of cut */
11515 if( sol == NULL )
11516 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11517 else
11518 mincutviolation = SCIPfeastol(scip);
11519
11520 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11521 assert(conshdlrdata != NULL);
11522
11523 sepasuccess = TRUE;
11524
11525 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11526 if( cutviol > 0.0 )
11527 {
11528 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11529
11530 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11531 if( !allowweakcuts && auxvalue != SCIP_INVALID )
11532 {
11533 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11534 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11535 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11536 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11537 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11538 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11539 *
11540 * if we are overestimating, we have z >= c'x-b >= f(x)
11541 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11542 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11543 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11544 *
11545 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11546 */
11547 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11548 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11549 {
11550 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11551 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11552 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11553 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11554 sepasuccess = FALSE;
11555 }
11556 }
11557
11558 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11559 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11560 }
11561 else
11562 {
11563 sepasuccess = FALSE;
11564 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11565 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11566 }
11567
11568 /* clean up estimator */
11569 if( sepasuccess )
11570 {
11571 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11572 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11573 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11574 SCIPprintRowprep(scip, rowprep, enfologfile); )
11575
11576 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11577 * instead, may even scale them down, that is, scale so that max coef is close to 1
11578 */
11579 if( !allowweakcuts )
11580 {
11581 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11582
11583 if( !sepasuccess )
11584 {
11585 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11586 }
11587 else
11588 {
11589 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11590 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11591 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11592 if( sepasuccess )
11593 sepasuccess = cutviol > mincutviolation;
11594 }
11595
11596 if( sepasuccess && auxvalue != SCIP_INVALID )
11597 {
11598 /* check whether cut is weak now
11599 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11600 * reconstructing estimateval from cutviol (TODO improve or remove?)
11601 */
11602 SCIP_Real auxvarcoef = 0.0;
11603 int i;
11604
11605 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11606 * it should be...
11607 */
11608 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11609 {
11610 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11611 {
11612 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11613 break;
11614 }
11615 }
11616
11617 if( auxvarcoef == 0.0 ||
11618 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11619 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11620 {
11621 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11622 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11623 sepasuccess = FALSE;
11624 }
11625 }
11626 }
11627 else
11628 {
11629 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11630
11631 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11632 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11633 */
11634 if( !branchscoresuccess )
11635 SCIProwprepRecordModifications(rowprep);
11636
11637 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11638
11639 if( !sepasuccess )
11640 {
11641 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11642 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11643 }
11644
11645 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11646 * changed
11647 */
11648 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11649 {
11650 SCIP_Real violscore;
11651
11652 #ifdef BRSCORE_ABSVIOL
11653 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11654 #else
11655 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11656 #endif
11657 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11658
11659 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11660 * - were fixed,
11661 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11662 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11663 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11664 * so I'm disabling the assert for now
11665 */
11666 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11667 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11668 }
11669 }
11670 }
11671
11672 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11673 if( sepasuccess )
11674 {
11675 SCIP_ROW* row;
11676
11677 if( conshdlrdata->branchdualweight > 0.0 )
11678 {
11679 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11680 * skip if gap is zero
11681 */
11682 if( auxvalue == SCIP_INVALID )
11683 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11684 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11685 {
11686 char gap[40];
11687 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
11688 strcat(SCIProwprepGetName(rowprep), gap);
11689 }
11690 }
11691
11692 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11693
11694 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11695 {
11696 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11697 SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11698 }
11699 else if( !SCIPisCutApplicable(scip, row) )
11700 {
11701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11702 }
11703 else
11704 {
11705 SCIP_Bool infeasible;
11706
11707 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11708 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11709
11710 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11711 * if we haven't found strong cuts before)
11712 */
11713 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11714
11715 /* mark row as not removable from LP for current node (this can prevent some cycling) */
11716 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11717 SCIPmarkRowNotRemovableLocal(scip, row);
11718
11719 if( infeasible )
11720 {
11721 *result = SCIP_CUTOFF;
11722 SCIPnlhdlrIncrementNCutoffs(nlhdlr);
11723 }
11724 else
11725 {
11726 *result = SCIP_SEPARATED;
11727 SCIPnlhdlrIncrementNSeparated(nlhdlr);
11728 }
11729 }
11730
11731 SCIP_CALL( SCIPreleaseRow(scip, &row) );
11732 }
11733 else if( branchscoresuccess )
11734 {
11735 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11736 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11737
11738 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11739 * expressions eligible for branching candidate, see enforceConstraints() and branching()
11740 */
11741 *result = SCIP_BRANCHED;
11742 }
11743 else
11744 {
11745 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11746 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11747 " (!)" : ""); )
11748 }
11749
11750 return SCIP_OKAY;
11751 }
11752
11753 /** returns whether all nonlinear constraints are assumed to be convex */
11754 SCIP_Bool SCIPassumeConvexNonlinear(
11755 SCIP_CONSHDLR* conshdlr
11756 )
11757 {
11758 SCIP_CONSHDLRDATA* conshdlrdata;
11759
11760 assert(conshdlr != NULL);
11761
11762 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11763 assert(conshdlrdata != NULL);
11764
11765 return conshdlrdata->assumeconvex;
11766 }
11767
11768 /** collects all bilinear terms for a given set of constraints
11769 *
11770 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11771 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11772 */
11773 SCIP_RETCODE SCIPcollectBilinTermsNonlinear(
11774 SCIP* scip, /**< SCIP data structure */
11775 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11776 SCIP_CONS** conss, /**< nonlinear constraints */
11777 int nconss /**< total number of nonlinear constraints */
11778 )
11779 {
11780 assert(conshdlr != NULL);
11781 assert(conss != NULL || nconss == 0);
11782
11783 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11784
11785 return SCIP_OKAY;
11786 }
11787
11788 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
11789 *
11790 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11791 */
11792 int SCIPgetNBilinTermsNonlinear(
11793 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11794 )
11795 {
11796 SCIP_CONSHDLRDATA* conshdlrdata;
11797
11798 assert(conshdlr != NULL);
11799
11800 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11801 assert(conshdlrdata != NULL);
11802
11803 return conshdlrdata->nbilinterms;
11804 }
11805
11806 /** returns all bilinear terms that are contained in all nonlinear constraints
11807 *
11808 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11809 * @note The value of the auxiliary variable of a bilinear term might be NULL, which indicates that the term does not have an auxiliary variable.
11810 */
11811 SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermsNonlinear(
11812 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11813 )
11814 {
11815 SCIP_CONSHDLRDATA* conshdlrdata;
11816
11817 assert(conshdlr != NULL);
11818
11819 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11820 assert(conshdlrdata != NULL);
11821
11822 return conshdlrdata->bilinterms;
11823 }
11824
11825 /** returns the index of the bilinear term representing the product of the two given variables
11826 *
11827 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11828 * @return The method returns -1 if the variables do not appear bilinearly.
11829 */
11830 int SCIPgetBilinTermIdxNonlinear(
11831 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11832 SCIP_VAR* x, /**< first variable */
11833 SCIP_VAR* y /**< second variable */
11834 )
11835 {
11836 SCIP_CONSHDLRDATA* conshdlrdata;
11837 SCIP_CONSNONLINEAR_BILINTERM entry;
11838 int idx;
11839
11840 assert(conshdlr != NULL);
11841 assert(x != NULL);
11842 assert(y != NULL);
11843
11844 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11845 assert(conshdlrdata != NULL);
11846
11847 if( conshdlrdata->bilinhashtable == NULL )
11848 {
11849 return -1;
11850 }
11851
11852 /* ensure that x.index <= y.index */
11853 if( SCIPvarCompare(x, y) == 1 )
11854 {
11855 SCIPswapPointers((void**)&x, (void**)&y);
11856 }
11857 assert(SCIPvarCompare(x, y) < 1);
11858
11859 /* use a new entry to find the image in the bilinear hash table */
11860 entry.x = x;
11861 entry.y = y;
11862 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11863 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11864 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11865 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11866
11867 return idx;
11868 }
11869
11870 /** returns the bilinear term that represents the product of two given variables
11871 *
11872 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11873 * @return The method returns NULL if the variables do not appear bilinearly.
11874 */
11875 SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermNonlinear(
11876 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11877 SCIP_VAR* x, /**< first variable */
11878 SCIP_VAR* y /**< second variable */
11879 )
11880 {
11881 SCIP_CONSHDLRDATA* conshdlrdata;
11882 int idx;
11883
11884 assert(conshdlr != NULL);
11885 assert(x != NULL);
11886 assert(y != NULL);
11887
11888 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11889 assert(conshdlrdata != NULL);
11890
11891 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11892 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11893
11894 if( idx >= 0 )
11895 {
11896 return &conshdlrdata->bilinterms[idx];
11897 }
11898
11899 return NULL;
11900 }
11901
11902 /** evaluates an auxiliary expression for a bilinear term */
11903 SCIP_Real SCIPevalBilinAuxExprNonlinear(
11904 SCIP* scip, /**< SCIP data structure */
11905 SCIP_VAR* x, /**< first variable of the bilinear term */
11906 SCIP_VAR* y, /**< second variable of the bilinear term */
11907 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11908 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11909 )
11910 {
11911 assert(scip != NULL);
11912 assert(x != NULL);
11913 assert(y != NULL);
11914 assert(auxexpr != NULL);
11915 assert(auxexpr->auxvar != NULL);
11916
11917 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11918 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11919 }
11920
11921 /** stores the variables of a bilinear term in the data of the constraint handler */
11922 SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(
11923 SCIP* scip, /**< SCIP data structure */
11924 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11925 SCIP_VAR* x, /**< first variable */
11926 SCIP_VAR* y, /**< second variable */
11927 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11928 int nlockspos, /**< number of positive expression locks */
11929 int nlocksneg /**< number of negative expression locks */
11930 )
11931 {
11932 SCIP_CONSHDLRDATA* conshdlrdata;
11933 SCIP_CONSNONLINEAR_BILINTERM* term;
11934 int idx;
11935
11936 assert(conshdlr != NULL);
11937
11938 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11939 assert(conshdlrdata != NULL);
11940
11941 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11942
11943 term = &conshdlrdata->bilinterms[idx];
11944 assert(term != NULL);
11945 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11946 assert(term->aux.var == NULL); /* there should not already be an auxvar, that is, existing terms should exist only once (common subexprs should have been eliminated) */
11947
11948 /* store and capture auxiliary variable */
11949 if( auxvar != NULL )
11950 {
11951 term->aux.var = auxvar;
11952 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11953 }
11954
11955 return SCIP_OKAY;
11956 }
11957
11958 /** stores the variables of a bilinear term in the data of the constraint handler */
11959 SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(
11960 SCIP* scip, /**< SCIP data structure */
11961 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11962 SCIP_VAR* x, /**< first variable */
11963 SCIP_VAR* y, /**< second variable */
11964 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11965 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11966 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11967 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11968 SCIP_Real cst, /**< constant of the auxiliary expression */
11969 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11970 )
11971 {
11972 SCIP_CONSHDLRDATA* conshdlrdata;
11973 SCIP_CONSNONLINEAR_BILINTERM* term;
11974 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11975 int idx;
11976 int nlockspos;
11977 int nlocksneg;
11978 SCIP_Bool added;
11979
11980 assert(conshdlr != NULL);
11981
11982 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11983 assert(conshdlrdata != NULL);
11984
11985 nlockspos = overestimate ? 1 : 0;
11986 nlocksneg = overestimate ? 0 : 1;
11987
11988 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
11989
11990 term = &conshdlrdata->bilinterms[idx];
11991 assert(term != NULL);
11992 assert(SCIPvarCompare(term->x, term->y) < 1);
11993
11994 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
11995 {
11996 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
11997 /* this is the case where we are adding an implicitly defined relation for a product that has already
11998 * been explicitly defined; convert auxvar into an auxexpr */
11999
12000 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12001 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12002 return SCIP_OKAY;
12003
12004 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12005 auxvarexpr->cst = 0.0;
12006 auxvarexpr->coefs[0] = 1.0;
12007 auxvarexpr->coefs[1] = 0.0;
12008 auxvarexpr->coefs[2] = 0.0;
12009 auxvarexpr->auxvar = term->aux.var;
12010 auxvarexpr->underestimate = term->nlocksneg > 0;
12011 auxvarexpr->overestimate = term->nlockspos > 0;
12012
12013 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12014 term->aux.exprs = NULL;
12015
12016 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12017
12018 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12019 assert(added);
12020 }
12021
12022 /* create and add auxexpr */
12023 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12024 auxexpr->underestimate = !overestimate;
12025 auxexpr->overestimate = overestimate;
12026 auxexpr->auxvar = auxvar;
12027 auxexpr->coefs[0] = coefaux;
12028 if( term->x == x )
12029 {
12030 assert(term->y == y);
12031 auxexpr->coefs[1] = coefx;
12032 auxexpr->coefs[2] = coefy;
12033 }
12034 else
12035 {
12036 assert(term->x == y);
12037 assert(term->y == x);
12038 auxexpr->coefs[1] = coefy;
12039 auxexpr->coefs[2] = coefx;
12040 }
12041 auxexpr->cst = cst;
12042 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12043
12044 if( !added )
12045 {
12046 SCIPfreeBlockMemory(scip, &auxexpr);
12047 }
12048 else if( auxvar != NULL )
12049 { /* capture auxiliary variable */
12050 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12051 }
12052
12053 return SCIP_OKAY;
12054 }
12055
12056 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12057 SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(
12058 SCIP* scip, /**< SCIP data structure */
12059 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12060 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12061 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12062 void* fundata, /**< data for function evaluation (can be NULL) */
12063 SCIP_Real* xstar, /**< point to be separated */
12064 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12065 int nallvars, /**< half of the length of box */
12066 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12067 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12068 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12069 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12070 )
12071 {
12072 SCIP_Real* corner;
12073 SCIP_Real* funvals;
12074 int* nonfixedpos;
12075 SCIP_Real maxfaceterror;
12076 int nvars; /* number of nonfixed variables */
12077 unsigned int ncorners;
12078 unsigned int i;
12079 int j;
12080
12081 assert(scip != NULL);
12082 assert(conshdlr != NULL);
12083 assert(function != NULL);
12084 assert(xstar != NULL);
12085 assert(box != NULL);
12086 assert(success != NULL);
12087 assert(facetcoefs != NULL);
12088 assert(facetconstant != NULL);
12089
12090 *success = FALSE;
12091
12092 /* identify fixed variables */
12093 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12094 nvars = 0;
12095 for( j = 0; j < nallvars; ++j )
12096 {
12097 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12098 continue;
12099 nonfixedpos[nvars] = j;
12100 nvars++;
12101 }
12102
12103 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12104 * if too many variables are not fixed, then we do nothing currently
12105 */
12106 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12107 {
12108 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12109 SCIPfreeBufferArray(scip, &nonfixedpos);
12110 return SCIP_OKAY;
12111 }
12112
12113 /* compute f(v^i) for each corner v^i of [l,u] */
12114 ncorners = POWEROFTWO(nvars);
12115 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12116 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12117 for( j = 0; j < nallvars; ++j )
12118 {
12119 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12120 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12121 }
12122 for( i = 0; i < ncorners; ++i )
12123 {
12124 SCIPdebugMsg(scip, "corner %u: ", i);
12125 for( j = 0; j < nvars; ++j )
12126 {
12127 int varpos = nonfixedpos[j];
12128 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12129 * we check this by shifting i for j positions to the right and checking whether the last bit is set
12130 */
12131 if( (i >> j) & 0x1 )
12132 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12133 else
12134 corner[varpos] = box[2 * varpos ]; /* lb of var */
12135 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12136 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12137 }
12138
12139 funvals[i] = function(corner, nallvars, fundata);
12140
12141 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12142
12143 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12144 {
12145 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12146 goto CLEANUP;
12147 }
12148 }
12149
12150 /* clear coefs array; below we only fill in coefs for nonfixed variables */
12151 BMSclearMemoryArray(facetcoefs, nallvars);
12152
12153 if( nvars == 1 )
12154 {
12155 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12156
12157 /* check whether target has been missed */
12158 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12159 {
12160 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12161 *success = FALSE;
12162 }
12163 }
12164 else if( nvars == 2 )
12165 {
12166 int idx1 = nonfixedpos[0];
12167 int idx2 = nonfixedpos[1];
12168 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12169 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12170 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12171 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12172 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12173 SCIP_Real coefs[2] = { 0.0, 0.0 };
12174
12175 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12176
12177 facetcoefs[idx1] = coefs[0];
12178 facetcoefs[idx2] = coefs[1];
12179 }
12180 else
12181 {
12182 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12183 }
12184 if( !*success )
12185 {
12186 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12187 goto CLEANUP;
12188 }
12189
12190 /*
12191 * check and adjust facet with the algorithm of Rikun et al.
12192 */
12193
12194 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12195
12196 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12197 if( maxfaceterror > 0.0 )
12198 {
12199 SCIP_CONSHDLRDATA* conshdlrdata;
12200 SCIP_Real midval;
12201 SCIP_Real feastol;
12202
12203 feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12204
12205 /* evaluate function in middle point to get some idea for a scaling */
12206 for( j = 0; j < nvars; ++j )
12207 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12208 midval = function(corner, nallvars, fundata);
12209 if( midval == SCIP_INVALID )
12210 midval = 1.0;
12211
12212 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12213 assert(conshdlrdata != NULL);
12214
12215 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12216 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12217 {
12218 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12219 *success = FALSE;
12220 goto CLEANUP;
12221 }
12222
12223 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12224
12225 if( overestimate )
12226 *facetconstant += maxfaceterror;
12227 else
12228 *facetconstant -= maxfaceterror;
12229 }
12230
12231 /* if we made it until here, then we have a nice facet */
12232 assert(*success);
12233
12234 CLEANUP:
12235 /* free allocated memory */
12236 SCIPfreeBufferArray(scip, &corner);
12237 SCIPfreeBufferArray(scip, &funvals);
12238 SCIPfreeBufferArray(scip, &nonfixedpos);
12239
12240 return SCIP_OKAY;
12241 }
12242
12243 /*
12244 * constraint specific interface methods
12245 */
12246
12247 /** returns the expression of the given nonlinear constraint */
12248 SCIP_EXPR* SCIPgetExprNonlinear(
12249 SCIP_CONS* cons /**< constraint data */
12250 )
12251 {
12252 SCIP_CONSDATA* consdata;
12253
12254 assert(cons != NULL);
12255 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12256
12257 consdata = SCIPconsGetData(cons);
12258 assert(consdata != NULL);
12259
12260 return consdata->expr;
12261 }
12262
12263 /** gets the left hand side of a nonlinear constraint */
12264 SCIP_Real SCIPgetLhsNonlinear(
12265 SCIP_CONS* cons /**< constraint data */
12266 )
12267 {
12268 SCIP_CONSDATA* consdata;
12269
12270 assert(cons != NULL);
12271 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12272
12273 consdata = SCIPconsGetData(cons);
12274 assert(consdata != NULL);
12275
12276 return consdata->lhs;
12277 }
12278
12279 /** gets the right hand side of a nonlinear constraint */
12280 SCIP_Real SCIPgetRhsNonlinear(
12281 SCIP_CONS* cons /**< constraint data */
12282 )
12283 {
12284 SCIP_CONSDATA* consdata;
12285
12286 assert(cons != NULL);
12287 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12288
12289 consdata = SCIPconsGetData(cons);
12290 assert(consdata != NULL);
12291
12292 return consdata->rhs;
12293 }
12294
12295 /** gets the nonlinear constraint as a nonlinear row representation. */
12296 SCIP_RETCODE SCIPgetNlRowNonlinear(
12297 SCIP* scip, /**< SCIP data structure */
12298 SCIP_CONS* cons, /**< constraint */
12299 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12300 )
12301 {
12302 SCIP_CONSDATA* consdata;
12303
12304 assert(cons != NULL);
12305 assert(nlrow != NULL);
12306 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12307
12308 consdata = SCIPconsGetData(cons);
12309 assert(consdata != NULL);
12310
12311 if( consdata->nlrow == NULL )
12312 {
12313 SCIP_CALL( createNlRow(scip, cons) );
12314 }
12315 assert(consdata->nlrow != NULL);
12316 *nlrow = consdata->nlrow;
12317
12318 return SCIP_OKAY;
12319 }
12320
12321 /** returns the curvature of the expression of a given nonlinear constraint
12322 *
12323 * @note The curvature information is computed during CONSINITSOL.
12324 */
12325 SCIP_EXPRCURV SCIPgetCurvatureNonlinear(
12326 SCIP_CONS* cons /**< constraint data */
12327 )
12328 {
12329 SCIP_CONSDATA* consdata;
12330
12331 assert(cons != NULL);
12332 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12333
12334 consdata = SCIPconsGetData(cons);
12335 assert(consdata != NULL);
12336
12337 return consdata->curv;
12338 }
12339
12340 /** checks whether expression of constraint can be represented as quadratic form
12341 *
12342 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12343 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12344 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12345 */
12346 SCIP_RETCODE SCIPcheckQuadraticNonlinear(
12347 SCIP* scip, /**< SCIP data structure */
12348 SCIP_CONS* cons, /**< constraint data */
12349 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12350 )
12351 {
12352 SCIP_CONSDATA* consdata;
12353
12354 assert(scip != NULL);
12355 assert(cons != NULL);
12356 assert(isquadratic != NULL);
12357 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12358
12359 consdata = SCIPconsGetData(cons);
12360 assert(consdata != NULL);
12361 assert(consdata->expr != NULL);
12362
12363 /* check whether constraint expression is quadratic in extended formulation */
12364 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12365
12366 /* if not quadratic in non-extended formulation, then do indicate quadratic */
12367 if( *isquadratic )
12368 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12369
12370 return SCIP_OKAY;
12371 }
12372
12373 /** changes left-hand-side of a nonlinear constraint
12374 *
12375 * @attention This method can only be called in the problem stage.
12376 */
12377 SCIP_RETCODE SCIPchgLhsNonlinear(
12378 SCIP* scip, /**< SCIP data structure */
12379 SCIP_CONS* cons, /**< constraint data */
12380 SCIP_Real lhs /**< new left-hand-side */
12381 )
12382 {
12383 SCIP_CONSDATA* consdata;
12384
12385 assert(scip != NULL);
12386 assert(cons != NULL);
12387 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12388
12389 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12390 {
12391 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12392 return SCIP_INVALIDCALL;
12393 }
12394
12395 /* we should have an original constraint */
12396 assert(SCIPconsIsOriginal(cons));
12397
12398 consdata = SCIPconsGetData(cons);
12399 assert(consdata != NULL);
12400
12401 if( consdata->lhs == lhs )
12402 return SCIP_OKAY;
12403
12404 consdata->lhs = lhs;
12405
12406 /* not sure we care about any of these flags for original constraints */
12407 consdata->ispropagated = FALSE;
12408
12409 return SCIP_OKAY;
12410 }
12411
12412 /** changes right-hand-side of a nonlinear constraint
12413 *
12414 * @attention This method can only be called in the problem stage.
12415 */
12416 SCIP_RETCODE SCIPchgRhsNonlinear(
12417 SCIP* scip, /**< SCIP data structure */
12418 SCIP_CONS* cons, /**< constraint data */
12419 SCIP_Real rhs /**< new right-hand-side */
12420 )
12421 {
12422 SCIP_CONSDATA* consdata;
12423
12424 assert(scip != NULL);
12425 assert(cons != NULL);
12426 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12427
12428 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12429 {
12430 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12431 return SCIP_INVALIDCALL;
12432 }
12433
12434 /* we should have an original constraint */
12435 assert(SCIPconsIsOriginal(cons));
12436
12437 consdata = SCIPconsGetData(cons);
12438 assert(consdata != NULL);
12439
12440 if( consdata->rhs == rhs )
12441 return SCIP_OKAY;
12442
12443 consdata->rhs = rhs;
12444
12445 /* not sure we care about any of these flags for original constraints */
12446 consdata->ispropagated = FALSE;
12447
12448 return SCIP_OKAY;
12449 }
12450
12451 /** changes expression of a nonlinear constraint
12452 *
12453 * @attention This method can only be called in the problem stage.
12454 */
12455 SCIP_RETCODE SCIPchgExprNonlinear(
12456 SCIP* scip, /**< SCIP data structure */
12457 SCIP_CONS* cons, /**< constraint data */
12458 SCIP_EXPR* expr /**< new expression */
12459 )
12460 {
12461 SCIP_CONSHDLR* conshdlr;
12462 SCIP_CONSDATA* consdata;
12463
12464 assert(scip != NULL);
12465 assert(cons != NULL);
12466 assert(expr != NULL);
12467
12468 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12469 {
12470 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12471 return SCIP_INVALIDCALL;
12472 }
12473
12474 /* we should have an original constraint */
12475 assert(SCIPconsIsOriginal(cons));
12476
12477 conshdlr = SCIPconsGetHdlr(cons);
12478 assert(conshdlr != NULL);
12479 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12480
12481 consdata = SCIPconsGetData(cons);
12482 assert(consdata != NULL);
12483 assert(consdata->expr != NULL);
12484
12485 /* we should not have collected additional data for the expr
12486 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12487 */
12488 assert(consdata->nvarexprs == 0);
12489 assert(consdata->varexprs == NULL);
12490 assert(!consdata->catchedevents);
12491
12492 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12493
12494 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12495 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12496
12497 /* not sure we care about any of these flags for original constraints */
12498 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12499 consdata->issimplified = FALSE;
12500 consdata->ispropagated = FALSE;
12501
12502 return SCIP_OKAY;
12503 }
12504
12505 /** adds coef * var to nonlinear constraint
12506 *
12507 * @attention This method can only be called in the problem stage.
12508 */
12509 SCIP_RETCODE SCIPaddLinearVarNonlinear(
12510 SCIP* scip, /**< SCIP data structure */
12511 SCIP_CONS* cons, /**< constraint data */
12512 SCIP_VAR* var, /**< variable */
12513 SCIP_Real coef /**< coefficient */
12514 )
12515 {
12516 SCIP_CONSHDLR* conshdlr;
12517 SCIP_CONSDATA* consdata;
12518 SCIP_EXPR* varexpr;
12519
12520 assert(scip != NULL);
12521 assert(cons != NULL);
12522
12523 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12524 {
12525 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12526 return SCIP_INVALIDCALL;
12527 }
12528
12529 /* we should have an original constraint */
12530 assert(SCIPconsIsOriginal(cons));
12531
12532 if( coef == 0.0 )
12533 return SCIP_OKAY;
12534
12535 conshdlr = SCIPconsGetHdlr(cons);
12536 assert(conshdlr != NULL);
12537 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12538
12539 consdata = SCIPconsGetData(cons);
12540 assert(consdata != NULL);
12541 assert(consdata->expr != NULL);
12542
12543 /* we should not have collected additional data for it
12544 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12545 */
12546 assert(consdata->nvarexprs == 0);
12547 assert(consdata->varexprs == NULL);
12548 assert(!consdata->catchedevents);
12549
12550 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12551
12552 /* append to sum, if consdata->expr is sum and not used anywhere else */
12553 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12554 {
12555 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12556 }
12557 else
12558 {
12559 /* create new expression = 1 * consdata->expr + coef * var */
12560 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12561 SCIP_Real coefs[2] = { 1.0, coef };
12562
12563 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12564
12565 /* release old root expr */
12566 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12567 }
12568
12569 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12570
12571 /* not sure we care about any of these flags for original constraints */
12572 consdata->issimplified = FALSE;
12573 consdata->ispropagated = FALSE;
12574
12575 return SCIP_OKAY;
12576 }
12577
12578 /** adds coef * expr to nonlinear constraint
12579 *
12580 * @attention This method can only be called in the problem stage.
12581 */
12582 SCIP_RETCODE SCIPaddExprNonlinear(
12583 SCIP* scip, /**< SCIP data structure */
12584 SCIP_CONS* cons, /**< nonlinear constraint */
12585 SCIP_EXPR* expr, /**< expression */
12586 SCIP_Real coef /**< coefficient */
12587 )
12588 {
12589 SCIP_CONSHDLR* conshdlr;
12590 SCIP_CONSDATA* consdata;
12591 SCIP_EXPR* exprowned;
12592
12593 assert(scip != NULL);
12594 assert(cons != NULL);
12595
12596 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12597 {
12598 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12599 return SCIP_INVALIDCALL;
12600 }
12601
12602 /* we should have an original constraint */
12603 assert(SCIPconsIsOriginal(cons));
12604
12605 if( coef == 0.0 )
12606 return SCIP_OKAY;
12607
12608 conshdlr = SCIPconsGetHdlr(cons);
12609 assert(conshdlr != NULL);
12610 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12611
12612 consdata = SCIPconsGetData(cons);
12613 assert(consdata != NULL);
12614 assert(consdata->expr != NULL);
12615
12616 /* we should not have collected additional data for it
12617 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12618 */
12619 assert(consdata->nvarexprs == 0);
12620 assert(consdata->varexprs == NULL);
12621 assert(!consdata->catchedevents);
12622
12623 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12624 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12625
12626 /* append to sum, if consdata->expr is sum and not used anywhere else */
12627 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12628 {
12629 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12630 }
12631 else
12632 {
12633 /* create new expression = 1 * consdata->expr + coef * var */
12634 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12635 SCIP_Real coefs[2] = { 1.0, coef };
12636
12637 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12638
12639 /* release old root expr */
12640 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12641 }
12642
12643 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12644
12645 /* not sure we care about any of these flags for original constraints */
12646 consdata->issimplified = FALSE;
12647 consdata->ispropagated = FALSE;
12648
12649 return SCIP_OKAY;
12650 }
12651
12652 /** gets absolute violation of nonlinear constraint
12653 *
12654 * This function evaluates the constraints in the given solution.
12655 *
12656 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12657 */
12658 SCIP_RETCODE SCIPgetAbsViolationNonlinear(
12659 SCIP* scip, /**< SCIP data structure */
12660 SCIP_CONS* cons, /**< constraint */
12661 SCIP_SOL* sol, /**< solution to check */
12662 SCIP_Real* viol /**< buffer to store computed violation */
12663 )
12664 {
12665 assert(cons != NULL);
12666 assert(viol != NULL);
12667
12668 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12669 *viol = getConsAbsViolation(cons);
12670
12671 return SCIP_OKAY;
12672 }
12673
12674 /** gets scaled violation of nonlinear constraint
12675 *
12676 * This function evaluates the constraints in the given solution.
12677 *
12678 * The scaling that is applied to the absolute violation of the constraint
12679 * depends on the setting of parameter constraints/nonlinear/violscale.
12680 */
12681 SCIP_RETCODE SCIPgetRelViolationNonlinear(
12682 SCIP* scip, /**< SCIP data structure */
12683 SCIP_CONS* cons, /**< constraint */
12684 SCIP_SOL* sol, /**< solution to check */
12685 SCIP_Real* viol /**< buffer to store computed violation */
12686 )
12687 {
12688 assert(cons != NULL);
12689 assert(viol != NULL);
12690
12691 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12692 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12693
12694 return SCIP_OKAY;
12695 }
12696
12697 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12698 void SCIPgetLinvarMayDecreaseNonlinear(
12699 SCIP* scip, /**< SCIP data structure */
12700 SCIP_CONS* cons, /**< nonlinear constraint */
12701 SCIP_VAR** var, /**< pointer to store the variable */
12702 SCIP_Real* coef /**< pointer to store the coefficient */
12703 )
12704 {
12705 SCIP_CONSDATA* consdata;
12706
12707 assert(cons != NULL);
12708 assert(var != NULL);
12709 assert(coef != NULL);
12710
12711 /* check for a linear variable that can be increased or decreased without harming feasibility */
12712 findUnlockedLinearVar(scip, cons);
12713
12714 consdata = SCIPconsGetData(cons);
12715 assert(consdata != NULL);
12716
12717 *var = consdata->linvardecr;
12718 *coef = consdata->linvardecrcoef;
12719 }
12720
12721 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12722 void SCIPgetLinvarMayIncreaseNonlinear(
12723 SCIP* scip, /**< SCIP data structure */
12724 SCIP_CONS* cons, /**< nonlinear constraint */
12725 SCIP_VAR** var, /**< pointer to store the variable */
12726 SCIP_Real* coef /**< pointer to store the coefficient */
12727 )
12728 {
12729 SCIP_CONSDATA* consdata;
12730
12731 assert(cons != NULL);
12732 assert(var != NULL);
12733 assert(coef != NULL);
12734
12735 /* check for a linear variable that can be increased or decreased without harming feasibility */
12736 findUnlockedLinearVar(scip, cons);
12737
12738 consdata = SCIPconsGetData(cons);
12739 assert(consdata != NULL);
12740
12741 *var = consdata->linvarincr;
12742 *coef = consdata->linvarincrcoef;
12743 }
12744
12745
12746 /*
12747 * Methods for Expressions in Nonlinear Constraints
12748 */
12749
12750 /** returns the number of positive rounding locks of an expression */
12751 int SCIPgetExprNLocksPosNonlinear(
12752 SCIP_EXPR* expr /**< expression */
12753 )
12754 {
12755 assert(expr != NULL);
12756 assert(SCIPexprGetOwnerData(expr) != NULL);
12757
12758 return SCIPexprGetOwnerData(expr)->nlockspos;
12759 }
12760
12761 /** returns the number of negative rounding locks of an expression */
12762 int SCIPgetExprNLocksNegNonlinear(
12763 SCIP_EXPR* expr /**< expression */
12764 )
12765 {
12766 assert(expr != NULL);
12767 assert(SCIPexprGetOwnerData(expr) != NULL);
12768
12769 return SCIPexprGetOwnerData(expr)->nlocksneg;
12770 }
12771
12772 /** returns the variable used for linearizing a given expression (return value might be NULL)
12773 *
12774 * @note for variable expression it returns the corresponding variable
12775 */
12776 SCIP_VAR* SCIPgetExprAuxVarNonlinear(
12777 SCIP_EXPR* expr /**< expression */
12778 )
12779 {
12780 SCIP_EXPR_OWNERDATA* ownerdata;
12781
12782 assert(expr != NULL);
12783
12784 ownerdata = SCIPexprGetOwnerData(expr);
12785 assert(ownerdata != NULL);
12786
12787 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12788 }
12789
12790 /** returns the number of enforcements for an expression */
12791 int SCIPgetExprNEnfosNonlinear(
12792 SCIP_EXPR* expr /**< expression */
12793 )
12794 {
12795 assert(expr != NULL);
12796 assert(SCIPexprGetOwnerData(expr) != NULL);
12797
12798 return SCIPexprGetOwnerData(expr)->nenfos;
12799 }
12800
12801 /** returns the data for one of the enforcements of an expression */
12802 void SCIPgetExprEnfoDataNonlinear(
12803 SCIP_EXPR* expr, /**< expression */
12804 int idx, /**< position of enforcement in enfos array */
12805 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12806 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12807 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12808 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12809 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12810 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12811 )
12812 {
12813 SCIP_EXPR_OWNERDATA* ownerdata;
12814
12815 assert(expr != NULL);
12816
12817 ownerdata = SCIPexprGetOwnerData(expr);
12818 assert(ownerdata != NULL);
12819 assert(idx >= 0);
12820 assert(idx < ownerdata->nenfos);
12821 assert(ownerdata->enfos[idx] != NULL);
12822 assert(nlhdlr != NULL);
12823
12824 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12825
12826 if( nlhdlrexprdata != NULL )
12827 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12828
12829 if( nlhdlrparticipation != NULL )
12830 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12831
12832 if( sepabelowusesactivity != NULL )
12833 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12834
12835 if( sepaaboveusesactivity != NULL )
12836 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12837
12838 if( auxvalue != NULL )
12839 *auxvalue = ownerdata->enfos[idx]->auxvalue;
12840 }
12841
12842 /** sets the auxiliary value of expression for one of the enforcements of an expression */
12843 void SCIPsetExprEnfoAuxValueNonlinear(
12844 SCIP_EXPR* expr, /**< expression */
12845 int idx, /**< position of enforcement in enfos array */
12846 SCIP_Real auxvalue /**< the new value of auxval */
12847 )
12848 {
12849 SCIP_EXPR_OWNERDATA* ownerdata;
12850
12851 assert(expr != NULL);
12852
12853 ownerdata = SCIPexprGetOwnerData(expr);
12854 assert(ownerdata != NULL);
12855
12856 assert(idx >= 0);
12857 assert(idx < ownerdata->nenfos);
12858 assert(ownerdata->enfos[idx] != NULL);
12859
12860 ownerdata->enfos[idx]->auxvalue = auxvalue;
12861 }
12862
12863 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12864 *
12865 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12866 */
12867 unsigned int SCIPgetExprNPropUsesActivityNonlinear(
12868 SCIP_EXPR* expr /**< expression */
12869 )
12870 {
12871 assert(expr != NULL);
12872 assert(SCIPexprGetOwnerData(expr) != NULL);
12873
12874 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12875 }
12876
12877 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12878 *
12879 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12880 */
12881 unsigned int SCIPgetExprNSepaUsesActivityNonlinear(
12882 SCIP_EXPR* expr /**< expression */
12883 )
12884 {
12885 assert(expr != NULL);
12886 assert(SCIPexprGetOwnerData(expr) != NULL);
12887
12888 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12889 }
12890
12891 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12892 *
12893 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12894 */
12895 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12896 SCIP_EXPR* expr /**< expression */
12897 )
12898 {
12899 assert(expr != NULL);
12900 assert(SCIPexprGetOwnerData(expr) != NULL);
12901
12902 return SCIPexprGetOwnerData(expr)->nauxvaruses;
12903 }
12904
12905 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12906 *
12907 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12908 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12909 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12910 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12911 * and also increments this count for all variables in the expression.
12912 *
12913 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12914 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12915 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12916 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12917 */
12918 SCIP_RETCODE SCIPregisterExprUsageNonlinear(
12919 SCIP* scip, /**< SCIP data structure */
12920 SCIP_EXPR* expr, /**< expression */
12921 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12922 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12923 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12924 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12925 )
12926 {
12927 SCIP_EXPR_OWNERDATA* ownerdata;
12928
12929 assert(expr != NULL);
12930
12931 ownerdata = SCIPexprGetOwnerData(expr);
12932 assert(ownerdata != NULL);
12933
12934 /* do not store auxvar request for variable expressions */
12935 if( useauxvar && SCIPisExprVar(scip, expr) )
12936 useauxvar = FALSE;
12937
12938 if( ownerdata->nenfos >= 0 &&
12939 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12940 (ownerdata->nauxvaruses == 0 && useauxvar)
12941 ) )
12942 {
12943 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12944 * we require additional enforcement methods, that is,
12945 * - activity of expr was not used before but will be used now, or
12946 * - auxiliary variable of expr was not required before but will be used now
12947 */
12948 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12949 }
12950
12951 if( useauxvar )
12952 ++ownerdata->nauxvaruses;
12953
12954 if( useactivityforprop )
12955 ++ownerdata->nactivityusesprop;
12956
12957 if( useactivityforsepabelow || useactivityforsepaabove )
12958 ++ownerdata->nactivityusessepa;
12959
12960 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12961 * information is used in detectNlhdlr()
12962 */
12963 if( useactivityforsepabelow )
12964 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12965 if( useactivityforsepaabove )
12966 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12967
12968 if( useactivityforprop )
12969 {
12970 /* if activity will be used for propagation, then make sure there is a valid activity
12971 * this way, we can do a reversepropcall after detectNlhdlr
12972 */
12973 SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12974 }
12975
12976 /* increase the nactivityusedsepa counter for all variables used in the given expression */
12977 if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12978 {
12979 SCIP_EXPRITER* it;
12980
12981 /* create and initialize iterator */
12982 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12983 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
12984
12985 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12986 if( SCIPisExprVar(scip, expr) )
12987 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
12988
12989 /* free iterator */
12990 SCIPfreeExpriter(&it);
12991 }
12992
12993 return SCIP_OKAY;
12994 }
12995
12996 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
12997 *
12998 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
12999 * Assume that f(x) is associated with auxiliary variable z.
13000 *
13001 * If there are negative locks, then returns the violation of z ≤ f(x) and sets `violover` to TRUE.
13002 * If there are positive locks, then returns the violation of z ≥ f(x) and sets `violunder` to TRUE.
13003 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13004 *
13005 * If necessary, f is evaluated in the given solution. If that fails (domain error),
13006 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13007 */
13008 SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(
13009 SCIP* scip, /**< SCIP data structure */
13010 SCIP_EXPR* expr, /**< expression */
13011 SCIP_SOL* sol, /**< solution */
13012 SCIP_Longint soltag, /**< tag of solution */
13013 SCIP_Real* viol, /**< buffer to store computed violation */
13014 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13015 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13016 )
13017 {
13018 assert(scip != NULL);
13019 assert(expr != NULL);
13020 assert(viol != NULL);
13021
13022 /* make sure expression has been evaluated */
13023 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13024
13025 /* get violation from internal method */
13026 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13027
13028 return SCIP_OKAY;
13029 }
13030
13031 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13032 *
13033 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13034 * Assume that f(w) is associated with auxiliary variable z.
13035 *
13036 * If there are negative locks, then returns the violation of z ≤ f(w) and sets `violover` to TRUE.
13037 * If there are positive locks, then returns the violation of z ≥ f(w) and sets `violunder` to TRUE.
13038 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13039 *
13040 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13041 * both `violover` and `violunder` are set to TRUE.
13042 */
13043 SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(
13044 SCIP* scip, /**< SCIP data structure */
13045 SCIP_EXPR* expr, /**< expression */
13046 SCIP_Real auxvalue, /**< the value of f(w) */
13047 SCIP_SOL* sol, /**< solution that has been evaluated */
13048 SCIP_Real* viol, /**< buffer to store computed violation */
13049 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13050 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13051 )
13052 {
13053 assert(scip != NULL);
13054 assert(expr != NULL);
13055 assert(viol != NULL);
13056
13057 /* get violation from internal method */
13058 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13059
13060 return SCIP_OKAY;
13061 }
13062
13063
13064 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13065 *
13066 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13067 * Assume that f(w) is associated with auxiliary variable z.
13068 *
13069 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13070 * the absolute violation divided by max(1,|f(w)|).
13071 *
13072 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13073 * both `violover` and `violunder` are set to TRUE.
13074 */
13075 SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(
13076 SCIP* scip, /**< SCIP data structure */
13077 SCIP_EXPR* expr, /**< expression */
13078 SCIP_Real auxvalue, /**< the value of f(w) */
13079 SCIP_SOL* sol, /**< solution that has been evaluated */
13080 SCIP_Real* viol, /**< buffer to store computed violation */
13081 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13082 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13083 )
13084 {
13085 assert(scip != NULL);
13086 assert(expr != NULL);
13087 assert(viol != NULL);
13088
13089 /* get violation from internal method */
13090 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13091
13092 if( !SCIPisInfinity(scip, *viol) )
13093 {
13094 assert(auxvalue != SCIP_INVALID);
13095 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13096 *viol /= MAX(1.0, REALABS(auxvalue));
13097 }
13098
13099 return SCIP_OKAY;
13100 }
13101
13102 /** returns bounds on the expression
13103 *
13104 * This gives an intersection of bounds from
13105 * - activity calculation (SCIPexprGetActivity()), if valid,
13106 * - auxiliary variable, if present,
13107 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13108 *
13109 * @note The returned interval can be empty!
13110 */
13111 SCIP_INTERVAL SCIPgetExprBoundsNonlinear(
13112 SCIP* scip, /**< SCIP data structure */
13113 SCIP_EXPR* expr /**< expression */
13114 )
13115 {
13116 SCIP_EXPR_OWNERDATA* ownerdata;
13117 SCIP_CONSHDLRDATA* conshdlrdata;
13118 SCIP_INTERVAL bounds;
13119
13120 assert(scip != NULL);
13121 assert(expr != NULL);
13122
13123 ownerdata = SCIPexprGetOwnerData(expr);
13124 assert(ownerdata != NULL);
13125
13126 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13127 assert(conshdlrdata != NULL);
13128
13129 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13130
13131 /* start with propbounds if they belong to current propagation */
13132 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13133 {
13134 bounds = ownerdata->propbounds;
13135 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13136 }
13137 else
13138 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &bounds);
13139
13140 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13141 {
13142 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13143 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13144 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13145 }
13146
13147 if( ownerdata->auxvar != NULL )
13148 {
13149 /* apply auxiliary variable bounds to bounds */
13150 SCIP_INTERVAL auxvarbounds;
13151
13152 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13153 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13154 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13155 }
13156
13157 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13158
13159 return bounds;
13160 }
13161
13162 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13163 * corresponding (auxiliary) variable (if any)
13164 *
13165 * @attention this function should only be called during domain propagation in cons_nonlinear
13166 */
13167 SCIP_RETCODE SCIPtightenExprIntervalNonlinear(
13168 SCIP* scip, /**< SCIP data structure */
13169 SCIP_EXPR* expr, /**< expression to be tightened */
13170 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13171 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13172 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13173 )
13174 {
13175 SCIP_EXPR_OWNERDATA* ownerdata;
13176 SCIP_CONSHDLRDATA* conshdlrdata;
13177
13178 assert(scip != NULL);
13179 assert(expr != NULL);
13180 assert(cutoff != NULL);
13181
13182 ownerdata = SCIPexprGetOwnerData(expr);
13183 assert(ownerdata != NULL);
13184 assert(ownerdata->conshdlr != NULL);
13185
13186 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13187 assert(conshdlrdata != NULL);
13188
13189 /* the code below assumes that current activity is valid
13190 * if it turns out that we cannot ensure that, then we should change code
13191 */
13192 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13193 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13194
13195 *cutoff = FALSE;
13196
13197 #ifdef DEBUG_PROP
13198 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13199 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13200 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13201 #endif
13202
13203 if( SCIPexprIsIntegral(expr) )
13204 {
13205 /* apply integrality to new bounds
13206 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13207 */
13208 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13209 newbounds.inf = SCIPceil(scip, newbounds.inf);
13210 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
13211 newbounds.sup = SCIPfloor(scip, newbounds.sup);
13212 #ifdef DEBUG_PROP
13213 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13214 #endif
13215 }
13216
13217 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13218 {
13219 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13220
13221 *cutoff = TRUE;
13222 return SCIP_OKAY;
13223 }
13224
13225 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13226 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13227 {
13228 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13229
13230 *cutoff = TRUE;
13231 return SCIP_OKAY;
13232 }
13233
13234 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13235 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13236 {
13237 /* if already having propbounds in expr, then tighten newbounds by propbounds */
13238 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13239 }
13240 else
13241 {
13242 /* first time we have propbounds for expr in this propagation rounds:
13243 * intersect with activity (though don't let it become empty if very close intervals)
13244 */
13245 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13246 }
13247 #ifdef DEBUG_PROP
13248 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13249 #endif
13250
13251 /* check if the new bounds lead to an empty interval */
13252 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13253 {
13254 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13255
13256 *cutoff = TRUE;
13257 return SCIP_OKAY;
13258 }
13259
13260 /* if expr is not constant or variable, then store newbounds in expr->propbounds
13261 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13262 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13263 */
13264 if( SCIPexprGetNChildren(expr) > 0 )
13265 {
13266 ownerdata->propbounds = newbounds;
13267 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13268 }
13269
13270 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13271 * propagation or update of auxvar bounds
13272 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13273 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13274 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13275 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13276 * one or should we not even update propbounds to newbounds if the update is small?
13277 */
13278 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13279 {
13280 #ifdef DEBUG_PROP
13281 SCIPdebugMsg(scip, " new bounds [%g,%g] for expr %p not sufficiently tighter than activity -- not adding to propqueue or tightening auxvar\n", newbounds.inf, newbounds.sup, (void*)expr);
13282 #endif
13283 return SCIP_OKAY;
13284 }
13285
13286 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13287 {
13288 /* add expression to propagation queue if not there yet and not var or constant and
13289 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13290 */
13291 #ifdef DEBUG_PROP
13292 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13293 #endif
13294 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13295 ownerdata->inpropqueue = TRUE;
13296 }
13297
13298 /* update bounds on variable or auxiliary variable */
13299 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13300
13301 return SCIP_OKAY;
13302 }
13303
13304 /** mark constraints that include this expression to be propagated again
13305 *
13306 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13307 * a change of variable bounds, e.g., because new information on the expression is available
13308 * that could potentially lead to tighter expression activity values.
13309 *
13310 * Note, that this call marks also constraints for propagation which only share some variable
13311 * with this expression.
13312 */
13313 SCIP_RETCODE SCIPmarkExprPropagateNonlinear(
13314 SCIP* scip, /**< SCIP data structure */
13315 SCIP_EXPR* expr /**< expression to propagate again */
13316 )
13317 {
13318 SCIP_EXPRITER* it;
13319 SCIP_CONSDATA* consdata;
13320 SCIP_EXPR_OWNERDATA* ownerdata;
13321 int c;
13322
13323 assert(scip != NULL);
13324 assert(expr != NULL);
13325
13326 ownerdata = SCIPexprGetOwnerData(expr);
13327 assert(ownerdata != NULL);
13328
13329 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13330
13331 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13332 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
13333
13334 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13335 {
13336 if( !SCIPisExprVar(scip, expr) )
13337 continue;
13338
13339 ownerdata = SCIPexprGetOwnerData(expr);
13340 assert(ownerdata != NULL);
13341
13342 for( c = 0; c < ownerdata->nconss; ++c )
13343 {
13344 consdata = SCIPconsGetData(ownerdata->conss[c]);
13345 assert(consdata != NULL);
13346 consdata->ispropagated = FALSE;
13347 }
13348 }
13349
13350 SCIPfreeExpriter(&it);
13351
13352 return SCIP_OKAY;
13353 }
13354
13355 /** adds violation-branching score to an expression
13356 *
13357 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13358 * The expression must either be a variable expression or have an aux-variable.
13359 * In the latter case, branching on auxiliary variables must have been enabled.
13360 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13361 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13362 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13363 *
13364 * @see SCIPaddExprsViolScoreNonlinear()
13365 */
13366 void SCIPaddExprViolScoreNonlinear(
13367 SCIP* scip, /**< SCIP data structure */
13368 SCIP_EXPR* expr, /**< expression where to add branching score */
13369 SCIP_Real violscore /**< violation score to add to expression */
13370 )
13371 {
13372 SCIP_EXPR_OWNERDATA* ownerdata;
13373 SCIP_CONSHDLRDATA* conshdlrdata;
13374
13375 assert(scip != NULL);
13376 assert(expr != NULL);
13377 assert(violscore >= 0.0);
13378
13379 ownerdata = SCIPexprGetOwnerData(expr);
13380 assert(ownerdata != NULL);
13381
13382 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13383 assert(conshdlrdata != NULL);
13384
13385 /* if not allowing to branch on auxvars, then expr must be a var-expr */
13386 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13387 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13388 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13389
13390 /* reset branching score if we are in a different enfo round */
13391 if( ownerdata->violscoretag != conshdlrdata->enforound )
13392 {
13393 ownerdata->violscoresum = violscore;
13394 ownerdata->violscoremax = violscore;
13395 ownerdata->nviolscores = 1;
13396 ownerdata->violscoretag = conshdlrdata->enforound;
13397 return;
13398 }
13399
13400 ownerdata->violscoresum += violscore;
13401 if( violscore > ownerdata->violscoremax )
13402 ownerdata->violscoremax = violscore;
13403 ++ownerdata->nviolscores;
13404 }
13405
13406 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13407 *
13408 * Each expression must either be a variable expression or have an aux-variable.
13409 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13410 * variables present in `exprs`.
13411 */
13412 SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(
13413 SCIP* scip, /**< SCIP data structure */
13414 SCIP_EXPR** exprs, /**< expressions where to add branching score */
13415 int nexprs, /**< number of expressions */
13416 SCIP_Real violscore, /**< violation score to add to expression */
13417 SCIP_SOL* sol, /**< current solution */
13418 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13419 )
13420 {
13421 SCIP_EXPRITER* it;
13422 SCIP_EXPR** varexprs;
13423 SCIP_EXPR* e;
13424 int nvars;
13425 int varssize;
13426 int i;
13427
13428 assert(exprs != NULL || nexprs == 0);
13429 assert(success != NULL);
13430
13431 if( nexprs == 0 )
13432 {
13433 *success = FALSE;
13434 return SCIP_OKAY;
13435 }
13436
13437 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13438 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13439 {
13440 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13441 return SCIP_OKAY;
13442 }
13443
13444 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13445 nvars = 0;
13446 varssize = 5;
13447 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13448
13449 SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13450 SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
13451
13452 for( i = 0; i < nexprs; ++i )
13453 {
13454 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13455 {
13456 assert(e != NULL);
13457
13458 if( SCIPisExprVar(scip, e) )
13459 {
13460 /* add variable expression to vars array */
13461 if( varssize == nvars )
13462 {
13463 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13464 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13465 }
13466 assert(varssize > nvars);
13467
13468 varexprs[nvars++] = e;
13469 }
13470 }
13471 }
13472
13473 SCIPfreeExpriter(&it);
13474
13475 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13476
13477 SCIPfreeBufferArray(scip, &varexprs);
13478
13479 return SCIP_OKAY;
13480 }
13481
13482 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13483 SCIP_Real SCIPgetExprViolScoreNonlinear(
13484 SCIP_EXPR* expr /**< expression */
13485 )
13486 {
13487 SCIP_EXPR_OWNERDATA* ownerdata;
13488 SCIP_CONSHDLRDATA* conshdlrdata;
13489
13490 assert(expr != NULL);
13491
13492 ownerdata = SCIPexprGetOwnerData(expr);
13493 assert(ownerdata != NULL);
13494
13495 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13496 assert(conshdlrdata != NULL);
13497
13498 if( conshdlrdata->enforound != ownerdata->violscoretag )
13499 return 0.0;
13500
13501 if( ownerdata->nviolscores == 0 )
13502 return 0.0;
13503
13504 switch( conshdlrdata->branchscoreagg )
13505 {
13506 case 'a' :
13507 /* average */
13508 return ownerdata->violscoresum / ownerdata->nviolscores;
13509
13510 case 'm' :
13511 /* maximum */
13512 return ownerdata->violscoremax;
13513
13514 case 's' :
13515 /* sum */
13516 return ownerdata->violscoresum;
13517
13518 default:
13519 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13520 SCIPABORT();
13521 return SCIP_INVALID;
13522 }
13523 }
13524
13525 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13526 *
13527 * @see SCIPexprGetDerivative()
13528 */
13529 SCIP_Real SCIPgetExprPartialDiffNonlinear(
13530 SCIP* scip, /**< SCIP data structure */
13531 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13532 SCIP_VAR* var /**< variable (needs to be in the expression) */
13533 )
13534 {
13535 SCIP_EXPR_OWNERDATA* ownerdata;
13536 SCIP_CONSHDLRDATA* conshdlrdata;
13537 SCIP_EXPR* varexpr;
13538
13539 assert(scip != NULL);
13540 assert(expr != NULL);
13541 assert(var != NULL);
13542
13543 /* return 0.0 for value expression */
13544 if( SCIPisExprValue(scip, expr) )
13545 {
13546 assert(SCIPexprGetDerivative(expr) == 0.0);
13547 return 0.0;
13548 }
13549
13550 /* check if an error occurred during the last SCIPevalExprGradient() call */
13551 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13552 return SCIP_INVALID;
13553
13554 ownerdata = SCIPexprGetOwnerData(expr);
13555 assert(ownerdata != NULL);
13556
13557 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13558 assert(conshdlrdata != NULL);
13559
13560 /* use variable to expressions mapping which is stored in the constraint handler data */
13561 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13562
13563 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13564 assert(varexpr != NULL);
13565 assert(SCIPisExprVar(scip, varexpr));
13566
13567 /* use difftag to decide whether the variable belongs to the expression */
13568 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13569 }
13570
13571 /** returns the var's coordinate of Hu partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13572 *
13573 * @see SCIPexprGetBardot()
13574 */
13575 SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(
13576 SCIP* scip, /**< SCIP data structure */
13577 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13578 SCIP_VAR* var /**< variable (needs to be in the expression) */
13579 )
13580 {
13581 SCIP_EXPR_OWNERDATA* ownerdata;
13582 SCIP_CONSHDLRDATA* conshdlrdata;
13583 SCIP_EXPR* varexpr;
13584
13585 assert(scip != NULL);
13586 assert(expr != NULL);
13587 assert(var != NULL);
13588
13589 /* return 0.0 for value expression */
13590 if( SCIPisExprValue(scip, expr) )
13591 return 0.0;
13592
13593 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13594 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13595 return SCIP_INVALID;
13596
13597 ownerdata = SCIPexprGetOwnerData(expr);
13598 assert(ownerdata != NULL);
13599
13600 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13601 assert(conshdlrdata != NULL);
13602
13603 /* use variable to expressions mapping which is stored in the constraint handler data;
13604 * if this fails it means that we are asking for the var's component of H*u for a var
13605 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13606 */
13607 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13608
13609 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13610 assert(varexpr != NULL);
13611 assert(SCIPisExprVar(scip, varexpr));
13612
13613 /* use difftag to decide whether the variable belongs to the expression */
13614 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13615 }
13616
13617 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
13618 *
13619 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13620 */
13621 SCIP_Real SCIPevalExprQuadraticAuxNonlinear(
13622 SCIP* scip, /**< SCIP data structure */
13623 SCIP_EXPR* expr, /**< quadratic expression */
13624 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13625 )
13626 {
13627 SCIP_Real auxvalue;
13628 int nlinexprs;
13629 SCIP_Real* lincoefs;
13630 SCIP_EXPR** linexprs;
13631 int nquadexprs;
13632 int nbilinexprs;
13633 int i;
13634
13635 assert(scip != NULL);
13636 assert(expr != NULL);
13637
13638 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13639
13640 /* linear terms */
13641 for( i = 0; i < nlinexprs; ++i )
13642 {
13643 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13644 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13645 }
13646
13647 /* quadratic terms */
13648 for( i = 0; i < nquadexprs; ++i )
13649 {
13650 SCIP_EXPR* quadexprterm;
13651 SCIP_Real lincoef;
13652 SCIP_Real sqrcoef;
13653 SCIP_Real solval;
13654
13655 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13656
13657 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13658
13659 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13660 auxvalue += (lincoef + sqrcoef * solval) * solval;
13661 }
13662
13663 /* bilinear terms */
13664 for( i = 0; i < nbilinexprs; ++i )
13665 {
13666 SCIP_EXPR* expr1;
13667 SCIP_EXPR* expr2;
13668 SCIP_Real coef;
13669
13670 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13671
13672 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13673 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13674 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13675 }
13676
13677 return auxvalue;
13678 }
13679
13680 /**@addtogroup PublicNlhdlrInterfaceMethods
13681 * @{
13682 */
13683
13684 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13685 SCIP_RETCODE SCIPincludeNlhdlrNonlinear(
13686 SCIP* scip, /**< SCIP data structure */
13687 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13688 const char* name, /**< name of nonlinear handler (must not be NULL) */
13689 const char* desc, /**< description of nonlinear handler (can be NULL) */
13690 int detectpriority, /**< detection priority of nonlinear handler */
13691 int enfopriority, /**< enforcement priority of nonlinear handler */
13692 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13693 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13694 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13695 )
13696 {
13697 SCIP_CONSHDLR* conshdlr;
13698 SCIP_CONSHDLRDATA* conshdlrdata;
13699
13700 assert(scip != NULL);
13701 assert(nlhdlr != NULL);
13702 assert(detect != NULL);
13703
13704 /* find myself */
13705 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13706 if( conshdlr == NULL )
13707 {
13708 SCIPerrorMessage("nonlinear constraint handler not found");
13709 return SCIP_PLUGINNOTFOUND;
13710 }
13711
13712 /* create nlhdlr */
13713 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13714
13715 /* include into constraint handler */
13716 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13717 assert(conshdlrdata != NULL);
13718
13719 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13720
13721 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13722 ++conshdlrdata->nnlhdlrs;
13723
13724 /* sort nonlinear handlers by detection priority, in decreasing order
13725 * will happen in INIT, so only do when called late
13726 */
13727 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13728 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13729
13730 return SCIP_OKAY;
13731 }
13732
13733 /** get number of nonlinear handler */
13734 int SCIPgetNNlhdlrsNonlinear(
13735 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13736 )
13737 {
13738 SCIP_CONSHDLRDATA* conshdlrdata;
13739
13740 assert(conshdlr != NULL);
13741
13742 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13743 assert(conshdlrdata != NULL);
13744
13745 return conshdlrdata->nnlhdlrs;
13746 }
13747
13748 /** get nonlinear handlers */
13749 SCIP_NLHDLR** SCIPgetNlhdlrsNonlinear(
13750 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13751 )
13752 {
13753 SCIP_CONSHDLRDATA* conshdlrdata;
13754
13755 assert(conshdlr != NULL);
13756
13757 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13758 assert(conshdlrdata != NULL);
13759
13760 return conshdlrdata->nlhdlrs;
13761 }
13762
13763 /** returns a nonlinear handler of a given name (or NULL if not found) */
13764 SCIP_NLHDLR* SCIPfindNlhdlrNonlinear(
13765 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13766 const char* name /**< name of nonlinear handler */
13767 )
13768 {
13769 SCIP_CONSHDLRDATA* conshdlrdata;
13770 int h;
13771
13772 assert(conshdlr != NULL);
13773 assert(name != NULL);
13774
13775 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13776 assert(conshdlrdata != NULL);
13777
13778 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13779 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13780 return conshdlrdata->nlhdlrs[h];
13781
13782 return NULL;
13783 }
13784
13785 /** gives expression data that a given nonlinear handler stored in an expression
13786 *
13787 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13788 */
13789 SCIP_NLHDLREXPRDATA* SCIPgetNlhdlrExprDataNonlinear(
13790 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13791 SCIP_EXPR* expr /**< expression */
13792 )
13793 {
13794 SCIP_EXPR_OWNERDATA* ownerdata;
13795 int e;
13796
13797 assert(nlhdlr != NULL);
13798 assert(expr != NULL);
13799
13800 ownerdata = SCIPexprGetOwnerData(expr);
13801 assert(ownerdata != NULL);
13802
13803 for( e = 0; e < ownerdata->nenfos; ++e )
13804 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13805 return ownerdata->enfos[e]->nlhdlrexprdata;
13806
13807 return NULL;
13808 }
13809
13810 /** @} */
13811