SCIP Doxygen Documentation
 
Loading...
Searching...
No Matches
cons_nonlinear.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_nonlinear.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for nonlinear constraints specified by algebraic expressions
28 * @author Ksenia Bestuzheva
29 * @author Benjamin Mueller
30 * @author Felipe Serrano
31 * @author Stefan Vigerske
32 */
33
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36#ifdef SCIP_DEBUG
37#define ENFO_LOGGING
38#endif
39
40/* enable to get log output for enforcement */
41/* #define ENFO_LOGGING */
42/* define to get enforcement logging into file */
43/* #define ENFOLOGFILE "consexpr_enfo.log" */
44
45/* define to get more debug output from domain propagation */
46/* #define DEBUG_PROP */
47
48/*lint -e440*/
49/*lint -e441*/
50/*lint -e528*/
51/*lint -e666*/
52/*lint -e777*/
53/*lint -e866*/
54
55#include <ctype.h>
56#include "scip/cons_nonlinear.h"
57#include "scip/nlhdlr.h"
58#include "scip/expr_var.h"
59#include "scip/expr_sum.h"
60#include "scip/expr_value.h"
61#include "scip/expr_pow.h"
62#include "scip/nlhdlr_convex.h"
63#include "scip/cons_linear.h"
64#include "scip/cons_varbound.h"
65#include "scip/cons_and.h"
67#include "scip/heur_subnlp.h"
68#include "scip/heur_trysol.h"
69#include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
70#include "scip/debug.h"
71#include "scip/dialog_default.h"
72
73
74/* fundamental constraint handler properties */
75#define CONSHDLR_NAME "nonlinear"
76#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
77#define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
78#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
79#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
80 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
81#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82
83/* optional constraint handler properties */
84#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
85#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
86#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87
88#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
89#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
90#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
91
92#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
93#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
94
95/* properties of the nonlinear constraint handler statistics table */
96#define TABLE_NAME_NONLINEAR "cons_nonlinear"
97#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
98#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
99#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
100
101/* properties of the nonlinear handler statistics table */
102#define TABLE_NAME_NLHDLR "nlhdlr"
103#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
104#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
105#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
106
107#define DIALOG_NAME "nlhdlrs"
108#define DIALOG_DESC "display nonlinear handlers"
109#define DIALOG_ISSUBMENU FALSE
110
111#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
112#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
113#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
114#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
115
116#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
117
118#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
119
120/** translate from one value of infinity to another
121 *
122 * if val is &ge; infty1, then give infty2, else give val
123 */
124#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
125
126/** translates x to 2^x for non-negative integer x */
127#define POWEROFTWO(x) (0x1u << (x))
128
129#ifdef ENFO_LOGGING
130#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
132#else
133#define ENFOLOG(x)
134#endif
135
136/*
137 * Data structures
138 */
139
140/** enforcement data of an expression */
141typedef struct
142{
143 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
144 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
145 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
146 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
147 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
148 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
149 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
150} EXPRENFO;
151
152/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
153struct SCIP_Expr_OwnerData
154{
155 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
156
157 /* locks and monotonicity */
158 int nlockspos; /**< positive locks counter */
159 int nlocksneg; /**< negative locks counter */
160 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
161 int monotonicitysize; /**< length of monotonicity array */
162
163 /* propagation (in addition to activity that is stored in expr) */
164 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
165 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
166 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
167
168 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
169 EXPRENFO** enfos; /**< enforcements */
170 int nenfos; /**< number of enforcements, or -1 if not initialized */
171 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
172 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
173 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
174 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
175 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
176
177 /* branching */
178 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
179 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
180 int nviolscores; /**< number of violation scores stored for this expression */
181 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
182
183 /* additional data for variable expressions (TODO move into sub-struct?) */
184 SCIP_CONS** conss; /**< constraints in which this variable appears */
185 int nconss; /**< current number of constraints in conss */
186 int consssize; /**< length of conss array */
187 SCIP_Bool consssorted; /**< is the array of constraints sorted */
188
189 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
190};
191
192/** constraint data for nonlinear constraints */
193struct SCIP_ConsData
194{
195 /* data that defines the constraint: expression and sides */
196 SCIP_EXPR* expr; /**< expression that represents this constraint */
197 SCIP_Real lhs; /**< left-hand side */
198 SCIP_Real rhs; /**< right-hand side */
199
200 /* variables */
201 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
202 int nvarexprs; /**< total number of variable expressions */
203 SCIP_Bool catchedevents; /**< do we catch events on variables? */
204
205 /* constraint violation */
206 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
207 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
208 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
209 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
210
211 /* status flags */
212 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
213 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
214
215 /* locks */
216 int nlockspos; /**< number of positive locks */
217 int nlocksneg; /**< number of negative locks */
218
219 /* repair infeasible solutions */
220 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
221 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
222 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
223 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
224
225 /* miscellaneous */
226 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
227 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
228 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
229};
230
231/** constraint upgrade method */
232typedef struct
233{
234 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
235 int priority; /**< priority of upgrading method */
236 SCIP_Bool active; /**< is upgrading enabled */
238
239/** constraint handler data */
240struct SCIP_ConshdlrData
241{
242 /* nonlinear handler */
243 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
244 int nnlhdlrs; /**< number of nonlinear handlers */
245 int nlhdlrssize; /**< size of nlhdlrs array */
246 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
247 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
248 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
249
250 /* constraint upgrades */
251 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
252 int consupgradessize; /**< size of consupgrades array */
253 int nconsupgrades; /**< number of constraint upgrade methods */
254
255 /* other plugins */
256 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
257 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
258 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
259
260 /* tags and counters */
261 int auxvarid; /**< unique id for the next auxiliary variable */
262 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
263 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
264 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
265 unsigned int enforound; /**< total number of enforcement calls, including current one */
266 int lastconsindex; /**< last used consindex, plus one */
267
268 /* activity intervals and domain propagation */
269 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
270 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
271 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
272 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
273 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
274
275 /* parameters */
276 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
277 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
278 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
279 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
280 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
281 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
282 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
283 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
284 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
285 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
286 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
287 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
288 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
289 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
290 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
291 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
292 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
293 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
294 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
295 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
296 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 */
297 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
298 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) */
299 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
300 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
301 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
302 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
303 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
304 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
305 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
306 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
307 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
308 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
309 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
310 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
311 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) */
312 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
313
314 /* statistics */
315 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
316 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
317 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 */
318 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
319 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
320 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
321 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
322 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
323
324 /* facets of envelops of vertex-polyhedral functions */
325 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
326 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
327
328 /* hashing of bilinear terms */
329 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
330 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
331 int nbilinterms; /**< total number of bilinear terms */
332 int bilintermssize; /**< size of bilinterms array */
333 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
334
335 /* branching */
336 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
337 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
338
339 /* misc */
340 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
341 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
342 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
343};
344
345/** branching candidate with various scores */
346typedef struct
347{
348 SCIP_EXPR* expr; /**< expression that holds branching candidate */
349 SCIP_Real auxviol; /**< aux-violation score of candidate */
350 SCIP_Real domain; /**< domain score of candidate */
351 SCIP_Real dual; /**< dual score of candidate */
352 SCIP_Real pscost; /**< pseudo-cost score of candidate */
353 SCIP_Real vartype; /**< variable type score of candidate */
354 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
355} BRANCHCAND;
356
357/*
358 * Local methods
359 */
360
361/* forward declaration */
362static
364 SCIP* scip, /**< SCIP data structure */
365 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
366 SCIP_EXPR* rootexpr, /**< expression */
367 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
368 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
369 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
370 );
371
372/** frees auxiliary variables of expression, if any */
373static
375 SCIP* scip, /**< SCIP data structure */
376 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
377 )
378{
380
381 assert(scip != NULL);
382 assert(expr != NULL);
383
385 assert(mydata != NULL);
386
387 if( mydata->auxvar == NULL )
388 return SCIP_OKAY;
389
390 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
391
392 /* remove variable locks
393 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
394 */
395 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
396
397 /* release auxiliary variable */
398 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
399 assert(mydata->auxvar == NULL);
400
401 return SCIP_OKAY;
402}
403
404/** frees data used for enforcement of expression, that is, nonlinear handlers
405 *
406 * can also clear indicators whether expr needs enforcement methods, that is,
407 * free an associated auxiliary variable and reset the nactivityuses counts
408 */
409static
411 SCIP* scip, /**< SCIP data structure */
412 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
413 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
414 )
415{
417 int e;
418
420 assert(mydata != NULL);
421
422 if( freeauxvar )
423 {
424 /* free auxiliary variable */
425 SCIP_CALL( freeAuxVar(scip, expr) );
426 assert(mydata->auxvar == NULL);
427
428 /* reset count on activity and auxvar usage */
429 mydata->nactivityusesprop = 0;
430 mydata->nactivityusessepa = 0;
431 mydata->nauxvaruses = 0;
432 }
433
434 /* free data stored by nonlinear handlers */
435 for( e = 0; e < mydata->nenfos; ++e )
436 {
437 SCIP_NLHDLR* nlhdlr;
438
439 assert(mydata->enfos[e] != NULL);
440
441 nlhdlr = mydata->enfos[e]->nlhdlr;
442 assert(nlhdlr != NULL);
443
444 if( mydata->enfos[e]->issepainit )
445 {
446 /* call the separation deinitialization callback of the nonlinear handler */
447 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
448 mydata->enfos[e]->issepainit = FALSE;
449 }
450
451 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
452 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
453 {
454 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
455 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
456 }
457
458 /* free enfo data */
459 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
460 }
461
462 /* free array with enfo data */
464
465 /* we need to look at this expression in detect again */
466 mydata->nenfos = -1;
467
468 return SCIP_OKAY;
469}
470
471/** callback that frees data that this conshdlr stored in an expression */
472static
474{
475 assert(scip != NULL);
476 assert(expr != NULL);
477 assert(ownerdata != NULL);
478 assert(*ownerdata != NULL);
479
480 /* expression should not be locked anymore */
481 assert((*ownerdata)->nlockspos == 0);
482 assert((*ownerdata)->nlocksneg == 0);
483
484 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
485
486 /* expression should not be enforced anymore */
487 assert((*ownerdata)->nenfos <= 0);
488 assert((*ownerdata)->auxvar == NULL);
489
490 if( SCIPisExprVar(scip, expr) )
491 {
492 SCIP_CONSHDLRDATA* conshdlrdata;
493 SCIP_VAR* var;
494
495 /* there should be no constraints left that still use this variable */
496 assert((*ownerdata)->nconss == 0);
497 /* thus, there should also be no variable event catched (via this exprhdlr) */
498 assert((*ownerdata)->filterpos == -1);
499
500 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
501
502 /* update var2expr hashmap in conshdlrdata */
503 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
504 assert(conshdlrdata != NULL);
505
506 var = SCIPgetVarExprVar(expr);
507 assert(var != NULL);
508
509 /* remove var -> expr map from hashmap if present
510 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
511 * if variable-expression stored for var is different, then also do nothing)
512 */
513 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
514 {
515 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
516 }
517 }
518
519 SCIPfreeBlockMemory(scip, ownerdata);
520
521 return SCIP_OKAY;
522}
523
524static
526{ /*lint --e{715}*/
527 assert(ownerdata != NULL);
528
529 /* print nl handlers associated to expr */
530 if( ownerdata->nenfos > 0 )
531 {
532 int i;
533 SCIPinfoMessage(scip, file, " {");
534
535 for( i = 0; i < ownerdata->nenfos; ++i )
536 {
537 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
538 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
539 SCIPinfoMessage(scip, file, "a");
540 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
541 SCIPinfoMessage(scip, file, "u");
542 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
543 SCIPinfoMessage(scip, file, "o");
544 if( i < ownerdata->nenfos-1 )
545 SCIPinfoMessage(scip, file, ", ");
546 }
547
548 SCIPinfoMessage(scip, file, "}");
549 }
550
551 /* print aux var associated to expr */
552 if( ownerdata->auxvar != NULL )
553 {
554 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
555 }
556 SCIPinfoMessage(scip, file, "\n");
557
558 return SCIP_OKAY;
559}
560
561/** possibly reevaluates and then returns the activity of the expression
562 *
563 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
564 */
565static
567{
568 SCIP_CONSHDLRDATA* conshdlrdata;
569
570 assert(scip != NULL);
571 assert(expr != NULL);
572 assert(ownerdata != NULL);
573
574 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
575 assert(conshdlrdata != NULL);
576
577 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
578 {
579 /* update activity of expression */
580 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
581
582 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
583 }
584
585 return SCIP_OKAY;
586}
587
588/** callback that creates data that this conshdlr wants to store in an expression */
589static
591{
592 assert(scip != NULL);
593 assert(expr != NULL);
594 assert(ownerdata != NULL);
595
597 (*ownerdata)->nenfos = -1;
598 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
599
600 if( SCIPisExprVar(scip, expr) )
601 {
602 SCIP_CONSHDLRDATA* conshdlrdata;
603 SCIP_VAR* var;
604
605 (*ownerdata)->filterpos = -1;
606
607 /* add to var2expr hashmap if not having expr for var yet */
608
609 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
610 assert(conshdlrdata != NULL);
611
612 var = SCIPgetVarExprVar(expr);
613
614 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
615 {
616 /* store the variable expression in the hashmap */
617 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
618 }
619 else
620 {
621 /* if expr was just created, then it shouldn't already be stored as image of var */
622 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
623 }
624 }
625 else
626 {
627 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
628 (*ownerdata)->filterpos = -2;
629 }
630
634
635 return SCIP_OKAY;
636}
637
638/** creates a variable expression or retrieves from hashmap in conshdlr data */
639static
641 SCIP* scip, /**< SCIP data structure */
642 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
643 SCIP_EXPR** expr, /**< pointer where to store expression */
644 SCIP_VAR* var /**< variable to be stored */
645 )
646{
647 assert(conshdlr != NULL);
648 assert(expr != NULL);
649 assert(var != NULL);
650
651 /* get variable expression representing the given variable if there is one already */
652 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
653
654 if( *expr == NULL )
655 {
656 /* create a new variable expression; this also captures the expression */
657 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
658 assert(*expr != NULL);
659 /* exprownerCreate should have added var->expr to var2expr */
660 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
661 }
662 else
663 {
664 /* only capture already existing expr to get a consistent uses-count */
665 SCIPcaptureExpr(*expr);
666 }
667
668 return SCIP_OKAY;
669}
670
671/* map var exprs to var-expr from var2expr hashmap */
672static
674{ /*lint --e{715}*/
676
677 assert(sourcescip != NULL);
683
684 /* do not provide map if not variable */
685 if( !SCIPisExprVar(sourcescip, sourceexpr) )
686 return SCIP_OKAY;
687
689
690 return SCIP_OKAY;
691}
692
693/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
694static
696{ /*lint --e{715}*/
698 SCIP_VAR* var;
699
700 assert(sourcescip != NULL);
706
707 /* do not provide map if not variable */
708 if( !SCIPisExprVar(sourcescip, sourceexpr) )
709 return SCIP_OKAY;
710
712 assert(var != NULL);
713
714 /* transform variable */
715 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
716 assert(var != NULL);
717
719
720 return SCIP_OKAY;
721}
722
723/** stores all variable expressions into a given constraint */
724static
726 SCIP* scip, /**< SCIP data structure */
727 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
728 SCIP_CONSDATA* consdata /**< constraint data */
729 )
730{
731 SCIP_CONSHDLRDATA* conshdlrdata;
732 int varexprssize;
733 int i;
734
735 assert(consdata != NULL);
736
737 /* skip if we have stored the variable expressions already */
738 if( consdata->varexprs != NULL )
739 return SCIP_OKAY;
740
741 assert(consdata->varexprs == NULL);
742 assert(consdata->nvarexprs == 0);
743
744 /* get an upper bound on number of variable expressions */
745 if( consdata->issimplified )
746 {
747 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
748 * so we cannot have more variable expression than the number of active variables
749 */
751 }
752 else
753 {
754 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
755 }
756
757 /* create array to store all variable expressions */
758 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
759
760 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
761 assert(varexprssize >= consdata->nvarexprs);
762
763 /* shrink array if there are less variables in the expression than in the problem */
764 if( varexprssize > consdata->nvarexprs )
765 {
766 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
767 }
768
769 conshdlrdata = SCIPconshdlrGetData(conshdlr);
770 assert(conshdlrdata != NULL);
771 assert(conshdlrdata->var2expr != NULL);
772
773 /* ensure that for every variable an entry exists in the var2expr hashmap
774 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
775 */
776 for( i = 0; i < consdata->nvarexprs; ++i )
777 {
778 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
779 {
780 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
781 }
782 }
783
784 return SCIP_OKAY;
785}
786
787/** frees all variable expression stored in storeVarExprs() */
788static
790 SCIP* scip, /**< SCIP data structure */
791 SCIP_CONSDATA* consdata /**< constraint data */
792 )
793{
794 int i;
795
796 assert(consdata != NULL);
797
798 /* skip if we have stored the variable expressions already*/
799 if( consdata->varexprs == NULL )
800 return SCIP_OKAY;
801
802 assert(consdata->varexprs != NULL);
803 assert(consdata->nvarexprs >= 0);
804
805 /* release variable expressions */
806 for( i = 0; i < consdata->nvarexprs; ++i )
807 {
808 assert(consdata->varexprs[i] != NULL);
809 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
810 assert(consdata->varexprs[i] == NULL);
811 }
812
813 /* free variable expressions */
814 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
815 consdata->varexprs = NULL;
816 consdata->nvarexprs = 0;
817
818 return SCIP_OKAY;
819}
820
821/** interval evaluation of variables as used in bound tightening
822 *
823 * Returns slightly relaxed local variable bounds of a variable as interval.
824 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
825 */
826static
828{
830 SCIP_CONSHDLRDATA* conshdlrdata;
831 SCIP_Real lb;
832 SCIP_Real ub;
833
834 assert(scip != NULL);
835 assert(var != NULL);
836
837 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
838 assert(conshdlrdata != NULL);
839
840 if( conshdlrdata->globalbounds )
841 {
844 }
845 else
846 {
849 }
850 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
851
852 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
854 {
855 lb = EPSROUND(lb, 0.0); /*lint !e835*/
856 ub = EPSROUND(ub, 0.0); /*lint !e835*/
857 }
858
859 /* integer variables should always have integral bounds in SCIP */
860 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
861 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
862
863 switch( conshdlrdata->varboundrelax )
864 {
865 case 'n' : /* no relaxation */
866 break;
867
868 case 'a' : /* relax by absolute value */
869 {
870 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
872 break;
873
874 if( !SCIPisInfinity(scip, -lb) )
875 {
876 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
877 SCIP_Real bnd = floor(lb);
878 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
879 }
880
881 if( !SCIPisInfinity(scip, ub) )
882 {
883 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
884 SCIP_Real bnd = ceil(ub);
885 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
886 }
887
888 break;
889 }
890
891 case 'b' : /* relax always by absolute value */
892 {
893 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
895 break;
896
897 if( !SCIPisInfinity(scip, -lb) )
898 lb -= conshdlrdata->varboundrelaxamount;
899
900 if( !SCIPisInfinity(scip, ub) )
901 ub += conshdlrdata->varboundrelaxamount;
902
903 break;
904 }
905
906 case 'r' : /* relax by relative value */
907 {
908 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
910 break;
911
912 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
913 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
914 * further, do not relax beyond next integer value
915 */
916 if( !SCIPisInfinity(scip, -lb) )
917 {
918 SCIP_Real bnd = floor(lb);
919 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
920 }
921
922 if( !SCIPisInfinity(scip, ub) )
923 {
924 SCIP_Real bnd = ceil(ub);
925 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
926 }
927
928 break;
929 }
930
931 default :
932 {
933 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
934 SCIPABORT();
935 break;
936 }
937 }
938
939 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
942 assert(lb <= ub);
943
945
946 return interval;
947}
948
949/** compares two nonlinear constraints by its index
950 *
951 * Usable as compare operator in array sort functions.
952 */
953static
964
965/** processes variable fixing or bound change event */
966static
968{ /*lint --e{715}*/
969 SCIP_EVENTTYPE eventtype;
970 SCIP_EXPR* expr;
971 SCIP_EXPR_OWNERDATA* ownerdata;
972
973 eventtype = SCIPeventGetType(event);
975
976 assert(eventdata != NULL);
977 expr = (SCIP_EXPR*) eventdata;
978 assert(SCIPisExprVar(scip, expr));
979
980 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
984
985 ownerdata = SCIPexprGetOwnerData(expr);
986 assert(ownerdata != NULL);
987 /* we only catch varevents for variables in constraints, so there should be constraints */
988 assert(ownerdata->nconss > 0);
989 assert(ownerdata->conss != NULL);
990
991 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
992 * - propagation can only find something new if a bound was tightened
993 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
994 * and we look at global changes (that is, we are not looking at boundchanges in probing)
995 */
997 {
998 SCIP_CONSDATA* consdata;
999 int c;
1000
1001 for( c = 0; c < ownerdata->nconss; ++c )
1002 {
1003 assert(ownerdata->conss[c] != NULL);
1004 consdata = SCIPconsGetData(ownerdata->conss[c]);
1005
1006 /* if bound tightening, then mark constraints to be propagated again
1007 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1008 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1009 * the locks don't help since they are not available separately for each constraint
1010 */
1011 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1012 {
1013 consdata->ispropagated = FALSE;
1014 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1015 }
1016
1017 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1019 {
1020 consdata->issimplified = FALSE;
1021 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1022 }
1023 }
1024 }
1025
1026 /* update curboundstag, lastboundrelax, and expr activity */
1027 if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1028 {
1029 SCIP_CONSHDLRDATA* conshdlrdata;
1030 SCIP_INTERVAL activity;
1031
1032 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1033 assert(conshdlrdata != NULL);
1034
1035 /* increase tag on bounds */
1036 ++conshdlrdata->curboundstag;
1037 assert(conshdlrdata->curboundstag > 0);
1038
1039 /* remember also if we relaxed bounds now */
1040 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1041 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1042
1043 /* update the activity of the var-expr here immediately
1044 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1045 */
1046 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1047 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1048#ifdef DEBUG_PROP
1049 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1050#endif
1051 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1052 }
1053
1054 return SCIP_OKAY;
1055}
1056
1057/** registers event handler to catch variable events on variable
1058 *
1059 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1060 * When an event occurs, all stored constraints are notified.
1061 */
1062static
1064 SCIP* scip, /**< SCIP data structure */
1065 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1066 SCIP_EXPR* expr, /**< variable expression */
1067 SCIP_CONS* cons /**< nonlinear constraint */
1068 )
1069{
1070 SCIP_EXPR_OWNERDATA* ownerdata;
1071
1072 assert(eventhdlr != NULL);
1073 assert(expr != NULL);
1074 assert(SCIPisExprVar(scip, expr));
1075 assert(cons != NULL);
1076
1077 ownerdata = SCIPexprGetOwnerData(expr);
1078 assert(ownerdata != NULL);
1079
1080#ifndef NDEBUG
1081 /* assert that constraint does not double-catch variable */
1082 {
1083 int i;
1084 for( i = 0; i < ownerdata->nconss; ++i )
1085 assert(ownerdata->conss[i] != cons);
1086 }
1087#endif
1088
1089 /* append cons to ownerdata->conss */
1090 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1091 ownerdata->conss[ownerdata->nconss++] = cons;
1092 /* we're not capturing the constraint here to avoid circular references */
1093
1094 /* updated sorted flag */
1095 if( ownerdata->nconss <= 1 )
1096 ownerdata->consssorted = TRUE;
1097 else if( ownerdata->consssorted )
1098 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1099
1100 /* catch variable events, if not done so yet (first constraint) */
1101 if( ownerdata->filterpos < 0 )
1102 {
1103 SCIP_EVENTTYPE eventtype;
1104
1105 assert(ownerdata->nconss == 1);
1106
1108
1109 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1110 assert(ownerdata->filterpos >= 0);
1111 }
1112
1113 return SCIP_OKAY;
1114}
1115
1116/** catch variable events */
1117static
1119 SCIP* scip, /**< SCIP data structure */
1120 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1121 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1122 )
1123{
1124 SCIP_CONSHDLRDATA* conshdlrdata;
1125 SCIP_CONSDATA* consdata;
1126 SCIP_EXPR* expr;
1127 int i;
1128
1129 assert(eventhdlr != NULL);
1130 assert(cons != NULL);
1131
1132 consdata = SCIPconsGetData(cons);
1133 assert(consdata != NULL);
1134 assert(consdata->varexprs != NULL);
1135 assert(consdata->nvarexprs >= 0);
1136
1137 /* check if we have catched variable events already */
1138 if( consdata->catchedevents )
1139 return SCIP_OKAY;
1140
1141 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1142 assert(conshdlrdata != NULL);
1143#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1144 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1145#endif
1146
1147 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1148
1149 for( i = 0; i < consdata->nvarexprs; ++i )
1150 {
1151 expr = consdata->varexprs[i];
1152
1153 assert(expr != NULL);
1154 assert(SCIPisExprVar(scip, expr));
1155
1156 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1157
1158 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1159 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1160 */
1161 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1162 {
1163 SCIP_INTERVAL activity;
1164 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1165 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1166 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1167#ifdef DEBUG_PROP
1168 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1169#endif
1170 }
1171 }
1172
1173 consdata->catchedevents = TRUE;
1174
1175 return SCIP_OKAY;
1176}
1177
1178/** unregisters event handler to catch variable events on variable
1179 *
1180 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1181 * If this was the last constraint, then the event handler is unregistered for this variable.
1182 */
1183static
1185 SCIP* scip, /**< SCIP data structure */
1186 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1187 SCIP_EXPR* expr, /**< variable expression */
1188 SCIP_CONS* cons /**< expr constraint */
1189 )
1190{
1191 SCIP_EXPR_OWNERDATA* ownerdata;
1192 int pos;
1193
1194 assert(eventhdlr != NULL);
1195 assert(expr != NULL);
1196 assert(SCIPisExprVar(scip, expr));
1197 assert(cons != NULL);
1198
1199 ownerdata = SCIPexprGetOwnerData(expr);
1200 assert(ownerdata != NULL);
1201 assert(ownerdata->nconss > 0);
1202
1203 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1204 {
1205 pos = ownerdata->nconss-1;
1206 }
1207 else
1208 {
1209 if( !ownerdata->consssorted )
1210 {
1211 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1212 ownerdata->consssorted = TRUE;
1213 }
1214
1215 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1216 {
1217 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1218 return SCIP_ERROR;
1219 }
1220 assert(pos >= 0 && pos < ownerdata->nconss);
1221 }
1222 assert(ownerdata->conss[pos] == cons);
1223
1224 /* move last constraint into position of removed constraint */
1225 if( pos < ownerdata->nconss-1 )
1226 {
1227 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1228 ownerdata->consssorted = FALSE;
1229 }
1230 --ownerdata->nconss;
1231
1232 /* drop variable events if that was the last constraint */
1233 if( ownerdata->nconss == 0 )
1234 {
1235 SCIP_EVENTTYPE eventtype;
1236
1237 assert(ownerdata->filterpos >= 0);
1238
1240
1241 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1242 ownerdata->filterpos = -1;
1243 }
1244
1245 return SCIP_OKAY;
1246}
1247
1248/** drop variable events */
1249static
1251 SCIP* scip, /**< SCIP data structure */
1252 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1253 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1254 )
1255{
1256 SCIP_CONSDATA* consdata;
1257 int i;
1258
1259 assert(eventhdlr != NULL);
1260 assert(cons != NULL);
1261
1262 consdata = SCIPconsGetData(cons);
1263 assert(consdata != NULL);
1264
1265 /* check if we have catched variable events already */
1266 if( !consdata->catchedevents )
1267 return SCIP_OKAY;
1268
1269 assert(consdata->varexprs != NULL);
1270 assert(consdata->nvarexprs >= 0);
1271
1272 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1273
1274 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1275 {
1276 assert(consdata->varexprs[i] != NULL);
1277
1278 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1279 }
1280
1281 consdata->catchedevents = FALSE;
1282
1283 return SCIP_OKAY;
1284}
1285
1286/** creates and captures a nonlinear constraint
1287 *
1288 * @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
1289 */
1290static
1292 SCIP* scip, /**< SCIP data structure */
1293 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1294 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1295 const char* name, /**< name of constraint */
1296 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1297 SCIP_Real lhs, /**< left hand side of constraint */
1298 SCIP_Real rhs, /**< right hand side of constraint */
1299 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1300 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1301 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1302 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1303 * Usually set to TRUE. */
1304 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1305 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1306 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1307 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1308 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1309 * Usually set to TRUE. */
1310 SCIP_Bool local, /**< is constraint only valid locally?
1311 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1312 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1313 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1314 * adds coefficients to this constraint. */
1315 SCIP_Bool dynamic, /**< is constraint subject to aging?
1316 * Usually set to FALSE. Set to TRUE for own cuts which
1317 * are separated as constraints. */
1318 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1319 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1320 )
1321{
1322 SCIP_CONSHDLRDATA* conshdlrdata;
1323 SCIP_CONSDATA* consdata;
1324
1325 assert(conshdlr != NULL);
1326 assert(expr != NULL);
1327
1328 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1329 assert(conshdlrdata != NULL);
1330
1331 if( local && SCIPgetDepth(scip) != 0 )
1332 {
1333 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1334 return SCIP_INVALIDCALL;
1335 }
1336
1337 /* TODO we should allow for non-initial nonlinear constraints */
1338 if( !initial )
1339 {
1340 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1341 return SCIP_INVALIDCALL;
1342 }
1343
1344 /* create constraint data */
1346
1347 if( copyexpr )
1348 {
1349 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1350 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1351 }
1352 else
1353 {
1354 consdata->expr = expr;
1355 SCIPcaptureExpr(consdata->expr);
1356 }
1357 consdata->lhs = lhs;
1358 consdata->rhs = rhs;
1359 consdata->consindex = conshdlrdata->lastconsindex++;
1360 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1361
1362 /* create constraint */
1363 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1364 local, modifiable, dynamic, removable, FALSE) );
1365
1366 return SCIP_OKAY;
1367}
1368
1369/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1370 *
1371 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1372 * Assume that f(x) is associated with auxiliary variable z.
1373 *
1374 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1375 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1376 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1377 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1378 *
1379 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1380 */
1381static
1383 SCIP* scip, /**< SCIP data structure */
1384 SCIP_EXPR* expr, /**< expression */
1385 SCIP_SOL* sol, /**< solution that has been evaluated */
1386 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1387 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1388 )
1389{
1390 SCIP_EXPR_OWNERDATA* ownerdata;
1391 SCIP_Real auxvarvalue;
1392
1393 assert(expr != NULL);
1394
1395 ownerdata = SCIPexprGetOwnerData(expr);
1396 assert(ownerdata != NULL);
1397 assert(ownerdata->auxvar != NULL);
1398
1399 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1400 {
1401 if( violunder != NULL )
1402 *violunder = TRUE;
1403 if( violover != NULL )
1404 *violover = TRUE;
1405 return SCIPinfinity(scip);
1406 }
1407
1408 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1409
1410 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1411 {
1412 if( violunder != NULL )
1413 *violunder = FALSE;
1414 if( violover != NULL )
1415 *violover = TRUE;
1416 return auxvarvalue - SCIPexprGetEvalValue(expr);
1417 }
1418
1419 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1420 {
1421 if( violunder != NULL )
1422 *violunder = TRUE;
1423 if( violover != NULL )
1424 *violover = FALSE;
1425 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1426 }
1427
1428 if( violunder != NULL )
1429 *violunder = FALSE;
1430 if( violover != NULL )
1431 *violover = FALSE;
1432 return 0.0;
1433}
1434
1435/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1436 *
1437 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1438 * Assume that f(w) is associated with auxiliary variable z.
1439 *
1440 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1441 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1442 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1443 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1444 *
1445 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1446 */
1447static
1449 SCIP* scip, /**< SCIP data structure */
1450 SCIP_EXPR* expr, /**< expression */
1451 SCIP_Real auxvalue, /**< value of f(w) */
1452 SCIP_SOL* sol, /**< solution that has been evaluated */
1453 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1454 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1455 )
1456{
1457 SCIP_EXPR_OWNERDATA* ownerdata;
1458 SCIP_Real auxvarvalue;
1459
1460 assert(expr != NULL);
1461
1462 ownerdata = SCIPexprGetOwnerData(expr);
1463 assert(ownerdata != NULL);
1464 assert(ownerdata->auxvar != NULL);
1465
1466 if( auxvalue == SCIP_INVALID )
1467 {
1468 if( violunder != NULL )
1469 *violunder = TRUE;
1470 if( violover != NULL )
1471 *violover = TRUE;
1472 return SCIPinfinity(scip);
1473 }
1474
1475 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1476
1477 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1478 {
1479 if( violunder != NULL )
1480 *violunder = FALSE;
1481 if( violover != NULL )
1482 *violover = TRUE;
1483 return auxvarvalue - auxvalue;
1484 }
1485
1486 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1487 {
1488 if( violunder != NULL )
1489 *violunder = TRUE;
1490 if( violover != NULL )
1491 *violover = FALSE;
1492 return auxvalue - auxvarvalue;
1493 }
1494
1495 if( violunder != NULL )
1496 *violunder = FALSE;
1497 if( violover != NULL )
1498 *violover = FALSE;
1499
1500 return 0.0;
1501}
1502
1503/** computes violation of a constraint */
1504static
1506 SCIP* scip, /**< SCIP data structure */
1507 SCIP_CONS* cons, /**< constraint */
1508 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1509 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1510 )
1511{
1512 SCIP_CONSDATA* consdata;
1513 SCIP_Real activity;
1514
1515 assert(scip != NULL);
1516 assert(cons != NULL);
1517
1518 consdata = SCIPconsGetData(cons);
1519 assert(consdata != NULL);
1520
1521 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1522 activity = SCIPexprGetEvalValue(consdata->expr);
1523
1524 /* consider constraint as violated if it is undefined in the current point */
1525 if( activity == SCIP_INVALID )
1526 {
1527 consdata->lhsviol = SCIPinfinity(scip);
1528 consdata->rhsviol = SCIPinfinity(scip);
1529 return SCIP_OKAY;
1530 }
1531
1532 /* compute violations */
1533 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1534 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1535
1536 return SCIP_OKAY;
1537}
1538
1539/** returns absolute violation of a constraint
1540 *
1541 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1542 */
1543static
1545 SCIP_CONS* cons /**< constraint */
1546 )
1547{
1548 SCIP_CONSDATA* consdata;
1549
1550 assert(cons != NULL);
1551
1552 consdata = SCIPconsGetData(cons);
1553 assert(consdata != NULL);
1554
1555 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1556}
1557
1558/** computes relative violation of a constraint
1559 *
1560 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1561 */
1562static
1564 SCIP* scip, /**< SCIP data structure */
1565 SCIP_CONS* cons, /**< constraint */
1566 SCIP_Real* viol, /**< buffer to store violation */
1567 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1568 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1569 )
1570{
1571 SCIP_CONSHDLR* conshdlr;
1572 SCIP_CONSHDLRDATA* conshdlrdata;
1573 SCIP_CONSDATA* consdata;
1574 SCIP_Real scale;
1575
1576 assert(cons != NULL);
1577 assert(viol != NULL);
1578
1579 conshdlr = SCIPconsGetHdlr(cons);
1580 assert(conshdlr != NULL);
1581
1582 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1583 assert(conshdlrdata != NULL);
1584
1585 *viol = getConsAbsViolation(cons);
1586
1587 if( conshdlrdata->violscale == 'n' )
1588 return SCIP_OKAY;
1589
1590 if( SCIPisInfinity(scip, *viol) )
1591 return SCIP_OKAY;
1592
1593 consdata = SCIPconsGetData(cons);
1594 assert(consdata != NULL);
1595
1596 if( conshdlrdata->violscale == 'a' )
1597 {
1598 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1599
1600 /* consider value of side that is violated for scaling, too */
1601 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1602 {
1603 assert(!SCIPisInfinity(scip, -consdata->lhs));
1604 scale = REALABS(consdata->lhs);
1605 }
1606 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1607 {
1608 assert(!SCIPisInfinity(scip, consdata->rhs));
1609 scale = REALABS(consdata->rhs);
1610 }
1611
1612 *viol /= scale;
1613 return SCIP_OKAY;
1614 }
1615
1616 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1617 assert(conshdlrdata->violscale == 'g');
1618 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1619 {
1620 /* we need the varexprs to conveniently access the gradient */
1621 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1622
1623 /* update cached value of norm of gradient */
1624 consdata->gradnorm = 0.0;
1625
1626 /* compute gradient */
1627 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1628
1629 /* gradient evaluation error -> no scaling */
1630 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1631 {
1632 int i;
1633 for( i = 0; i < consdata->nvarexprs; ++i )
1634 {
1635 SCIP_Real deriv;
1636
1637 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1638 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1639 if( deriv == SCIP_INVALID )
1640 {
1641 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1642 consdata->gradnorm = 0.0;
1643 break;
1644 }
1645
1646 consdata->gradnorm += deriv*deriv;
1647 }
1648 }
1649 consdata->gradnorm = sqrt(consdata->gradnorm);
1650 consdata->gradnormsoltag = soltag;
1651 }
1652
1653 *viol /= MAX(1.0, consdata->gradnorm);
1654
1655 return SCIP_OKAY;
1656}
1657
1658/** returns whether constraint is currently violated
1659 *
1660 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1661 */
1662static
1664 SCIP* scip, /**< SCIP data structure */
1665 SCIP_CONS* cons /**< constraint */
1666 )
1667{
1668 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1669}
1670
1671/** checks for a linear variable that can be increased or decreased without harming feasibility */
1672static
1674 SCIP* scip, /**< SCIP data structure */
1675 SCIP_CONS* cons /**< constraint */
1676 )
1677{
1678 SCIP_CONSDATA* consdata;
1679 int poslock;
1680 int neglock;
1681 int i;
1682
1683 assert(cons != NULL);
1684
1685 consdata = SCIPconsGetData(cons);
1686 assert(consdata != NULL);
1687
1688 consdata->linvarincr = NULL;
1689 consdata->linvardecr = NULL;
1690 consdata->linvarincrcoef = 0.0;
1691 consdata->linvardecrcoef = 0.0;
1692
1693 /* root expression is not a sum -> no unlocked linear variable available */
1694 if( !SCIPisExprSum(scip, consdata->expr) )
1695 return;
1696
1697 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1698 {
1699 SCIP_EXPR* child;
1700
1701 child = SCIPexprGetChildren(consdata->expr)[i];
1702 assert(child != NULL);
1703
1704 /* check whether the child is a variable expression */
1705 if( SCIPisExprVar(scip, child) )
1706 {
1707 SCIP_VAR* var = SCIPgetVarExprVar(child);
1708 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1709
1710 if( coef > 0.0 )
1711 {
1712 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1713 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1714 }
1715 else
1716 {
1717 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1718 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1719 }
1721
1723 {
1724 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1725 * if we have already one candidate, then take the one where the loss in the objective function is less
1726 */
1727 if( (consdata->linvardecr == NULL) ||
1728 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1729 {
1730 consdata->linvardecr = var;
1731 consdata->linvardecrcoef = coef;
1732 }
1733 }
1734
1736 {
1737 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1738 * if we have already one candidate, then take the one where the loss in the objective function is less
1739 */
1740 if( (consdata->linvarincr == NULL) ||
1741 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1742 {
1743 consdata->linvarincr = var;
1744 consdata->linvarincrcoef = coef;
1745 }
1746 }
1747 }
1748 }
1749
1750 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1751 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1752
1753 if( consdata->linvarincr != NULL )
1754 {
1755 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1756 }
1757 if( consdata->linvardecr != NULL )
1758 {
1759 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1760 }
1761}
1762
1763/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1764 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1765 *
1766 * The method assumes that this is always possible and that not all constraints are feasible already.
1767 */
1768static
1770 SCIP* scip, /**< SCIP data structure */
1771 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1772 SCIP_CONS** conss, /**< constraints to process */
1773 int nconss, /**< number of constraints */
1774 SCIP_SOL* sol, /**< solution to process */
1775 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1776 )
1777{
1778 SCIP_CONSHDLRDATA* conshdlrdata;
1780 int c;
1781
1782 assert(scip != NULL);
1783 assert(conshdlr != NULL);
1784 assert(conss != NULL || nconss == 0);
1785 assert(success != NULL);
1786
1787 *success = FALSE;
1788
1789 /* don't propose new solutions if not in presolve or solving */
1791 return SCIP_OKAY;
1792
1793 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1794 assert(conshdlrdata != NULL);
1795
1796 if( sol != NULL )
1797 {
1799 }
1800 else
1801 {
1803 }
1805 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1806 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1807
1808 for( c = 0; c < nconss; ++c )
1809 {
1810 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1811 SCIP_Real viol = 0.0;
1812 SCIP_Real delta;
1813 SCIP_Real gap;
1814
1815 assert(consdata != NULL);
1816
1817 /* get absolute violation and sign */
1818 if( consdata->lhsviol > SCIPfeastol(scip) )
1819 viol = consdata->lhsviol; /* lhs - activity */
1820 else if( consdata->rhsviol > SCIPfeastol(scip) )
1821 viol = -consdata->rhsviol; /* rhs - activity */
1822 else
1823 continue; /* constraint is satisfied */
1824
1825 if( consdata->linvarincr != NULL &&
1826 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1827 {
1828 SCIP_VAR* var = consdata->linvarincr;
1829
1830 /* compute how much we would like to increase var */
1831 delta = viol / consdata->linvarincrcoef;
1832 assert(delta > 0.0);
1833
1834 /* if var has an upper bound, may need to reduce delta */
1836 {
1838 delta = MIN(MAX(0.0, gap), delta);
1839 }
1840 if( SCIPisPositive(scip, delta) )
1841 {
1842 /* if variable is integral, round delta up so that it will still have an integer value */
1843 if( SCIPvarIsIntegral(var) )
1844 delta = SCIPceil(scip, delta);
1845
1846 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1847 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1848 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1849
1850 /* adjust constraint violation, if satisfied go on to next constraint */
1851 viol -= consdata->linvarincrcoef * delta;
1852 if( SCIPisZero(scip, viol) )
1853 continue;
1854 }
1855 }
1856
1857 assert(viol != 0.0);
1858 if( consdata->linvardecr != NULL &&
1859 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1860 {
1861 SCIP_VAR* var = consdata->linvardecr;
1862
1863 /* compute how much we would like to decrease var */
1864 delta = viol / consdata->linvardecrcoef;
1865 assert(delta < 0.0);
1866
1867 /* if var has a lower bound, may need to reduce delta */
1869 {
1871 delta = MAX(MIN(0.0, gap), delta);
1872 }
1873 if( SCIPisNegative(scip, delta) )
1874 {
1875 /* if variable is integral, round delta down so that it will still have an integer value */
1876 if( SCIPvarIsIntegral(var) )
1877 delta = SCIPfloor(scip, delta);
1878 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1879 /*lint --e{613} */
1880 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1881 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1882
1883 /* adjust constraint violation, if satisfied go on to next constraint */
1884 viol -= consdata->linvardecrcoef * delta;
1885 if( SCIPisZero(scip, viol) )
1886 continue;
1887 }
1888 }
1889
1890 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1891 break;
1892 }
1893
1894 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1895 * then pass it to the trysol heuristic
1896 */
1898 {
1899 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1900
1901 assert(conshdlrdata->trysolheur != NULL);
1902 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1903
1904 *success = TRUE;
1905 }
1906
1908
1909 return SCIP_OKAY;
1910}
1911
1912/** adds globally valid tight estimators in a given solution as cut to cutpool
1913 *
1914 * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1915 */
1916static
1918 SCIP* scip, /**< SCIP data structure */
1919 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1920 SCIP_CONS* cons, /**< constraint */
1921 SCIP_EXPR* expr, /**< expression */
1922 EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1923 SCIP_SOL* sol, /**< reference point where to estimate */
1924 SCIP_Bool overestimate, /**< whether to overestimate */
1925 SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1926 )
1927{
1928 SCIP_Bool estimatesuccess = FALSE;
1929 SCIP_Bool branchscoresuccess = FALSE;
1930 int minidx;
1931 int maxidx;
1932 int r;
1933
1934 assert(scip != NULL);
1935 assert(expr != NULL);
1936 assert(exprenfo != NULL);
1937 assert(rowpreps != NULL);
1938
1939 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1940 overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1941
1942 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1943 exprenfo->auxvalue, overestimate, overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1944
1947 assert(estimatesuccess == (minidx <= maxidx));
1948
1949 if( !estimatesuccess )
1950 {
1951 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1952 return SCIP_OKAY;
1953 }
1954
1955 for( r = minidx; r <= maxidx; ++r )
1956 {
1958 SCIP_ROW* row;
1959 SCIP_Real estimateval;
1960 int i;
1961
1963 assert(rowprep != NULL);
1965
1966 /* if estimators is only local valid, then skip */
1968 {
1969 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1971 continue;
1972 }
1973
1974 /* compute value of estimator */
1976 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1978
1979 /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1980 if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1981 (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1982 {
1983 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1985 continue;
1986 }
1987
1988 /* complete estimator to cut and clean it up */
1991
1992 /* if cleanup failed or rowprep is local now, then skip */
1994 {
1995 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1997 continue;
1998 }
1999
2000 /* generate row and add to cutpool */
2002
2003 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
2005
2006 SCIP_CALL( SCIPaddPoolCut(scip, row) );
2007 /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
2008
2009 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2011 }
2012
2014
2015 return SCIP_OKAY;
2016}
2017
2018/** adds globally valid tight estimators in a given solution as cuts to cutpool
2019 *
2020 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2021 * For convex constraints, we would achieve this by linearizing.
2022 * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2023 * use bound information and check whether the estimator is tight.
2024 *
2025 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2026 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2027 */
2028static
2030 SCIP* scip, /**< SCIP data structure */
2031 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2032 SCIP_CONS** conss, /**< constraints */
2033 int nconss, /**< number of constraints */
2034 SCIP_SOL* sol /**< reference point where to estimate */
2035 )
2036{
2037 SCIP_CONSDATA* consdata;
2038 SCIP_Longint soltag;
2040 SCIP_EXPR* expr;
2042 int c, e;
2043
2044 assert(scip != NULL);
2045 assert(conshdlr != NULL);
2046 assert(conss != NULL || nconss == 0);
2047
2048 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2049
2050 /* TODO probably we just evaluated all expressions when checking the sol before it was added
2051 * would be nice to recognize this and skip reevaluating
2052 */
2054
2056
2060
2061 for( c = 0; c < nconss; ++c )
2062 {
2063 /* skip constraints that are not enabled or deleted or have separation disabled */
2064 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2065 continue;
2066 assert(SCIPconsIsActive(conss[c]));
2067
2068 consdata = SCIPconsGetData(conss[c]);
2069 assert(consdata != NULL);
2070
2071 /* TODO we could remember for which constraints there is a chance that we would add anything,
2072 * i.e., there is some convex-like expression, and skip other constraints
2073 */
2074
2075 ENFOLOG(
2076 {
2077 int i;
2078 SCIPinfoMessage(scip, enfologfile, " constraint ");
2080 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2081 for( i = 0; i < consdata->nvarexprs; ++i )
2082 {
2083 SCIP_VAR* var;
2084 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2085 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2087 }
2088 })
2089
2090 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2091 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2092
2093 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2094 {
2095 SCIP_EXPR_OWNERDATA* ownerdata;
2096
2097 ownerdata = SCIPexprGetOwnerData(expr);
2098 assert(ownerdata != NULL);
2099
2100 /* we can only generate a cut from an estimator if there is an auxvar */
2101 if( ownerdata->auxvar == NULL )
2102 continue;
2103
2104 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2107 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2108
2109 /* generate cuts from estimators of each nonlinear handler that provides estimates */
2110 for( e = 0; e < ownerdata->nenfos; ++e )
2111 {
2112 SCIP_NLHDLR* nlhdlr;
2113
2114 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2115 assert(nlhdlr != NULL);
2116
2117 /* skip nlhdlr that does not implement estimate (so it does enfo) */
2118 if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2119 continue;
2120
2121 /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2122 * (because it uses activities on vars/auxvars)
2123 */
2124 if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2125 ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2126 continue;
2127
2128 /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2129 if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2130 continue;
2131
2132 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2133 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2134 ENFOLOG(
2135 SCIPinfoMessage(scip, enfologfile, " expr ");
2137 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2138 (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2139 )
2140 /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2141 assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2142
2143 /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2144 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2145 {
2146 SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2147 }
2148
2149 /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2150 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2151 {
2152 SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2153 }
2154 }
2155 }
2156 }
2157
2160
2161 return SCIP_OKAY;
2162}
2163
2164/** processes the event that a new primal solution has been found */
2165static
2167{
2168 SCIP_CONSHDLR* conshdlr;
2169 SCIP_CONSHDLRDATA* conshdlrdata;
2170 SCIP_SOL* sol;
2171
2172 assert(scip != NULL);
2173 assert(event != NULL);
2174 assert(eventdata != NULL);
2175 assert(eventhdlr != NULL);
2177
2178 conshdlr = (SCIP_CONSHDLR*)eventdata;
2179
2180 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2181 return SCIP_OKAY;
2182
2184 assert(sol != NULL);
2185
2186 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2187 assert(conshdlrdata != NULL);
2188
2189 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2190 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2191 * from the tree, but postprocessed via proposeFeasibleSolution
2192 */
2193 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2194 return SCIP_OKAY;
2195
2196 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2197
2199
2200 return SCIP_OKAY;
2201}
2202
2203/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2204 *
2205 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2206 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2207 *
2208 * Nothing will happen if SCIP is not in presolve or solve.
2209 */
2210static
2212 SCIP* scip, /**< SCIP data structure */
2213 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2214 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2215 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2216 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2217 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2218 )
2219{
2220 SCIP_VAR* var;
2221 SCIP_Bool tightenedlb;
2222 SCIP_Bool tightenedub;
2223 SCIP_Bool force;
2224
2225 assert(scip != NULL);
2226 assert(conshdlr != NULL);
2227 assert(expr != NULL);
2228 assert(cutoff != NULL);
2229
2230 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2232
2233 *cutoff = FALSE;
2234
2235 /* do not tighten variable in problem stage (important for unittests)
2236 * TODO put some kind of #ifdef UNITTEST around this
2237 */
2239 return SCIP_OKAY;
2240
2242 if( var == NULL )
2243 return SCIP_OKAY;
2244
2245 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2246 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2247
2248 /* try to tighten lower bound of (auxiliary) variable */
2249 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2250 if( tightenedlb )
2251 {
2252 if( ntightenings != NULL )
2253 ++*ntightenings;
2254 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2255 }
2256 if( *cutoff )
2257 {
2258 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2259 return SCIP_OKAY;
2260 }
2261
2262 /* try to tighten upper bound of (auxiliary) variable */
2263 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2264 if( tightenedub )
2265 {
2266 if( ntightenings != NULL )
2267 ++*ntightenings;
2268 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2269 }
2270 if( *cutoff )
2271 {
2272 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2273 return SCIP_OKAY;
2274 }
2275
2276 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2277 * that seems unnecessary and we could easily undo this here, e.g.,
2278 * if( tightenedlb ) expr->activity.inf = bounds.inf
2279 */
2280
2281 return SCIP_OKAY;
2282}
2283
2284/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2285 * and tries to tighten the bounds of the auxiliary variables accordingly
2286 */
2287static
2289 SCIP* scip, /**< SCIP data structure */
2290 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2291 SCIP_EXPR* rootexpr, /**< expression */
2292 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2293 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2294 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2295 )
2296{
2298 SCIP_EXPR* expr;
2299 SCIP_EXPR_OWNERDATA* ownerdata;
2300 SCIP_CONSHDLRDATA* conshdlrdata;
2301
2302 assert(scip != NULL);
2303 assert(rootexpr != NULL);
2304
2305 if( infeasible != NULL )
2306 *infeasible = FALSE;
2307 if( ntightenings != NULL )
2308 *ntightenings = 0;
2309
2310 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2311 assert(conshdlrdata != NULL);
2312
2313 /* if value is valid and empty, then we cannot improve, so do nothing */
2315 {
2316 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2317
2318 if( infeasible != NULL )
2319 *infeasible = TRUE;
2320
2321 /* just update tag to curboundstag */
2322 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2323
2324 return SCIP_OKAY;
2325 }
2326
2327 /* if value is up-to-date, then nothing to do */
2328 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2329 {
2330 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2331
2333
2334 return SCIP_OKAY;
2335 }
2336
2337 ownerdata = SCIPexprGetOwnerData(rootexpr);
2338 assert(ownerdata != NULL);
2339
2340 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2341 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2342 * during detect, we are in some in-between state where we may want to eval activity
2343 * on exprs that we did not notify about their activity usage
2344 */
2345 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2346 {
2347#ifdef DEBUG_PROP
2348 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2349#endif
2350 SCIPABORT();
2351 return SCIP_OKAY;
2352 }
2353
2357
2359 {
2360 switch( SCIPexpriterGetStageDFS(it) )
2361 {
2363 {
2364 /* skip child if it has been evaluated already */
2365 SCIP_EXPR* child;
2366
2368 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2369 {
2371 *infeasible = TRUE;
2372
2373 expr = SCIPexpriterSkipDFS(it);
2374 continue;
2375 }
2376
2377 break;
2378 }
2379
2381 {
2382 SCIP_INTERVAL activity;
2383
2384 /* we should not have entered this expression if its activity was already up to date */
2385 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2386
2387 ownerdata = SCIPexprGetOwnerData(expr);
2388 assert(ownerdata != NULL);
2389
2390 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2391 * so we can assume that the activity is up to date for all these variables
2392 * UNLESS we changed the method used to evaluate activity of variable expressions
2393 * or we currently use global bounds (varevents are catched for local bound changes only)
2394 */
2395 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2396 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2397 {
2398#ifndef NDEBUG
2400
2401 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2404#endif
2405#ifdef DEBUG_PROP
2406 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2407#endif
2408 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2409
2410 break;
2411 }
2412
2413 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2414 {
2415 /* start with entire activity if current one is invalid */
2417 }
2419 {
2420 /* If already empty, then don't try to compute even better activity.
2421 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2422 * so an assert(infeasible == NULL || *infeasible) should work here.
2423 * However, after reporting a cutoff due to expr->activity being empty,
2424 * SCIP may wander to a different node and call propagation again.
2425 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2426 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2427 * we will still have expr->activity being empty, but will have forgotten
2428 * that we found infeasibility here before (!2221#note_134120).
2429 * Therefore we just set *infeasibility=TRUE here and stop.
2430 */
2431 if( infeasible != NULL )
2432 *infeasible = TRUE;
2433 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2434 break;
2435 }
2436 else
2437 {
2438 /* start with current activity, since it is valid */
2439 activity = SCIPexprGetActivity(expr);
2440 }
2441
2442 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2443 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2444 {
2445#ifdef DEBUG_PROP
2446 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2447#endif
2448 break;
2449 }
2450
2451#ifdef DEBUG_PROP
2452 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2453 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2454 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2455#endif
2456
2457 /* run interval eval of nonlinear handlers or expression handler */
2458 if( ownerdata->nenfos > 0 )
2459 {
2460 SCIP_NLHDLR* nlhdlr;
2462 int e;
2463
2464 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2465 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2466 {
2467 /* skip nlhdlr if it does not want to participate in activity computation */
2468 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2469 continue;
2470
2471 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2472 assert(nlhdlr != NULL);
2473
2474 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2475 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2476 continue;
2477
2478 /* let nlhdlr evaluate current expression */
2479 nlhdlrinterval = activity;
2480 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2481 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2482#ifdef DEBUG_PROP
2483 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2484#endif
2485
2486 /* update activity by intersecting with computed activity */
2488#ifdef DEBUG_PROP
2489 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2490#endif
2491 }
2492 }
2493 else
2494 {
2495 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2497 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2498#ifdef DEBUG_PROP
2499 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2500#endif
2501
2502 /* update expr->activity by intersecting with computed activity */
2504#ifdef DEBUG_PROP
2505 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2506#endif
2507 }
2508
2509 /* if expression is integral, then we try to tighten the interval bounds a bit
2510 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2511 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2512 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2513 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2514 * (constants should be ok, too)
2515 */
2516 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2517 {
2518 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2519 activity.inf = SCIPceil(scip, activity.inf);
2520 if( activity.sup < SCIP_INTERVAL_INFINITY )
2521 activity.sup = SCIPfloor(scip, activity.sup);
2522#ifdef DEBUG_PROP
2523 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2524#endif
2525 }
2526
2527 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2528 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2529 */
2530 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2531 {
2532 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2533 SCIPintervalSetEmpty(&activity);
2534 }
2535
2536 /* now finally store activity in expr */
2537 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2538
2540 {
2541 if( infeasible != NULL )
2542 *infeasible = TRUE;
2543 }
2544 else if( tightenauxvars && ownerdata->auxvar != NULL )
2545 {
2546 SCIP_Bool tighteninfeasible;
2547
2548 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2549 if( tighteninfeasible )
2550 {
2551 if( infeasible != NULL )
2552 *infeasible = TRUE;
2553 SCIPintervalSetEmpty(&activity);
2554 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2555 }
2556 }
2557
2558 break;
2559 }
2560
2561 default:
2562 /* you should never be here */
2563 SCIPerrorMessage("unexpected iterator stage\n");
2564 SCIPABORT();
2565 break;
2566 }
2567
2568 expr = SCIPexpriterGetNext(it);
2569 }
2570
2572
2573 return SCIP_OKAY;
2574}
2575
2576/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2577 *
2578 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2579 *
2580 * If `subsetsufficient` is FALSE, then we require
2581 * - a change from an unbounded interval to a bounded one, or
2582 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2583 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2584 */
2585static
2587 SCIP* scip, /**< SCIP data structure */
2588 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2589 SCIP_INTERVAL newinterval, /**< new interval */
2590 SCIP_INTERVAL oldinterval /**< old interval */
2591 )
2592{
2593 assert(scip != NULL);
2596
2597 if( subsetsufficient )
2598 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2600
2601 /* check whether lower bound of interval becomes finite */
2603 return TRUE;
2604
2605 /* check whether upper bound of interval becomes finite */
2607 return TRUE;
2608
2609 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2611 return TRUE;
2612
2613 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2615 return TRUE;
2616
2617 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2619 return TRUE;
2620
2621 return FALSE;
2622}
2623
2624/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2625 *
2626 * The expression will be traversed in breadth first search by using this queue.
2627 *
2628 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2629 * forwardPropExpr() before calling this function.
2630 *
2631 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2632 */
2633static
2635 SCIP* scip, /**< SCIP data structure */
2636 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2637 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2638 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2639 )
2640{
2641 SCIP_CONSHDLRDATA* conshdlrdata;
2642 SCIP_EXPR* expr;
2643 SCIP_EXPR_OWNERDATA* ownerdata;
2644
2645 assert(infeasible != NULL);
2647
2648 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2649 assert(conshdlrdata != NULL);
2650
2651 *ntightenings = 0;
2652
2653 /* main loop that calls reverse propagation for expressions on the queue
2654 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2655 */
2656 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2657 {
2658 SCIP_INTERVAL propbounds;
2659 int e;
2660
2661 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2662 assert(expr != NULL);
2663
2664 ownerdata = SCIPexprGetOwnerData(expr);
2665 assert(ownerdata != NULL);
2666
2667 assert(ownerdata->inpropqueue);
2668 /* mark that the expression is not in the queue anymore */
2669 ownerdata->inpropqueue = FALSE;
2670
2671 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2672 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2673 */
2674 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2675 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2676 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2677
2678 /* this intersects propbounds with activity and auxvar bounds
2679 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2680 * auxvar bounds separately, so disabling this for now
2681 */
2682#ifdef SCIP_DISABLED_CODE
2683 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2685 {
2686 *infeasible = TRUE;
2687 break;
2688 }
2689#else
2690 propbounds = ownerdata->propbounds;
2691#endif
2692
2693 if( ownerdata->nenfos > 0 )
2694 {
2695 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2696 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2697 {
2698 SCIP_NLHDLR* nlhdlr;
2699 int nreds;
2700
2701 /* skip nlhdlr if it does not want to participate in activity computation */
2702 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2703 continue;
2704
2705 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2706 assert(nlhdlr != NULL);
2707
2708 /* call the reverseprop of the nlhdlr */
2709#ifdef SCIP_DEBUG
2710 SCIPdebugMsg(scip, "call reverse propagation for ");
2711 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2712 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2713#endif
2714
2715 nreds = 0;
2716 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2717 assert(nreds >= 0);
2718 *ntightenings += nreds;
2719 }
2720 }
2722 {
2723 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2725 int c;
2726
2727#ifdef SCIP_DEBUG
2728 SCIPdebugMsg(scip, "call reverse propagation for ");
2729 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2730 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2731#endif
2732
2733 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2734 * been initialized in detectNlhdlr yet (nenfos < 0)
2735 */
2736 assert(ownerdata->nenfos < 0);
2737
2739 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2741
2742 /* call the reverseprop of the exprhdlr */
2743 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2744
2745 if( !*infeasible )
2746 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2747 {
2749 }
2750
2752 }
2753 }
2754
2755 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2756 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2757 {
2758 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2759 assert(expr != NULL);
2760
2761 ownerdata = SCIPexprGetOwnerData(expr);
2762 assert(ownerdata != NULL);
2763
2764 /* mark that the expression is not in the queue anymore */
2765 ownerdata->inpropqueue = FALSE;
2766 }
2767
2768 return SCIP_OKAY;
2769}
2770
2771/** calls domain propagation for a given set of constraints
2772 *
2773 * The algorithm alternates calls of forward and reverse propagation.
2774 * Forward propagation ensures that activity of expressions is up to date.
2775 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2776 * [lhs,rhs] interval as starting point.
2777 *
2778 * The propagation algorithm works as follows:
2779 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2780 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2781 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2782 * provide tighter bounds
2783 * 3. apply reverse propagation to all collected expressions; don't explore
2784 * sub-expressions which have not changed since the beginning of the propagation loop
2785 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2786 *
2787 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2788 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2789 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2790 *
2791 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2792 * e.g., try less to propagate on convex constraints?
2793 */
2794static
2796 SCIP* scip, /**< SCIP data structure */
2797 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2798 SCIP_CONS** conss, /**< constraints to propagate */
2799 int nconss, /**< total number of constraints */
2800 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2801 SCIP_RESULT* result, /**< pointer to store the result */
2802 int* nchgbds /**< buffer to add the number of changed bounds */
2803 )
2804{
2805 SCIP_CONSHDLRDATA* conshdlrdata;
2806 SCIP_CONSDATA* consdata;
2807 SCIP_EXPR_OWNERDATA* ownerdata;
2808 SCIP_Bool cutoff = FALSE;
2810 int ntightenings;
2811 int roundnr;
2813 int i;
2814
2815 assert(scip != NULL);
2816 assert(conshdlr != NULL);
2817 assert(conss != NULL);
2818 assert(nconss >= 0);
2819 assert(result != NULL);
2820 assert(nchgbds != NULL);
2821 assert(*nchgbds >= 0);
2822
2823 /* no constraints to propagate */
2824 if( nconss == 0 )
2825 {
2827 return SCIP_OKAY;
2828 }
2829
2830 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2831 assert(conshdlrdata != NULL);
2832#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2833 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2834#endif
2835 assert(!conshdlrdata->globalbounds);
2836
2838 roundnr = 0;
2839
2840 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2841 conshdlrdata->forceboundtightening = force;
2842
2843 /* invalidate all propbounds (probably not needed) */
2844 ++conshdlrdata->curpropboundstag;
2845
2846 /* create iterator that we will use if we need to look at all auxvars */
2847 if( conshdlrdata->propauxvars )
2848 {
2850 }
2851
2852 /* main propagation loop */
2853 do
2854 {
2855 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2856
2857 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2858
2859 /* apply forward propagation (update expression activities)
2860 * and add promising root expressions into queue for reversepropagation
2861 */
2862 for( i = 0; i < nconss; ++i )
2863 {
2864 consdata = SCIPconsGetData(conss[i]);
2865 assert(consdata != NULL);
2866
2867 /* skip deleted, non-active, or propagation-disabled constraints */
2868 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2869 continue;
2870
2871 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2872 * activity didn't change
2873 */
2874 if( consdata->ispropagated )
2875 continue;
2876
2877 /* update activities in expression */
2878 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2879 SCIPdebugPrintCons(scip, conss[i], NULL);
2880
2881 ntightenings = 0;
2882 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2884
2885 if( cutoff )
2886 {
2887 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2889 break;
2890 }
2891
2892 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2893
2894 /* 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 */
2895 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2896 {
2897 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2898 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2899 * so taking auxvar bounds is enough)
2900 */
2901 if( ownerdata->auxvar == NULL )
2902 {
2903 /* relax sides by SCIPepsilon() and handle infinite sides */
2904 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2905 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2906 SCIPintervalSetBounds(&conssides, lhs, rhs);
2907 }
2908 else
2909 {
2910 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2911 }
2913 }
2914 else
2915 {
2916 /* check whether bounds of any auxvar used in constraint provides a tightening
2917 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2918 * but skip exprs that have an auxvar, but do not participate in propagation
2919 */
2920 SCIP_EXPR* expr;
2921
2925 {
2926 ownerdata = SCIPexprGetOwnerData(expr);
2927 assert(ownerdata != NULL);
2928
2929 if( ownerdata->auxvar == NULL )
2930 continue;
2931
2932 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2933 continue;
2934
2935 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2937 }
2938 }
2939
2940 if( cutoff )
2941 {
2942 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2944 break;
2945 }
2946
2947 assert(ntightenings >= 0);
2948 if( ntightenings > 0 )
2949 {
2950 *nchgbds += ntightenings;
2952 }
2953
2954 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2955 consdata->ispropagated = TRUE;
2956 }
2957
2958 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2960 assert(ntightenings >= 0);
2961 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2962
2963 if( cutoff )
2964 {
2965 SCIPdebugMsg(scip, " -> cutoff\n");
2967 break;
2968 }
2969
2970 if( ntightenings > 0 )
2971 {
2972 *nchgbds += ntightenings;
2974 }
2975 }
2976 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2977
2978 if( conshdlrdata->propauxvars )
2979 {
2981 }
2982
2983 conshdlrdata->forceboundtightening = FALSE;
2984
2985 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2986 ++conshdlrdata->curpropboundstag;
2987
2988 return SCIP_OKAY;
2989}
2990
2991/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2992 *
2993 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2994 *
2995 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2996 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2997 */
2998static
3000 SCIP* scip, /**< SCIP data structure */
3001 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3002 SCIP_CONS** conss, /**< constraints to propagate */
3003 int nconss, /**< total number of constraints */
3004 SCIP_RESULT* result, /**< pointer to store the result */
3005 int* nchgbds /**< buffer to add the number of changed bounds */
3006 )
3007{
3008 SCIP_CONSDATA* consdata;
3010 SCIP_EXPR* expr;
3011 SCIP_EXPR_OWNERDATA* ownerdata;
3012 SCIP_Bool cutoff = FALSE;
3013 int ntightenings;
3014 int c;
3015 int e;
3016
3017 assert(scip != NULL);
3018 assert(conshdlr != NULL);
3019 assert(conss != NULL);
3020 assert(nconss >= 0);
3021 assert(result != NULL);
3022 assert(nchgbds != NULL);
3023 assert(*nchgbds >= 0);
3024
3025#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
3027#endif
3028 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3029 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3030
3032
3035
3036 for( c = 0; c < nconss && !cutoff; ++c )
3037 {
3038 /* skip deleted, non-active, or propagation-disabled constraints */
3039 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3040 continue;
3041
3042 consdata = SCIPconsGetData(conss[c]);
3043 assert(consdata != NULL);
3044
3045 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3046 {
3047 ownerdata = SCIPexprGetOwnerData(expr);
3048 assert(ownerdata != NULL);
3049
3050 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3051 * this will propagate the current activity
3052 */
3053 for( e = 0; e < ownerdata->nenfos; ++e )
3054 {
3055 SCIP_NLHDLR* nlhdlr;
3056 assert(ownerdata->enfos[e] != NULL);
3057
3058 nlhdlr = ownerdata->enfos[e]->nlhdlr;
3059 assert(nlhdlr != NULL);
3060 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3061 continue;
3062
3063 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3064 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3065 ntightenings = 0;
3066 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3068
3069 if( cutoff )
3070 {
3071 /* stop everything if we detected infeasibility */
3072 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3074 break;
3075 }
3076
3077 assert(ntightenings >= 0);
3078 if( ntightenings > 0 )
3079 {
3080 *nchgbds += ntightenings;
3082 }
3083 }
3084 }
3085 }
3086
3087 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3089 assert(ntightenings >= 0);
3090
3091 if( cutoff )
3092 {
3093 SCIPdebugMsg(scip, " -> cutoff\n");
3095 }
3096 else if( ntightenings > 0 )
3097 {
3098 *nchgbds += ntightenings;
3100 }
3101
3103
3104 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3105 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3106
3107 return SCIP_OKAY;
3108}
3109
3110/** propagates variable locks through expression and adds locks to variables */
3111static
3113 SCIP* scip, /**< SCIP data structure */
3114 SCIP_EXPR* expr, /**< expression */
3115 int nlockspos, /**< number of positive locks */
3116 int nlocksneg /**< number of negative locks */
3117 )
3118{
3119 SCIP_EXPR_OWNERDATA* ownerdata;
3122
3123 assert(expr != NULL);
3124
3125 /* if no locks, then nothing to propagate */
3126 if( nlockspos == 0 && nlocksneg == 0 )
3127 return SCIP_OKAY;
3128
3132 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3133
3134 /* store locks in root node */
3135 ituserdata.intvals[0] = nlockspos;
3136 ituserdata.intvals[1] = nlocksneg;
3138
3139 while( !SCIPexpriterIsEnd(it) )
3140 {
3141 /* collect locks */
3143 nlockspos = ituserdata.intvals[0];
3144 nlocksneg = ituserdata.intvals[1];
3145
3146 ownerdata = SCIPexprGetOwnerData(expr);
3147
3148 switch( SCIPexpriterGetStageDFS(it) )
3149 {
3151 {
3152 if( SCIPisExprVar(scip, expr) )
3153 {
3154 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3155 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3156 }
3157
3158 /* add locks to expression */
3159 ownerdata->nlockspos += nlockspos;
3160 ownerdata->nlocksneg += nlocksneg;
3161
3162 /* add monotonicity information if expression has been locked for the first time */
3163 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3165 {
3166 int i;
3167
3168 assert(ownerdata->monotonicity == NULL);
3169 assert(ownerdata->monotonicitysize == 0);
3170
3171 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3172 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3173
3174 /* store the monotonicity for each child */
3175 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3176 {
3177 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3178 }
3179 }
3180 break;
3181 }
3182
3184 {
3185 /* remove monotonicity information if expression has been unlocked */
3186 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3187 {
3188 assert(ownerdata->monotonicitysize > 0);
3189 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3190 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3191
3192 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3193 ownerdata->monotonicitysize = 0;
3194 }
3195 break;
3196 }
3197
3199 {
3200 SCIP_MONOTONE monotonicity;
3201
3202 /* get monotonicity of child */
3203 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3204 * SCIPcallExprMonotonicity
3205 */
3206 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3207
3208 /* compute resulting locks of the child expression */
3209 switch( monotonicity )
3210 {
3211 case SCIP_MONOTONE_INC:
3212 ituserdata.intvals[0] = nlockspos;
3213 ituserdata.intvals[1] = nlocksneg;
3214 break;
3215 case SCIP_MONOTONE_DEC:
3216 ituserdata.intvals[0] = nlocksneg;
3217 ituserdata.intvals[1] = nlockspos;
3218 break;
3220 ituserdata.intvals[0] = nlockspos + nlocksneg;
3221 ituserdata.intvals[1] = nlockspos + nlocksneg;
3222 break;
3224 ituserdata.intvals[0] = 0;
3225 ituserdata.intvals[1] = 0;
3226 break;
3227 }
3228 /* set locks in child expression */
3230
3231 break;
3232 }
3233
3234 default :
3235 /* you should never be here */
3236 SCIPABORT();
3237 break;
3238 }
3239
3240 expr = SCIPexpriterGetNext(it);
3241 }
3242
3244
3245 return SCIP_OKAY;
3246}
3247
3248/** main function for adding locks to expressions and variables
3249 *
3250 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3251 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3252 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3253 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3254 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3255 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3256 * which implies that updating the monotonicity information during the next locking of this expression does not
3257 * break existing locks.
3258 *
3259 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3260 * locks from an expression and repropagating them after the structural changes have been applied.
3261 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3262 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3263 */
3264static
3266 SCIP* scip, /**< SCIP data structure */
3267 SCIP_CONS* cons, /**< nonlinear constraint */
3268 int nlockspos, /**< number of positive rounding locks */
3269 int nlocksneg /**< number of negative rounding locks */
3270 )
3271{
3272 SCIP_CONSDATA* consdata;
3273
3274 assert(cons != NULL);
3275
3276 if( nlockspos == 0 && nlocksneg == 0 )
3277 return SCIP_OKAY;
3278
3279 consdata = SCIPconsGetData(cons);
3280 assert(consdata != NULL);
3281
3282 /* no constraint sides -> nothing to lock */
3283 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3284 return SCIP_OKAY;
3285
3286 /* remember locks */
3287 consdata->nlockspos += nlockspos;
3288 consdata->nlocksneg += nlocksneg;
3289
3290 assert(consdata->nlockspos >= 0);
3291 assert(consdata->nlocksneg >= 0);
3292
3293 /* compute locks for lock propagation */
3294 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3295 {
3296 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3297 }
3298 else if( !SCIPisInfinity(scip, consdata->rhs) )
3299 {
3300 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3301 }
3302 else
3303 {
3304 assert(!SCIPisInfinity(scip, -consdata->lhs));
3305 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3306 }
3307
3308 return SCIP_OKAY;
3309}
3310
3311/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3312static
3314 SCIP* scip, /**< SCIP data structure */
3315 SCIP_CONS* cons /**< nonlinear constraint */
3316 )
3317{
3318 SCIP_CONSDATA* consdata;
3319
3320 assert(scip != NULL);
3321 assert(cons != NULL);
3322
3323 consdata = SCIPconsGetData(cons);
3324 assert(consdata != NULL);
3325 assert(consdata->expr != NULL);
3326
3327 if( consdata->nlrow != NULL )
3328 {
3329 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3330 }
3331
3332 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3333 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3334 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3335
3336 if( SCIPisExprSum(scip, consdata->expr) )
3337 {
3338 /* if root is a sum, then split into linear and nonlinear terms */
3340 SCIP_EXPR* child;
3341 SCIP_Real* coefs;
3342 int i;
3343
3344 coefs = SCIPgetCoefsExprSum(consdata->expr);
3345
3346 /* constant term of sum */
3347 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3348
3349 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3351
3352 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3353 {
3354 child = SCIPexprGetChildren(consdata->expr)[i];
3355 if( SCIPisExprVar(scip, child) )
3356 {
3357 /* linear term */
3358 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3359 }
3360 else
3361 {
3362 /* nonlinear term */
3363 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3364 }
3365 }
3366
3368 {
3369 /* add expression to nlrow (this will make a copy) */
3370 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3371 }
3373 }
3374 else
3375 {
3376 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3377 }
3378
3379 return SCIP_OKAY;
3380}
3381
3382/** compares enfodata by enforcement priority of nonlinear handler
3383 *
3384 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3385 */
3386static
3409
3410/** install nlhdlrs in one expression */
3411static
3413 SCIP* scip, /**< SCIP data structure */
3414 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3415 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3416 )
3417{
3418 SCIP_EXPR_OWNERDATA* ownerdata;
3419 SCIP_CONSHDLRDATA* conshdlrdata;
3425 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3426 int enfossize; /* allocated length of expr->enfos array */
3427 int h;
3428
3429 assert(expr != NULL);
3430
3431 ownerdata = SCIPexprGetOwnerData(expr);
3432 assert(ownerdata != NULL);
3433
3434 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3435 assert(conshdlrdata != NULL);
3436 assert(conshdlrdata->auxvarid >= 0);
3437 assert(!conshdlrdata->indetect);
3438
3439 /* there should be no enforcer yet and detection should not even have considered expr yet */
3440 assert(ownerdata->nenfos < 0);
3441 assert(ownerdata->enfos == NULL);
3442
3443 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3444 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3445 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3446 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3447 * - if no one uses activity, then do not need activity methods
3448 */
3450 if( ownerdata->nauxvaruses == 0 )
3452 else
3453 {
3454 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3456 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3458 }
3459 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3461
3462 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3464
3465 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3467
3468 ownerdata->nenfos = 0;
3469 enfossize = 2;
3470 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3471 conshdlrdata->indetect = TRUE;
3472
3473 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3474 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3475 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3476 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3477 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3478
3479 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3480 {
3481 SCIP_NLHDLR* nlhdlr;
3482
3483 nlhdlr = conshdlrdata->nlhdlrs[h];
3484 assert(nlhdlr != NULL);
3485
3486 /* skip disabled nlhdlrs */
3487 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3488 continue;
3489
3490 /* call detect routine of nlhdlr */
3491 nlhdlrexprdata = NULL;
3494 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3495 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3496 /* coverity[forward_null] */
3497 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3498
3499 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3501
3502 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3504
3505 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3506 * They are also cleaned up here to ensure that only the needed methods are claimed.
3507 */
3509
3510 /* nlhdlr needs to participate for the methods it is enforcing */
3512
3514 {
3515 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3516 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3517
3518 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3519 if( nlhdlrexprdata != NULL )
3520 {
3521 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3522 }
3523 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3525
3526 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3527
3528 continue;
3529 }
3530
3531 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3532 SCIPnlhdlrGetName(nlhdlr),
3533 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3534 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3535 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3536
3537 /* store nlhdlr and its data */
3538 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3539 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3540 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3541 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3542 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3543 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3544 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3545 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3546 ownerdata->nenfos++;
3547
3548 /* update enforcement flags */
3550 }
3551
3552 conshdlrdata->indetect = FALSE;
3553
3554 /* stop if an enforcement method is missing but we are already in solving stage
3555 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3556 */
3558 {
3559 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3560 return SCIP_ERROR;
3561 }
3562
3563 assert(ownerdata->nenfos > 0);
3564
3565 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3566 if( ownerdata->nenfos > 1 )
3567 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3568
3569 /* resize enfos array to be nenfos long */
3570 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3571
3572 return SCIP_OKAY;
3573}
3574
3575/** detect nlhdlrs that can handle the expressions */
3576static
3578 SCIP* scip, /**< SCIP data structure */
3579 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3580 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3581 int nconss /**< total number of constraints */
3582 )
3583{
3584 SCIP_CONSHDLRDATA* conshdlrdata;
3585 SCIP_CONSDATA* consdata;
3586 SCIP_EXPR* expr;
3587 SCIP_EXPR_OWNERDATA* ownerdata;
3589 int i;
3590
3591 assert(conss != NULL || nconss == 0);
3592 assert(nconss >= 0);
3593 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 */
3594
3595 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3596 assert(conshdlrdata != NULL);
3597
3600
3602 {
3603 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3604 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3605 */
3607 conshdlrdata->globalbounds = TRUE;
3608 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3609 }
3610
3611 for( i = 0; i < nconss; ++i )
3612 {
3613 assert(conss != NULL && conss[i] != NULL);
3614
3615 consdata = SCIPconsGetData(conss[i]);
3616 assert(consdata != NULL);
3617 assert(consdata->expr != NULL);
3618
3619 /* if a constraint is separated, we currently need it to be initial, too
3620 * this is because INITLP will create the auxiliary variables that are used for any separation
3621 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3622 */
3623 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3624
3625 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3626 assert(ownerdata != NULL);
3627
3628 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3629 * then we would normally skip to run DETECT again
3630 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3631 * thus, if expr is the root expression, we rerun DETECT
3632 */
3633 if( ownerdata->nenfos > 0 )
3634 {
3635 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3636 assert(ownerdata->nenfos < 0);
3637 }
3638
3639 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3640 * this way we can treat the root expression like any other expression when enforcing via separation
3641 * if constraint will be propagated, then register activity usage of root expression
3642 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3643 */
3644 conshdlrdata->indetect = TRUE;
3647 SCIPconsIsPropagated(conss[i]),
3648 FALSE, FALSE) );
3649 conshdlrdata->indetect = FALSE;
3650
3651 /* compute integrality information for all subexpressions */
3652 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3653
3654 /* run detectNlhdlr on all expr where required */
3655 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3656 {
3657 ownerdata = SCIPexprGetOwnerData(expr);
3658 assert(ownerdata != NULL);
3659
3660 /* skip exprs that we already looked at */
3661 if( ownerdata->nenfos >= 0 )
3662 continue;
3663
3664 /* if there is use of the auxvar, then someone requires that
3665 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3666 * thus, we need to find nlhdlrs that separate or estimate
3667 * if there is use of the activity, then there is someone requiring that
3668 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3669 * thus, we need to find nlhdlrs that do interval-evaluation
3670 */
3671 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3672 {
3673 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3674
3675 assert(ownerdata->nenfos >= 0);
3676 }
3677 else
3678 {
3679 /* remember that we looked at this expression during detectNlhdlrs
3680 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3681 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3682 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3683 */
3684 ownerdata->nenfos = 0;
3685 }
3686 }
3687
3688 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3689 if( SCIPconsIsPropagated(conss[i]) )
3690 consdata->ispropagated = FALSE;
3691 }
3692
3694 {
3695 /* ensure that the local bounds are used again when reevaluating the expressions later;
3696 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3697 */
3699 conshdlrdata->globalbounds = FALSE;
3700 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3701 }
3702 else
3703 {
3704 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3706 }
3707
3709
3710 return SCIP_OKAY;
3711}
3712
3713/** initializes (pre)solving data of constraints
3714 *
3715 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3716 * not be modified.
3717 * In particular, this function
3718 * - runs the detection method of nlhldrs
3719 * - looks for unlocked linear variables
3720 * - checks curvature (if not in presolve)
3721 * - creates and add row to NLP (if not in presolve)
3722 *
3723 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3724 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3725 */
3726static
3728 SCIP* scip, /**< SCIP data structure */
3729 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3730 SCIP_CONS** conss, /**< constraints */
3731 int nconss /**< number of constraints */
3732 )
3733{
3734 int c;
3735
3736 for( c = 0; c < nconss; ++c )
3737 {
3738 /* check for a linear variable that can be increase or decreased without harming feasibility */
3739 findUnlockedLinearVar(scip, conss[c]);
3740
3742 {
3743 SCIP_CONSDATA* consdata;
3744 SCIP_Bool success = FALSE;
3745
3746 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3747 assert(consdata != NULL);
3748 assert(consdata->expr != NULL);
3749
3750 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3751 {
3752 /* call the curvature detection algorithm of the convex nonlinear handler
3753 * Check only for those curvature that may result in a convex inequality, i.e.,
3754 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3755 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3756 */
3757 if( !SCIPisInfinity(scip, -consdata->lhs) )
3758 {
3760 if( success )
3761 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3762 }
3763 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3764 {
3766 if( success )
3767 consdata->curv = SCIP_EXPRCURV_CONVEX;
3768 }
3769 }
3770 else
3771 {
3772 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3773 {
3774 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3775 consdata->curv = SCIP_EXPRCURV_LINEAR;
3776 }
3777 else
3778 {
3779 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3780 }
3781 }
3782 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3783
3784 /* add nlrow representation to NLP, if NLP had been constructed */
3786 {
3787 if( consdata->nlrow == NULL )
3788 {
3789 SCIP_CALL( createNlRow(scip, conss[c]) );
3790 assert(consdata->nlrow != NULL);
3791 }
3792 SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3793 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3794 }
3795 }
3796 }
3797
3798 /* register non linear handlers */
3799 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3800
3801 return SCIP_OKAY;
3802}
3803
3804/** deinitializes (pre)solving data of constraints
3805 *
3806 * This removes the initialization data created in initSolve().
3807 *
3808 * This function can be called in presolve and solve.
3809 *
3810 * TODO At the moment, it should not be called for a constraint if there are other constraints
3811 * that use the same expressions but still require their nlhdlr.
3812 * We should probably only decrement the auxvar and activity usage for the root expr and then
3813 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3814 */
3815static
3817 SCIP* scip, /**< SCIP data structure */
3818 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3819 SCIP_CONS** conss, /**< constraints */
3820 int nconss /**< number of constraints */
3821 )
3822{
3824 SCIP_EXPR* expr;
3825 SCIP_CONSDATA* consdata;
3826 SCIP_Bool rootactivityvalid;
3827 int c;
3828
3832
3833 /* call deinitialization callbacks of expression and nonlinear handlers
3834 * free nonlinear handlers information from expressions
3835 * remove auxiliary variables and nactivityuses counts from expressions
3836 */
3837 for( c = 0; c < nconss; ++c )
3838 {
3839 assert(conss != NULL);
3840 assert(conss[c] != NULL);
3841
3842 consdata = SCIPconsGetData(conss[c]);
3843 assert(consdata != NULL);
3844 assert(consdata->expr != NULL);
3845
3846 /* check and remember whether activity in root is valid */
3847 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3848
3849 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3850 {
3851 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3852
3853 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3854 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3855
3856 /* remove quadratic info */
3858
3859 if( rootactivityvalid )
3860 {
3861 /* ensure activity is valid if consdata->expr activity is valid
3862 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3863 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3864 * so this childs activity would be invalid, which can generate confusion
3865 */
3867 }
3868 }
3869
3870 if( consdata->nlrow != NULL )
3871 {
3872 /* remove row from NLP, if still in solving
3873 * if we are in exitsolve, the whole NLP will be freed anyway
3874 */
3876 {
3877 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3878 }
3879
3880 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3881 }
3882
3883 /* forget about linear variables that can be increased or decreased without harming feasibility */
3884 consdata->linvardecr = NULL;
3885 consdata->linvarincr = NULL;
3886
3887 /* forget about curvature */
3888 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3889 }
3890
3892
3893 return SCIP_OKAY;
3894}
3895
3896/** helper method to decide whether a given expression is product of at least two binary variables */
3897static
3899 SCIP* scip, /**< SCIP data structure */
3900 SCIP_EXPR* expr /**< expression */
3901 )
3902{
3903 int i;
3904
3905 assert(expr != NULL);
3906
3907 /* check whether the expression is a product */
3908 if( !SCIPisExprProduct(scip, expr) )
3909 return FALSE;
3910
3911 /* don't consider products with a coefficient != 1 and products with a single child
3912 * simplification will take care of this expression later
3913 */
3914 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3915 return FALSE;
3916
3917 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3918 {
3919 SCIP_EXPR* child;
3920 SCIP_VAR* var;
3921 SCIP_Real ub;
3922 SCIP_Real lb;
3923
3924 child = SCIPexprGetChildren(expr)[i];
3925 assert(child != NULL);
3926
3927 if( !SCIPisExprVar(scip, child) )
3928 return FALSE;
3929
3930 var = SCIPgetVarExprVar(child);
3931 lb = SCIPvarGetLbLocal(var);
3932 ub = SCIPvarGetUbLocal(var);
3933
3934 /* check whether variable is integer and has [0,1] as variable bounds */
3935 if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3936 return FALSE;
3937 }
3938
3939 return TRUE;
3940}
3941
3942/** helper method to collect all bilinear binary product terms */
3943static
3945 SCIP* scip, /**< SCIP data structure */
3946 SCIP_EXPR* sumexpr, /**< sum expression */
3947 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3948 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3949 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3950 int* nterms /**< pointer to store the total number of bilinear binary terms */
3951 )
3952{
3953 int i;
3954
3955 assert(sumexpr != NULL);
3957 assert(xs != NULL);
3958 assert(ys != NULL);
3959 assert(childidxs != NULL);
3960 assert(nterms != NULL);
3961
3962 *nterms = 0;
3963
3964 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3965 {
3966 SCIP_EXPR* child;
3967
3968 child = SCIPexprGetChildren(sumexpr)[i];
3969 assert(child != NULL);
3970
3971 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3972 {
3975
3976 assert(x != NULL);
3977 assert(y != NULL);
3978
3979 if( x != y )
3980 {
3981 xs[*nterms] = x;
3982 ys[*nterms] = y;
3983 childidxs[*nterms] = i;
3984 ++(*nterms);
3985 }
3986 }
3987 }
3988
3989 return SCIP_OKAY;
3990}
3991
3992/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3993static
3995 SCIP* scip, /**< SCIP data structure */
3996 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3997 SCIP_CONS* cons, /**< constraint */
3998 SCIP_VAR* facvar, /**< variable that has been factorized */
3999 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
4000 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
4001 int nvars, /**< total number of variables in sum_j c_ij x_j */
4002 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
4003 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4004 )
4005{
4006 SCIP_VAR* auxvar;
4008 SCIP_Real minact = 0.0;
4009 SCIP_Real maxact = 0.0;
4010 SCIP_Bool integral = TRUE;
4011 char name [SCIP_MAXSTRLEN];
4012 int i;
4013
4014 assert(facvar != NULL);
4015 assert(vars != NULL);
4016 assert(nvars > 1);
4017 assert(newexpr != NULL);
4018
4019 /* compute minimum and maximum activity of sum_j c_ij x_j */
4020 /* 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 */
4021 for( i = 0; i < nvars; ++i )
4022 {
4023 minact += MIN(coefs[i], 0.0);
4024 maxact += MAX(coefs[i], 0.0);
4025 integral = integral && SCIPisIntegral(scip, coefs[i]);
4026 }
4027 assert(minact <= maxact);
4028
4029 /* create and add auxiliary variable */
4030 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4032 SCIP_CALL( SCIPaddVar(scip, auxvar) );
4033
4034 /* create and add z - maxact x <= 0 */
4035 if( !SCIPisZero(scip, maxact) )
4036 {
4037 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4041 if( naddconss != NULL )
4042 ++(*naddconss);
4043 }
4044
4045 /* create and add 0 <= z - minact x */
4046 if( !SCIPisZero(scip, minact) )
4047 {
4048 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4052 if( naddconss != NULL )
4053 ++(*naddconss);
4054 }
4055
4056 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4057 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4059 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4060 if( !SCIPisZero(scip, minact) )
4061 {
4063 }
4066 if( naddconss != NULL )
4067 ++(*naddconss);
4068
4069 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4070 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4072 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4073 if( !SCIPisZero(scip, maxact) )
4074 {
4076 }
4079 if( naddconss != NULL )
4080 ++(*naddconss);
4081
4082 /* create variable expression */
4083 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4084
4085 /* release auxvar */
4086 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4087
4088 return SCIP_OKAY;
4089}
4090
4091/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4092static
4094 SCIP* scip, /**< SCIP data structure */
4095 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4096 SCIP_CONS* cons, /**< constraint */
4097 SCIP_EXPR* sumexpr, /**< expression */
4098 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4099 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4100 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4101 )
4102{
4103 SCIP_EXPR** exprs = NULL;
4104 SCIP_VAR** tmpvars = NULL;
4105 SCIP_VAR** vars = NULL;
4106 SCIP_VAR** xs = NULL;
4107 SCIP_VAR** ys = NULL;
4108 SCIP_Real* exprcoefs = NULL;
4109 SCIP_Real* tmpcoefs = NULL;
4110 SCIP_Real* sumcoefs;
4111 SCIP_Bool* isused = NULL;
4112 int* childidxs = NULL;
4113 int* count = NULL;
4114 int nchildren;
4115 int nexprs = 0;
4116 int nterms;
4117 int nvars;
4118 int ntotalvars;
4119 int i;
4120
4121 assert(sumexpr != NULL);
4122 assert(minterms > 1);
4123 assert(newexpr != NULL);
4124
4125 *newexpr = NULL;
4126
4127 /* check whether sumexpr is indeed a sum */
4128 if( !SCIPisExprSum(scip, sumexpr) )
4129 return SCIP_OKAY;
4130
4131 nchildren = SCIPexprGetNChildren(sumexpr);
4135
4136 /* check whether there are enough terms available */
4137 if( nchildren < minterms )
4138 return SCIP_OKAY;
4139
4140 /* allocate memory */
4141 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4142 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4144
4145 /* collect all bilinear binary product terms */
4147
4148 /* check whether there are enough terms available */
4149 if( nterms < minterms )
4150 goto TERMINATE;
4151
4152 /* store how often each variable appears in a bilinear binary product */
4156
4157 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4161
4162 for( i = 0; i < nterms; ++i )
4163 {
4164 int xidx;
4165 int yidx;
4166
4167 assert(xs[i] != NULL);
4168 assert(ys[i] != NULL);
4169
4170 xidx = SCIPvarGetIndex(xs[i]);
4172 yidx = SCIPvarGetIndex(ys[i]);
4174
4175 ++count[xidx];
4176 ++count[yidx];
4177
4178 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4179 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4180 }
4181
4182 /* sort variables; don't change order of count array because it depends on problem indices */
4183 {
4184 int* tmpcount;
4185
4189 }
4190
4191 for( i = 0; i < nvars; ++i )
4192 {
4193 SCIP_VAR* facvar = vars[i];
4194 int ntmpvars = 0;
4195 int j;
4196
4197 /* skip candidate if there are not enough terms left */
4198 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4199 continue;
4200
4201 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4202
4203 /* collect variables for x_i * sum_j c_ij x_j */
4204 for( j = 0; j < nterms; ++j )
4205 {
4206 int childidx = childidxs[j];
4207 assert(childidx >= 0 && childidx < nchildren);
4208
4209 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4210 {
4211 SCIP_Real coef;
4212 int xidx;
4213 int yidx;
4214
4215 coef = sumcoefs[childidx];
4216 assert(coef != 0.0);
4217
4218 /* collect corresponding variable */
4219 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4220 tmpcoefs[ntmpvars] = coef;
4221 ++ntmpvars;
4222
4223 /* update counters */
4224 xidx = SCIPvarGetIndex(xs[j]);
4226 yidx = SCIPvarGetIndex(ys[j]);
4228 --count[xidx];
4229 --count[yidx];
4230 assert(count[xidx] >= 0);
4231 assert(count[yidx] >= 0);
4232
4233 /* mark term to be used */
4234 isused[childidx] = TRUE;
4235 }
4236 }
4239 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4240
4241 /* create required constraints and store the generated expression */
4242 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4243 exprcoefs[nexprs] = 1.0;
4244 ++nexprs;
4245 }
4246
4247 /* factorization was only successful if at least one expression has been generated */
4248 if( nexprs > 0 )
4249 {
4250 int nexprsold = nexprs;
4251
4252 /* add all children of the sum that have not been used */
4253 for( i = 0; i < nchildren; ++i )
4254 {
4255 if( !isused[i] )
4256 {
4257 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4258 exprcoefs[nexprs] = sumcoefs[i];
4259 ++nexprs;
4260 }
4261 }
4262
4263 /* create a new sum expression */
4265
4266 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4267 for( i = 0; i < nexprsold; ++i )
4268 {
4269 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4270 }
4271 }
4272
4273TERMINATE:
4274 /* free memory */
4276 SCIPfreeBufferArrayNull(scip, &tmpvars);
4285
4286 return SCIP_OKAY;
4287}
4288
4289/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4290static
4292 SCIP* scip, /**< SCIP data structure */
4293 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4294 SCIP_EXPR* prodexpr, /**< product expression */
4295 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4296 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4297 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4298 )
4299{
4300 SCIP_VAR** vars;
4301 SCIP_CONS* cons;
4302 SCIP_Real* coefs;
4303 SCIP_VAR* w;
4304 char* name;
4305 int nchildren;
4306 int i;
4307
4308 assert(conshdlr != NULL);
4309 assert(prodexpr != NULL);
4310 assert(SCIPisExprProduct(scip, prodexpr));
4311 assert(newexpr != NULL);
4312
4313 nchildren = SCIPexprGetNChildren(prodexpr);
4314 assert(nchildren >= 2);
4315
4316 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4317 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4318 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4319 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4320
4321 /* prepare the names of the variable and the constraints */
4322 strcpy(name, "binreform");
4323 for( i = 0; i < nchildren; ++i )
4324 {
4326 coefs[i] = 1.0;
4327 assert(vars[i] != NULL);
4328 (void) strcat(name, "_");
4329 (void) strcat(name, SCIPvarGetName(vars[i]));
4330 }
4331
4332 /* create and add variable */
4333 SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4335 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4336
4337 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4338 if( nchildren == 2 && !empathy4and )
4339 {
4340 SCIP_VAR* x = vars[0];
4341 SCIP_VAR* y = vars[1];
4342
4343 assert(x != NULL);
4344 assert(y != NULL);
4345 assert(x != y);
4346
4347 /* create and add x - w >= 0 */
4348 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4349 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4350 SCIP_CALL( SCIPaddCons(scip, cons) );
4351 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4352
4353 /* create and add y - w >= 0 */
4354 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4355 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4356 SCIP_CALL( SCIPaddCons(scip, cons) );
4357 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4358
4359 /* create and add x + y - w <= 1 */
4360 vars[2] = w;
4361 coefs[2] = -1.0;
4362 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4363 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4364 SCIP_CALL( SCIPaddCons(scip, cons) );
4365 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4366
4367 /* update number of added constraints */
4368 if( naddconss != NULL )
4369 *naddconss += 3;
4370 }
4371 else
4372 {
4373 /* create, add, and release AND constraint */
4374 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4375 SCIP_CALL( SCIPaddCons(scip, cons) );
4376 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4377 SCIPdebugMsg(scip, " create AND constraint\n");
4378
4379 /* update number of added constraints */
4380 if( naddconss != NULL )
4381 *naddconss += 1;
4382 }
4383
4384 /* create variable expression */
4385 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4386
4387 /* release created variable */
4389
4390 /* free memory */
4391 SCIPfreeBufferArray(scip, &name);
4392 SCIPfreeBufferArray(scip, &coefs);
4394
4395 return SCIP_OKAY;
4396}
4397
4398/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4399static
4401 SCIP* scip, /**< SCIP data structure */
4402 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4403 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4404 SCIP_EXPR* prodexpr, /**< product expression */
4405 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4406 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4407 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4408 )
4409{
4410 SCIP_CONSHDLRDATA* conshdlrdata;
4411 int nchildren;
4412
4413 assert(prodexpr != NULL);
4414 assert(newexpr != NULL);
4415
4416 *newexpr = NULL;
4417
4418 /* only consider products of binary variables */
4419 if( !isBinaryProduct(scip, prodexpr) )
4420 return SCIP_OKAY;
4421
4422 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4423 assert(conshdlrdata != NULL);
4424 nchildren = SCIPexprGetNChildren(prodexpr);
4425 assert(nchildren >= 2);
4426
4427 /* check whether there is already an expression that represents the product */
4428 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4429 {
4430 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4431 assert(*newexpr != NULL);
4432
4433 /* capture expression */
4435 }
4436 else
4437 {
4438 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4439
4440 if( nchildren == 2 )
4441 {
4443 SCIP_VAR* x;
4444 SCIP_VAR* y;
4445 SCIP_Bool found_clique = FALSE;
4446 int c;
4447
4448 /* get variables from the product expression */
4449 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4450 assert(x != NULL);
4451 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4452 assert(y != NULL);
4453 assert(x != y);
4454
4455 /* first try to find a clique containing both variables */
4457
4458 /* look in cliques containing x */
4459 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4460 {
4461 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4462 {
4463 /* create zero value expression */
4464 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4465
4466 if( nchgcoefs != NULL )
4467 *nchgcoefs += 1;
4468
4470 break;
4471 }
4472
4473 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4474 {
4475 /* create variable expression for x */
4476 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4477
4478 if( nchgcoefs != NULL )
4479 *nchgcoefs += 2;
4480
4482 break;
4483 }
4484 }
4485
4486 if( !found_clique )
4487 {
4489
4490 /* look in cliques containing complement of x */
4491 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4492 {
4493 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4494 {
4495 /* create variable expression for y */
4496 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4497
4498 if( nchgcoefs != NULL )
4499 *nchgcoefs += 1;
4500
4502 break;
4503 }
4504
4505 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4506 {
4507 /* create sum expression */
4509 SCIP_Real sum_coefs[2];
4510 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4511 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4512 sum_coefs[0] = 1.0;
4513 sum_coefs[1] = 1.0;
4515
4518
4519 if( nchgcoefs != NULL )
4520 *nchgcoefs += 3;
4521
4523 break;
4524 }
4525 }
4526 }
4527
4528 /* if the variables are not in a clique, do standard linearization */
4529 if( !found_clique )
4530 {
4531 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4532 }
4533 }
4534 else
4535 {
4536 /* linearize binary product using an AND constraint because nchildren > 2 */
4537 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4538 }
4539
4540 /* hash variable expression */
4541 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4542 }
4543
4544 return SCIP_OKAY;
4545}
4546
4547/** helper function to replace binary products in a given constraint */
4548static
4550 SCIP* scip, /**< SCIP data structure */
4551 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4552 SCIP_CONS* cons, /**< constraint */
4553 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4554 SCIP_EXPRITER* it, /**< expression iterator */
4555 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4556 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4557 )
4558{
4559 SCIP_CONSHDLRDATA* conshdlrdata;
4560 SCIP_CONSDATA* consdata;
4561 SCIP_EXPR* expr;
4562
4563 assert(conshdlr != NULL);
4564 assert(cons != NULL);
4565 assert(exprmap != NULL);
4566 assert(it != NULL);
4567
4568 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4569 assert(conshdlrdata != NULL);
4570
4571 consdata = SCIPconsGetData(cons);
4572 assert(consdata != NULL);
4573 assert(consdata->expr != NULL);
4574
4575 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4576
4577 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4578 {
4581 int childexpridx;
4582
4586 assert(childexpr != NULL);
4587
4588 /* try to factorize variables in a sum expression that contains several products of binary variables */
4589 if( conshdlrdata->reformbinprodsfac > 1 )
4590 {
4591 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4592 }
4593
4594 /* try to create an expression that represents a product of binary variables */
4595 if( newexpr == NULL )
4596 {
4597 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4598 }
4599
4600 if( newexpr != NULL )
4601 {
4602 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4603
4604 /* replace product expression */
4606
4607 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4609
4610 /* mark the constraint to not be simplified anymore */
4611 consdata->issimplified = FALSE;
4612 }
4613 }
4614
4615 return SCIP_OKAY;
4616}
4617
4618/** reformulates products of binary variables during presolving in the following way:
4619 *
4620 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4621 * 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}:
4622 * \f[
4623 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4624 * \f]
4625 *
4626 * 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$.
4627 * These cliques allow for a better reformulation. There are four cases:
4628 *
4629 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4630 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4631 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4632 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4633 *
4634 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4635 *
4636 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4637 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4638 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4639 * Such a lower sum is reformulated with only one extra variable w_i:
4640 * \f{align}{
4641 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4642 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4643 * \text{minact}\, x_i & \leq w_i, \\
4644 * w_i &\leq \text{maxact}\, x_i, \\
4645 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4646 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4647 * \f}
4648 * 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
4649 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4650 * of terms are prioritized.
4651 */
4652static
4654 SCIP* scip, /**< SCIP data structure */
4655 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4656 SCIP_CONS** conss, /**< constraints */
4657 int nconss, /**< total number of constraints */
4658 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4659 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4660 )
4661{
4662 SCIP_CONSHDLRDATA* conshdlrdata;
4663 SCIP_HASHMAP* exprmap;
4665 int c;
4666
4667 assert(conshdlr != NULL);
4668
4669 /* no nonlinear constraints or binary variables -> skip */
4670 if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4671 return SCIP_OKAY;
4672 assert(conss != NULL);
4673
4674 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4675 assert(conshdlrdata != NULL);
4676
4677 /* create expression hash map */
4679
4680 /* create expression iterator */
4684
4685 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4686
4687 for( c = 0; c < nconss; ++c )
4688 {
4689 SCIP_CONSDATA* consdata;
4691
4692 assert(conss[c] != NULL);
4693
4694 consdata = SCIPconsGetData(conss[c]);
4695 assert(consdata != NULL);
4696
4697 /* try to reformulate the root expression */
4698 if( conshdlrdata->reformbinprodsfac > 1 )
4699 {
4700 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4701 }
4702
4703 /* release the root node if another expression has been found */
4704 if( newexpr != NULL )
4705 {
4706 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4707 consdata->expr = newexpr;
4708
4709 /* mark constraint to be not simplified anymore */
4710 consdata->issimplified = FALSE;
4711 }
4712
4713 /* replace each product of binary variables separately */
4714 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4715 }
4716
4717 /* free memory */
4718 SCIPhashmapFree(&exprmap);
4720
4721 return SCIP_OKAY;
4722}
4723
4724/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4725 *
4726 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4727 * Then scale by -1 if
4728 * - \f$n_+ < n_-\f$, or
4729 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4730 */
4731static
4733 SCIP* scip, /**< SCIP data structure */
4734 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4735 SCIP_CONS* cons, /**< nonlinear constraint */
4736 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4737 )
4738{
4739 SCIP_CONSDATA* consdata;
4740 int i;
4741
4742 assert(cons != NULL);
4743
4744 consdata = SCIPconsGetData(cons);
4745 assert(consdata != NULL);
4746
4747 if( SCIPisExprSum(scip, consdata->expr) )
4748 {
4749 SCIP_Real* coefs;
4750 SCIP_Real constant;
4751 int nchildren;
4752 int counter = 0;
4753
4754 coefs = SCIPgetCoefsExprSum(consdata->expr);
4755 constant = SCIPgetConstantExprSum(consdata->expr);
4756 nchildren = SCIPexprGetNChildren(consdata->expr);
4757
4758 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4759 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4760 {
4761 SCIP_EXPR* expr;
4762 expr = consdata->expr;
4763
4764 consdata->expr = SCIPexprGetChildren(expr)[0];
4765 assert(!SCIPisExprSum(scip, consdata->expr));
4766
4767 SCIPcaptureExpr(consdata->expr);
4768
4769 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4770 consdata->lhs = -consdata->lhs;
4771 consdata->rhs = -consdata->rhs;
4772
4773 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4774 *changed = TRUE;
4775 return SCIP_OKAY;
4776 }
4777
4778 /* compute n_+ - n_i */
4779 for( i = 0; i < nchildren; ++i )
4780 counter += coefs[i] > 0 ? 1 : -1;
4781
4782 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4783 {
4784 SCIP_EXPR* expr;
4785 SCIP_Real* newcoefs;
4786
4787 /* allocate memory */
4789
4790 for( i = 0; i < nchildren; ++i )
4791 newcoefs[i] = -coefs[i];
4792
4793 /* create a new sum expression */
4794 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4795
4796 /* replace expression in constraint data and scale sides */
4797 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4798 consdata->expr = expr;
4799 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4800 consdata->lhs = -consdata->lhs;
4801 consdata->rhs = -consdata->rhs;
4802
4803 /* free memory */
4805
4806 *changed = TRUE;
4807 }
4808 }
4809
4810 return SCIP_OKAY;
4811}
4812
4813/** forbid multiaggrations of variables that appear nonlinear in constraints */
4814static
4816 SCIP* scip, /**< SCIP data structure */
4817 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4818 SCIP_CONS** conss, /**< constraints */
4819 int nconss /**< number of constraints */
4820 )
4821{
4823 SCIP_CONSDATA* consdata;
4824 SCIP_EXPR* expr;
4825 int c;
4826
4827 assert(scip != NULL);
4828 assert(conshdlr != NULL);
4829
4830 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4831 return SCIP_OKAY;
4832
4835
4836 for( c = 0; c < nconss; ++c )
4837 {
4838 consdata = SCIPconsGetData(conss[c]);
4839 assert(consdata != NULL);
4840
4841 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4842 * i.e., skip children of sum that are variables
4843 */
4844 if( SCIPisExprSum(scip, consdata->expr) )
4845 {
4846 int i;
4847 SCIP_EXPR* child;
4848 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4849 {
4850 child = SCIPexprGetChildren(consdata->expr)[i];
4851
4852 /* skip variable expression, as they correspond to a linear term */
4853 if( SCIPisExprVar(scip, child) )
4854 continue;
4855
4856 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4857 if( SCIPisExprVar(scip, expr) )
4858 {
4860 }
4861 }
4862 }
4863 else
4864 {
4865 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4866 if( SCIPisExprVar(scip, expr) )
4867 {
4869 }
4870 }
4871 }
4872
4874
4875 return SCIP_OKAY;
4876}
4877
4878/** simplifies expressions and replaces common subexpressions for a set of constraints
4879 * @todo put the constant to the constraint sides
4880 */
4881static
4883 SCIP* scip, /**< SCIP data structure */
4884 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4885 SCIP_CONS** conss, /**< constraints */
4886 int nconss, /**< total number of constraints */
4887 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4888 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4889 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4890 int* naddconss, /**< counter to add number of added constraints, or NULL */
4891 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4892 )
4893{
4894 SCIP_CONSHDLRDATA* conshdlrdata;
4895 SCIP_CONSDATA* consdata;
4896 int* nlockspos;
4897 int* nlocksneg;
4898 SCIP_Bool havechange;
4899 int i;
4900
4901 assert(scip != NULL);
4902 assert(conshdlr != NULL);
4903 assert(conss != NULL);
4904 assert(nconss > 0);
4905 assert(infeasible != NULL);
4906
4907 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4908 assert(conshdlrdata != NULL);
4909
4910 /* update number of canonicalize calls */
4911 ++(conshdlrdata->ncanonicalizecalls);
4912
4913 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4914
4915 *infeasible = FALSE;
4916
4917 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4918 havechange = conshdlrdata->ncanonicalizecalls == 1;
4919
4920 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4921 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4922
4923 /* allocate memory for storing locks of each constraint */
4924 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4925 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4926
4927 /* unlock all constraints */
4928 for( i = 0; i < nconss; ++i )
4929 {
4930 assert(conss[i] != NULL);
4931
4932 consdata = SCIPconsGetData(conss[i]);
4933 assert(consdata != NULL);
4934
4935 /* remember locks */
4936 nlockspos[i] = consdata->nlockspos;
4937 nlocksneg[i] = consdata->nlocksneg;
4938
4939 /* remove locks */
4940 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4941 assert(consdata->nlockspos == 0);
4942 assert(consdata->nlocksneg == 0);
4943 }
4944
4945#ifndef NDEBUG
4946 /* check whether all locks of each expression have been removed */
4947 for( i = 0; i < nconss; ++i )
4948 {
4949 SCIP_EXPR* expr;
4951
4953
4954 consdata = SCIPconsGetData(conss[i]);
4955 assert(consdata != NULL);
4956
4958 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4959 {
4960 assert(expr != NULL);
4961 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4962 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4963 }
4965 }
4966#endif
4967
4968 /* reformulate products of binary variables */
4969 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4970 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4971 {
4972 int tmpnaddconss = 0;
4973 int tmpnchgcoefs = 0;
4974
4975 /* call this function before simplification because expressions might not be simplified after reformulating
4976 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4977 */
4978 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4979
4980 /* update counters */
4981 if( naddconss != NULL )
4982 *naddconss += tmpnaddconss;
4983 if( nchgcoefs != NULL )
4984 *nchgcoefs += tmpnchgcoefs;
4985
4986 /* check whether at least one expression has changed */
4987 if( tmpnaddconss + tmpnchgcoefs > 0 )
4988 havechange = TRUE;
4989 }
4990
4991 for( i = 0; i < nconss; ++i )
4992 {
4993 consdata = SCIPconsGetData(conss[i]);
4994 assert(consdata != NULL);
4995
4996 /* call simplify for each expression */
4997 if( !consdata->issimplified && consdata->expr != NULL )
4998 {
5000 SCIP_Bool changed;
5001
5002 changed = FALSE;
5003 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
5004 consdata->issimplified = TRUE;
5005
5006 if( changed )
5007 havechange = TRUE;
5008
5009 /* 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").
5010 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
5011 */
5012 if( simplified != consdata->expr )
5013 {
5014 assert(changed);
5015
5016 /* release old expression */
5017 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5018
5019 /* store simplified expression */
5020 consdata->expr = simplified;
5021 }
5022 else
5023 {
5024 /* The simplify captures simplified in any case, also if nothing has changed.
5025 * Therefore, we have to release it here.
5026 */
5028 }
5029
5030 if( *infeasible )
5031 break;
5032
5033 /* scale constraint sides */
5034 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5035
5036 if( changed )
5037 havechange = TRUE;
5038
5039 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5040 if( SCIPisExprValue(scip, consdata->expr) )
5041 {
5042 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5043 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5044 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5045 {
5046 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5047 SCIPdebugPrintCons(scip, conss[i], NULL);
5048 *infeasible = TRUE;
5049 break;
5050 }
5051 else
5052 {
5053 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5054 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5055 if( ndelconss != NULL )
5056 ++*ndelconss;
5057 havechange = TRUE;
5058 }
5059 }
5060 }
5061 }
5062
5063 /* replace common subexpressions */
5064 if( havechange && !*infeasible )
5065 {
5066 SCIP_CONS** consssorted;
5068 SCIP_Bool replacedroot;
5069
5071 for( i = 0; i < nconss; ++i )
5072 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5073
5075
5076 /* update pointer to root expr in constraints, if any has changed
5077 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5078 */
5079 if( replacedroot )
5080 for( i = 0; i < nconss; ++i )
5081 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5082
5084
5085 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5086 * been changed after simplification; now we completely recollect all variable expression and variable events
5087 */
5088
5089 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5090 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5091 */
5092 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5093 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5094
5095 for( i = nconss-1; i >= 0; --i )
5096 {
5097 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5098 if( SCIPconsIsDeleted(consssorted[i]) )
5099 continue;
5100
5101 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5102 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5103 }
5104 for( i = 0; i < nconss; ++i )
5105 {
5106 if( SCIPconsIsDeleted(consssorted[i]) )
5107 continue;
5108
5109 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5110 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5111 }
5112
5113 SCIPfreeBufferArray(scip, &consssorted);
5114
5115 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5116 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5117 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5118 */
5119 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5120 }
5121
5122 /* restore locks */
5123 for( i = 0; i < nconss; ++i )
5124 {
5125 if( SCIPconsIsDeleted(conss[i]) )
5126 continue;
5127
5128 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5129 }
5130
5131 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5132 * TODO can we skip this in presoltiming fast?
5133 */
5134 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5135 {
5136 /* reset one of the number of detections counter to count only current presolving round */
5137 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5138 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5139
5140 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5141 }
5142
5143 /* free allocated memory */
5144 SCIPfreeBufferArray(scip, &nlocksneg);
5145 SCIPfreeBufferArray(scip, &nlockspos);
5146
5147 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5148
5149 return SCIP_OKAY;
5150}
5151
5152/** merges constraints that have the same root expression */
5153static
5155 SCIP* scip, /**< SCIP data structure */
5156 SCIP_CONS** conss, /**< constraints to process */
5157 int nconss, /**< number of constraints */
5158 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5159 )
5160{
5162 SCIP_Bool* updatelocks;
5163 int* nlockspos;
5164 int* nlocksneg;
5165 int c;
5166
5167 assert(success != NULL);
5168
5169 *success = FALSE;
5170
5171 /* not enough constraints available */
5172 if( nconss <= 1 )
5173 return SCIP_OKAY;
5174
5176 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5177 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5178 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5179
5180 for( c = 0; c < nconss; ++c )
5181 {
5182 SCIP_CONSDATA* consdata;
5183
5184 /* ignore deleted constraints */
5185 if( SCIPconsIsDeleted(conss[c]) )
5186 continue;
5187
5188 consdata = SCIPconsGetData(conss[c]);
5189 assert(consdata != NULL);
5190
5191 /* add expression to the hash map if not seen so far */
5192 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5193 {
5194 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5195 }
5196 else
5197 {
5199 int idx;
5200
5201 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5202 assert(idx >= 0 && idx < nconss);
5203
5204 imgconsdata = SCIPconsGetData(conss[idx]);
5206 assert(imgconsdata->expr == consdata->expr);
5207
5208 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5209 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5210
5211 /* check whether locks need to be updated */
5212 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5213 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5214 {
5215 nlockspos[idx] = imgconsdata->nlockspos;
5216 nlocksneg[idx] = imgconsdata->nlocksneg;
5217 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5218 updatelocks[idx] = TRUE;
5219 }
5220
5221 /* update constraint sides */
5222 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5223 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5224
5225 /* delete constraint */
5226 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5227 *success = TRUE;
5228 }
5229 }
5230
5231 /* restore locks of updated constraints */
5232 if( *success )
5233 {
5234 for( c = 0; c < nconss; ++c )
5235 {
5236 if( updatelocks[c] )
5237 {
5238 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5239 }
5240 }
5241 }
5242
5243 /* free memory */
5244 SCIPfreeBufferArray(scip, &nlocksneg);
5245 SCIPfreeBufferArray(scip, &nlockspos);
5246 SCIPfreeBufferArray(scip, &updatelocks);
5248
5249 return SCIP_OKAY;
5250}
5251
5252/** interval evaluation of variables as used in redundancy check
5253 *
5254 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5255 */
5256static
5258{ /*lint --e{715}*/
5259 SCIP_CONSHDLRDATA* conshdlrdata;
5261 SCIP_Real lb;
5262 SCIP_Real ub;
5263
5264 assert(scip != NULL);
5265 assert(var != NULL);
5266
5267 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5268 assert(conshdlrdata != NULL);
5269
5270 if( conshdlrdata->globalbounds )
5271 {
5272 lb = SCIPvarGetLbGlobal(var);
5273 ub = SCIPvarGetUbGlobal(var);
5274 }
5275 else
5276 {
5277 lb = SCIPvarGetLbLocal(var);
5278 ub = SCIPvarGetUbLocal(var);
5279 }
5280 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5281
5282 /* relax variable bounds, if there are bounds and variable is not fixed
5283 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5284 */
5285 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5286 {
5287 if( !SCIPisInfinity(scip, -lb) )
5288 lb -= SCIPfeastol(scip);
5289
5290 if( !SCIPisInfinity(scip, ub) )
5291 ub += SCIPfeastol(scip);
5292 }
5293
5294 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5297 assert(lb <= ub);
5298
5300
5301 return interval;
5302}
5303
5304/** removes constraints that are always feasible or very simple
5305 *
5306 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5307 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5308 * might violate variable bounds by up to feastol, too.
5309 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5310 *
5311 * Also removes constraints of the form lhs &le; variable &le; rhs.
5312 *
5313 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5314 *
5315 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5316 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5317 * would appear as if the constraint is redundant.
5318 */
5319static
5321 SCIP* scip, /**< SCIP data structure */
5322 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5323 SCIP_CONS** conss, /**< constraints to propagate */
5324 int nconss, /**< total number of constraints */
5325 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5326 int* ndelconss, /**< buffer to add the number of deleted constraints */
5327 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5328 )
5329{
5330 SCIP_CONSHDLRDATA* conshdlrdata;
5331 SCIP_CONSDATA* consdata;
5332 SCIP_INTERVAL activity;
5334 int i;
5335
5336 assert(scip != NULL);
5337 assert(conshdlr != NULL);
5338 assert(conss != NULL);
5339 assert(nconss >= 0);
5340 assert(cutoff != NULL);
5341 assert(ndelconss != NULL);
5342 assert(nchgbds != NULL);
5343
5344 /* no constraints to check */
5345 if( nconss == 0 )
5346 return SCIP_OKAY;
5347
5348 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5349 assert(conshdlrdata != NULL);
5350
5351 /* increase curboundstag and set lastvaractivitymethodchange
5352 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5353 * for the redundancy check differently than for domain propagation
5354 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5355 */
5356 ++conshdlrdata->curboundstag;
5357 assert(conshdlrdata->curboundstag > 0);
5358 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5359 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5360 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5361
5362 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5363
5364 *cutoff = FALSE;
5365 for( i = 0; i < nconss; ++i )
5366 {
5367 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5368 continue;
5369
5370 consdata = SCIPconsGetData(conss[i]);
5371 assert(consdata != NULL);
5372
5373 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5374 if( SCIPisExprValue(scip, consdata->expr) )
5375 {
5376 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5377
5378 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5379 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5380 {
5381 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5382 *cutoff = TRUE;
5383
5384 goto TERMINATE;
5385 }
5386
5387 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5388
5389 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5390 ++*ndelconss;
5391
5392 continue;
5393 }
5394
5395 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5396 if( SCIPisExprVar(scip, consdata->expr) )
5397 {
5398 SCIP_VAR* var;
5399 SCIP_Bool tightened;
5400
5401 var = SCIPgetVarExprVar(consdata->expr);
5402 assert(var != NULL);
5403
5404 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);
5405
5406 /* ensure that variable bounds are within constraint sides */
5407 if( !SCIPisInfinity(scip, -consdata->lhs) )
5408 {
5409 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5410
5411 if( tightened )
5412 ++*nchgbds;
5413
5414 if( *cutoff )
5415 goto TERMINATE;
5416 }
5417
5418 if( !SCIPisInfinity(scip, consdata->rhs) )
5419 {
5420 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5421
5422 if( tightened )
5423 ++*nchgbds;
5424
5425 if( *cutoff )
5426 goto TERMINATE;
5427 }
5428
5429 /* delete the (now) redundant constraint locally */
5430 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5431 ++*ndelconss;
5432
5433 continue;
5434 }
5435
5436 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5437 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5438 * variable bounds by up to feastol
5439 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5440 */
5441 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5442 SCIPdebugPrintCons(scip, conss[i], NULL);
5443
5444 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5446
5447 /* it is unlikely that we detect infeasibility by doing forward propagation */
5448 if( *cutoff )
5449 {
5450 SCIPdebugMsg(scip, " -> cutoff\n");
5451 goto TERMINATE;
5452 }
5453
5454 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5455 activity = SCIPexprGetActivity(consdata->expr);
5456
5457 /* relax sides by feastol
5458 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5459 */
5461 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5462 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5463
5465 {
5466 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5467
5468 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5469 ++*ndelconss;
5470
5471 continue;
5472 }
5473
5474 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5475 }
5476
5477TERMINATE:
5478 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5479 ++conshdlrdata->curboundstag;
5480 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5481 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5482 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5483
5484 return SCIP_OKAY;
5485}
5486
5487/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5488static
5490 SCIP* scip, /**< SCIP data structure */
5491 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5492 SCIP_CONS* cons, /**< source constraint to try to convert */
5493 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5494 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5495 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5496 )
5497{
5498 SCIP_CONSHDLRDATA* conshdlrdata;
5499 SCIP_CONSDATA* consdata;
5501 int upgdconsssize;
5502 int nupgdconss_;
5503 int i;
5504
5505 assert(scip != NULL);
5506 assert(conshdlr != NULL);
5507 assert(cons != NULL);
5509 assert(upgraded != NULL);
5510 assert(nupgdconss != NULL);
5511 assert(naddconss != NULL);
5512
5513 *upgraded = FALSE;
5514
5515 nupgdconss_ = 0;
5516
5517 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5518 assert(conshdlrdata != NULL);
5519
5520 /* if there are no upgrade methods, we can stop */
5521 if( conshdlrdata->nconsupgrades == 0 )
5522 return SCIP_OKAY;
5523
5524 upgdconsssize = 2;
5526
5527 /* call the upgrading methods */
5528 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5530
5531 consdata = SCIPconsGetData(cons);
5532 assert(consdata != NULL);
5533
5534 /* try all upgrading methods in priority order in case the upgrading step is enable */
5535 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5536 {
5537 if( !conshdlrdata->consupgrades[i]->active )
5538 continue;
5539
5540 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5541
5542 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5543
5544 while( nupgdconss_ < 0 )
5545 {
5546 /* upgrade function requires more memory: resize upgdconss and call again */
5550
5551 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5552
5553 assert(nupgdconss_ != 0);
5554 }
5555
5556 if( nupgdconss_ > 0 )
5557 {
5558 /* got upgrade */
5559 int j;
5560
5561 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5562
5563 /* add the upgraded constraints to the problem and forget them */
5564 for( j = 0; j < nupgdconss_; ++j )
5565 {
5566 SCIPdebugMsgPrint(scip, "\t");
5568
5569 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5570 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5571 }
5572
5573 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5574 *nupgdconss += 1;
5575 *naddconss += nupgdconss_ - 1;
5576 *upgraded = TRUE;
5577
5578 /* delete upgraded constraint */
5579 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5580 SCIP_CALL( SCIPdelCons(scip, cons) );
5581
5582 break;
5583 }
5584 }
5585
5587
5588 return SCIP_OKAY;
5589}
5590
5591/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5592 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5593 * variable bounds, and is not binary
5594 */
5595static
5597 SCIP* scip, /**< SCIP data structure */
5598 SCIP_EXPR* expr /**< variable expression */
5599 )
5600{
5601 SCIP_VAR* var;
5602 SCIP_EXPR_OWNERDATA* ownerdata;
5603
5604 assert(SCIPisExprVar(scip, expr));
5605
5606 var = SCIPgetVarExprVar(expr);
5607 assert(var != NULL);
5608
5609 ownerdata = SCIPexprGetOwnerData(expr);
5610 assert(ownerdata != NULL);
5611
5612 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5613 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5614 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5618}
5619
5620/** removes all variable expressions that are contained in a given expression from a hash map */
5621static
5623 SCIP* scip, /**< SCIP data structure */
5624 SCIP_EXPR* expr, /**< expression */
5625 SCIP_EXPRITER* it, /**< expression iterator */
5626 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5627 )
5628{
5629 SCIP_EXPR* e;
5630
5632 {
5633 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5634 {
5636 }
5637 }
5638
5639 return SCIP_OKAY;
5640}
5641
5642/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5643 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5644 *
5645 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5646 * Otherwise, a bound disjunction constraint is added.
5647 *
5648 * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) &le; rhs
5649 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5650 * 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
5651 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5652 * @todo reduction should also be applicable if variable appears in the objective with the right sign (sign such that opt is at boundary)
5653 */
5654static
5656 SCIP* scip, /**< SCIP data structure */
5657 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5658 SCIP_CONS* cons, /**< nonlinear constraint */
5659 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5660 int* naddconss, /**< pointer to store the total number of added constraints */
5661 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5662 )
5663{
5664 SCIP_CONSHDLRDATA* conshdlrdata;
5665 SCIP_CONSDATA* consdata;
5668 SCIP_Bool hasbounddisj;
5669 SCIP_Bool haslhs;
5670 SCIP_Bool hasrhs;
5671 int nsinglelocked = 0;
5672 int i;
5673
5674 assert(conshdlr != NULL);
5675 assert(cons != NULL);
5676 assert(nchgvartypes != NULL);
5677 assert(naddconss != NULL);
5678 assert(infeasible != NULL);
5679
5680 *nchgvartypes = 0;
5681 *naddconss = 0;
5682 *infeasible = FALSE;
5683
5684 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5685 assert(conshdlrdata != NULL);
5686 consdata = SCIPconsGetData(cons);
5687 assert(consdata != NULL);
5688
5689 /* only consider constraints with one finite side */
5690 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5691 return SCIP_OKAY;
5692
5693 /* only consider sum expressions */
5694 if( !SCIPisExprSum(scip, consdata->expr) )
5695 return SCIP_OKAY;
5696
5697 /* remember which side is finite */
5698 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5699 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5700
5701 /* allocate memory */
5702 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5703 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5704
5705 /* check all variable expressions for single locked variables */
5706 for( i = 0; i < consdata->nvarexprs; ++i )
5707 {
5708 assert(consdata->varexprs[i] != NULL);
5709
5710 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5711 {
5712 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5713 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5714 }
5715 }
5716 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5717
5718 if( nsinglelocked > 0 )
5719 {
5720 SCIP_EXPR** children;
5722 int nchildren;
5723
5724 children = SCIPexprGetChildren(consdata->expr);
5725 nchildren = SCIPexprGetNChildren(consdata->expr);
5726
5727 /* create iterator */
5731
5732 for( i = 0; i < nchildren; ++i )
5733 {
5734 SCIP_EXPR* child;
5735 SCIP_Real coef;
5736
5737 child = children[i];
5738 assert(child != NULL);
5739 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5740
5741 /* ignore linear terms */
5742 if( SCIPisExprVar(scip, child) )
5743 continue;
5744
5745 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5746 * expression that represents f_j and remove each variable expression from exprcands
5747 */
5748 else if( SCIPisExprProduct(scip, child) )
5749 {
5750 int j;
5751
5752 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5753 {
5755
5757 {
5758 /* mark all variable expressions that are contained in the expression */
5760 }
5761 }
5762 }
5763 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5764 * for an integer k >= 1
5765 */
5766 else if( SCIPisExprPower(scip, child) )
5767 {
5769 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5770 SCIP_Bool valid;
5771
5772 /* check for even integral exponent */
5773 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5774
5775 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5776 {
5777 /* mark all variable expressions that are contained in the expression */
5779 }
5780 }
5781 /* all other cases cannot be handled */
5782 else
5783 {
5784 /* mark all variable expressions that are contained in the expression */
5786 }
5787 }
5788
5789 /* free expression iterator */
5791 }
5792
5793 /* check whether the bound disjunction constraint handler is available */
5794 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5795
5796 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5797 for( i = 0; i < nsinglelocked; ++i )
5798 {
5799 /* only consider expressions that are still contained in the exprcands map */
5801 {
5803 SCIP_VAR* vars[2];
5804 SCIP_BOUNDTYPE boundtypes[2];
5805 SCIP_Real bounds[2];
5806 char name[SCIP_MAXSTRLEN];
5807 SCIP_VAR* var;
5808
5810 assert(var != NULL);
5811 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5813
5814 /* try to change the variable type to binary */
5815 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5816 {
5819 ++(*nchgvartypes);
5820
5821 if( *infeasible )
5822 {
5823 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5824 break;
5825 }
5826 }
5827 /* add bound disjunction constraint if bounds of the variable are finite */
5829 {
5830 vars[0] = var;
5831 vars[1] = var;
5832 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5833 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5834 bounds[0] = SCIPvarGetUbGlobal(var);
5835 bounds[1] = SCIPvarGetLbGlobal(var);
5836
5837 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5838
5839 /* create, add, and release bound disjunction constraint */
5840 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5841 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5845 ++(*naddconss);
5846 }
5847 }
5848 }
5849
5850 /* free memory */
5853
5854 return SCIP_OKAY;
5855}
5856
5857/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5858static
5860 SCIP* scip, /**< SCIP data structure */
5861 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5862 SCIP_CONS** conss, /**< nonlinear constraints */
5863 int nconss, /**< total number of nonlinear constraints */
5864 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5865 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5866 )
5867{
5868 int c;
5869
5870 assert(scip != NULL);
5871 assert(conshdlr != NULL);
5872 assert(conss != NULL || nconss == 0);
5873 assert(nchgvartypes != NULL);
5874 assert(infeasible != NULL);
5875
5876 *infeasible = FALSE;
5877
5878 /* nothing can be done if there are no binary and integer variables available */
5879 if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5880 return SCIP_OKAY;
5881
5882 /* no continuous var can be made implicit-integer if there are no continuous variables */
5883 if( SCIPgetNContVars(scip) == 0 )
5884 return SCIP_OKAY;
5885
5886 for( c = 0; c < nconss; ++c )
5887 {
5888 SCIP_CONSDATA* consdata;
5889 SCIP_EXPR** children;
5890 int nchildren;
5891 SCIP_Real* coefs;
5892 SCIP_EXPR* cand = NULL;
5893 SCIP_Real candcoef = 0.0;
5894 int i;
5895
5896 assert(conss != NULL && conss[c] != NULL);
5897
5898 consdata = SCIPconsGetData(conss[c]);
5899 assert(consdata != NULL);
5900
5901 /* the constraint must be an equality constraint */
5902 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5903 continue;
5904
5905 /* the root expression needs to be a sum expression */
5906 if( !SCIPisExprSum(scip, consdata->expr) )
5907 continue;
5908
5909 children = SCIPexprGetChildren(consdata->expr);
5910 nchildren = SCIPexprGetNChildren(consdata->expr);
5911
5912 /* the sum expression must have at least two children
5913 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5914 */
5915 if( nchildren <= 1 )
5916 continue;
5917
5918 coefs = SCIPgetCoefsExprSum(consdata->expr);
5919
5920 /* find first continuous variable and get value of its coefficient */
5921 for( i = 0; i < nchildren; ++i )
5922 {
5923 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5924 continue;
5925
5926 candcoef = coefs[i];
5927 assert(candcoef != 0.0);
5928
5929 /* lhs/rhs - constant divided by candcoef must be integral
5930 * if not, break with cand == NULL, so give up
5931 */
5932 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5933 cand = children[i];
5934
5935 break;
5936 }
5937
5938 /* no suitable continuous variable found */
5939 if( cand == NULL )
5940 continue;
5941
5942 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5943 for( i = 0; i < nchildren; ++i )
5944 {
5945 if( children[i] == cand )
5946 continue;
5947
5948 /* child i must be integral */
5949 if( !SCIPexprIsIntegral(children[i]) )
5950 {
5951 cand = NULL;
5952 break;
5953 }
5954
5955 /* coefficient of child i must be integral if diving by candcoef */
5956 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5957 {
5958 cand = NULL;
5959 break;
5960 }
5961 }
5962
5963 if( cand == NULL )
5964 continue;
5965
5966 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5968
5969 /* change variable type */
5971
5972 if( *infeasible )
5973 return SCIP_OKAY;
5974
5975 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5977 }
5978
5979 return SCIP_OKAY;
5980}
5981
5982/** creates auxiliary variable for a given expression
5983 *
5984 * @note for a variable expression it does nothing
5985 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5986 */
5987static
5989 SCIP* scip, /**< SCIP data structure */
5990 SCIP_EXPR* expr /**< expression */
5991 )
5992{
5993 SCIP_EXPR_OWNERDATA* ownerdata;
5994 SCIP_CONSHDLRDATA* conshdlrdata;
5995 SCIP_VARTYPE vartype;
5996 SCIP_INTERVAL activity;
5997 char name[SCIP_MAXSTRLEN];
5998
5999 assert(scip != NULL);
6000 assert(expr != NULL);
6001
6002 ownerdata = SCIPexprGetOwnerData(expr);
6003 assert(ownerdata != NULL);
6004 assert(ownerdata->nauxvaruses > 0);
6005
6006 /* if we already have auxvar, then do nothing */
6007 if( ownerdata->auxvar != NULL )
6008 return SCIP_OKAY;
6009
6010 /* if expression is a variable-expression, then do nothing */
6011 if( SCIPisExprVar(scip, expr) )
6012 return SCIP_OKAY;
6013
6015 {
6016 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6017 return SCIP_INVALIDCALL;
6018 }
6019
6020 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6021 assert(conshdlrdata != NULL);
6022 assert(conshdlrdata->auxvarid >= 0);
6023
6024 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6025 * but it usually indicates a missing simplify
6026 * if we find situations where we need to have an auxvar for a constant, then remove this assert
6027 */
6028 assert(!SCIPisExprValue(scip, expr));
6029
6030 /* create and capture auxiliary variable */
6031 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6032 ++conshdlrdata->auxvarid;
6033
6034 /* type of auxiliary variable depends on integrality information of the expression */
6036
6037 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6038 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6039 {
6040 activity = SCIPexprGetActivity(expr);
6041 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6042 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6043 * and abort in debug mode only
6044 */
6046 {
6047 SCIPABORT();
6049 }
6050 }
6051 else
6053
6054 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6055 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6056 */
6057 if( SCIPgetDepth(scip) == 0 )
6058 {
6059 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6060 }
6061 else
6062 {
6063 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6064 }
6065
6066 /* mark the auxiliary variable to be added for the relaxation only
6067 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6068 * or to copy the variable to a subscip
6069 */
6070 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6071
6072 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6073
6074 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6075
6076 /* add variable locks in both directions
6077 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6078 * but then we need to also update the auxvars locks when the expr locks change
6079 */
6080 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6081
6082#ifdef WITH_DEBUG_SOLUTION
6084 {
6085 /* store debug solution value of auxiliary variable
6086 * assumes that expression has been evaluated in debug solution before
6087 */
6088 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6089 }
6090#endif
6091
6092 if( SCIPgetDepth(scip) > 0 )
6093 {
6094 /* initialize local bounds to (locally valid) activity */
6095 SCIP_Bool cutoff;
6096 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6097 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6098 }
6099
6100 return SCIP_OKAY;
6101}
6102
6103/** initializes separation for constraint
6104 *
6105 * - ensures that activities are up to date in all expressions
6106 * - creates auxiliary variables where required
6107 * - calls propExprDomains() to possibly tighten auxvar bounds
6108 * - calls separation initialization callback of nlhdlrs
6109 */
6110static
6112 SCIP* scip, /**< SCIP data structure */
6113 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6114 SCIP_CONS** conss, /**< constraints */
6115 int nconss, /**< number of constraints */
6116 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6117 )
6118{
6119 SCIP_CONSDATA* consdata;
6120 SCIP_CONSHDLRDATA* conshdlrdata;
6122 SCIP_EXPR* expr;
6124 SCIP_VAR* auxvar;
6125 int nreductions = 0;
6126 int c, e;
6127
6128 assert(scip != NULL);
6129 assert(conshdlr != NULL);
6130 assert(conss != NULL || nconss == 0);
6131 assert(nconss >= 0);
6132 assert(infeasible != NULL);
6133
6134 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6135 assert(conshdlrdata != NULL);
6136
6137 /* start with new propbounds (just to be sure, should not be needed) */
6138 ++conshdlrdata->curpropboundstag;
6139
6142
6143 /* first ensure activities are up to date and create auxvars */
6144 *infeasible = FALSE;
6145 for( c = 0; c < nconss; ++c )
6146 {
6147 assert(conss != NULL);
6148 assert(conss[c] != NULL);
6149
6150 consdata = SCIPconsGetData(conss[c]);
6151 assert(consdata != NULL);
6152 assert(consdata->expr != NULL);
6153
6154#ifdef WITH_DEBUG_SOLUTION
6156 {
6158
6160
6161 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6162 {
6163 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6164 * in createAuxVar()
6165 */
6166 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6167 }
6168 }
6169#endif
6170
6171 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6172 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6173
6174 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6175 {
6176 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6177 {
6178 SCIP_CALL( createAuxVar(scip, expr) );
6179 }
6180 }
6181
6182 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6183 if( auxvar != NULL )
6184 {
6185 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6186 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6187 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6188 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6189 if( *infeasible )
6190 {
6191 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6192 break;
6193 }
6194
6195 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6196 if( *infeasible )
6197 {
6198 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6199 break;
6200 }
6201 }
6202 }
6203
6204 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6205 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6206 * (e.g., log(x*y), which becomes log(w), w=x*y
6207 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6208 */
6209 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6210 if( result == SCIP_CUTOFF )
6211 *infeasible = TRUE;
6212
6213 /* now call initsepa of nlhdlrs
6214 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6215 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6216 */
6218 for( c = 0; c < nconss && !*infeasible; ++c )
6219 {
6220 assert(conss != NULL);
6221 assert(conss[c] != NULL);
6222
6223 consdata = SCIPconsGetData(conss[c]);
6224 assert(consdata != NULL);
6225 assert(consdata->expr != NULL);
6226
6227 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6228 {
6229 SCIP_EXPR_OWNERDATA* ownerdata;
6230
6231 ownerdata = SCIPexprGetOwnerData(expr);
6232 assert(ownerdata != NULL);
6233
6234 if( ownerdata->nauxvaruses == 0 )
6235 continue;
6236
6237 for( e = 0; e < ownerdata->nenfos; ++e )
6238 {
6239 SCIP_NLHDLR* nlhdlr;
6240 SCIP_Bool underestimate;
6241 SCIP_Bool overestimate;
6242 assert(ownerdata->enfos[e] != NULL);
6243
6244 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6245 * which participated in a previous initSepa() call
6246 */
6247 if( ownerdata->enfos[e]->issepainit )
6248 continue;
6249
6250 /* only call initsepa if it will actually separate */
6251 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6252 continue;
6253
6254 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6255 assert(nlhdlr != NULL);
6256
6257 /* only init sepa if there is an initsepa callback */
6258 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6259 continue;
6260
6261 /* check whether expression needs to be under- or overestimated */
6262 overestimate = ownerdata->nlocksneg > 0;
6263 underestimate = ownerdata->nlockspos > 0;
6264 assert(underestimate || overestimate);
6265
6266 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6267
6268 /* call the separation initialization callback of the nonlinear handler */
6269 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6270 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6271 ownerdata->enfos[e]->issepainit = TRUE;
6272
6273 if( *infeasible )
6274 {
6275 /* stop everything if we detected infeasibility */
6276 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6277 break;
6278 }
6279 }
6280 }
6281 }
6282
6284
6285 return SCIP_OKAY;
6286}
6287
6288/** returns whether we are ok to branch on auxiliary variables
6289 *
6290 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6291 */
6292static
6294 SCIP* scip, /**< SCIP data structure */
6295 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6296 )
6297{
6298 SCIP_CONSHDLRDATA* conshdlrdata;
6299
6300 assert(conshdlr != NULL);
6301
6302 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6303 assert(conshdlrdata != NULL);
6304
6305 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6306}
6307
6308/** gets weight of variable when splitting violation score onto several variables in an expression */
6309static
6311 SCIP* scip, /**< SCIP data structure */
6312 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6313 SCIP_VAR* var, /**< variable */
6314 SCIP_SOL* sol /**< current solution */
6315 )
6316{
6317 SCIP_CONSHDLRDATA* conshdlrdata;
6318
6319 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6320 assert(conshdlrdata != NULL);
6321
6322 switch( conshdlrdata->branchviolsplit )
6323 {
6324 case 'u' : /* uniform: everyone gets the same score */
6325 return 1.0;
6326
6327 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6328 {
6329 SCIP_Real weight;
6331 return MAX(0.05, weight);
6332 }
6333
6334 case 'd' : /* domain width */
6336
6337 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6338 {
6339 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6340 assert(width > 0.0);
6341 if( width > 10.0 )
6342 return 10.0*log10(width);
6343 if( width < 0.1 )
6344 return 0.1/(-log10(width));
6345 return width;
6346 }
6347
6348 default :
6349 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6350 SCIPABORT();
6351 return SCIP_INVALID;
6352 }
6353}
6354
6355/** adds violation-branching score to a set of expressions, thereby distributing the score
6356 *
6357 * Each expression must either be a variable expression or have an aux-variable.
6358 *
6359 * If unbounded variables are present, each unbounded var gets an even score.
6360 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6361 */
6362static
6364 SCIP* scip, /**< SCIP data structure */
6365 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6366 int nexprs, /**< number of expressions */
6367 SCIP_Real violscore, /**< violation-branching score to add to expression */
6368 SCIP_SOL* sol, /**< current solution */
6369 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6370 )
6371{
6372 SCIP_CONSHDLR* conshdlr;
6373 SCIP_VAR* var;
6374 SCIP_Real weight;
6375 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6376 int nunbounded = 0; /* number of candidates with unbounded domain */
6377 int i;
6378
6379 assert(exprs != NULL);
6380 assert(nexprs > 0);
6381 assert(success != NULL);
6382
6383 if( nexprs == 1 )
6384 {
6386 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6388 *success = TRUE;
6389 return;
6390 }
6391
6392 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6393
6394 for( i = 0; i < nexprs; ++i )
6395 {
6397 assert(var != NULL);
6398
6400 ++nunbounded;
6402 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6403 }
6404
6405 *success = FALSE;
6406 for( i = 0; i < nexprs; ++i )
6407 {
6409 assert(var != NULL);
6410
6411 if( nunbounded > 0 )
6412 {
6414 {
6416 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6417 100.0/nunbounded, violscore,
6419 *success = TRUE;
6420 }
6421 }
6423 {
6424 assert(weightsum > 0.0);
6425
6426 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6427 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6428 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6429 100*weight / weightsum, violscore,
6431 *success = TRUE;
6432 }
6433 else
6434 {
6435 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6437 }
6438 }
6439}
6440
6441/** adds violation-branching score to children of expression for given auxiliary variables
6442 *
6443 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6444 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6445 *
6446 * @note This method may modify the given auxvars array by means of sorting.
6447 */
6448static
6450 SCIP* scip, /**< SCIP data structure */
6451 SCIP_EXPR* expr, /**< expression where to start searching */
6452 SCIP_Real violscore, /**< violation score to add to expression */
6453 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6454 int nauxvars, /**< number of auxiliary variables */
6455 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6456 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6457 )
6458{
6460 SCIP_VAR* auxvar;
6461 SCIP_EXPR** exprs;
6462 int nexprs;
6463 int pos;
6464
6465 assert(scip != NULL);
6466 assert(expr != NULL);
6467 assert(auxvars != NULL);
6468 assert(success != NULL);
6469
6470 /* sort variables to make lookup below faster */
6471 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6472
6475
6477 nexprs = 0;
6478
6480 {
6481 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6482 if( auxvar == NULL )
6483 continue;
6484
6485 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6486 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6487 {
6488 assert(auxvars[pos] == auxvar);
6489
6490 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6491 exprs[nexprs++] = expr;
6492
6493 if( nexprs == nauxvars )
6494 break;
6495 }
6496 }
6497
6499
6500 if( nexprs > 0 )
6501 {
6503 }
6504 else
6505 *success = FALSE;
6506
6507 SCIPfreeBufferArray(scip, &exprs);
6508
6509 return SCIP_OKAY;
6510}
6511
6512/** registers all unfixed variables in violated constraints as branching candidates */
6513static
6515 SCIP* scip, /**< SCIP data structure */
6516 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6517 SCIP_CONS** conss, /**< constraints */
6518 int nconss, /**< number of constraints */
6519 int* nnotify /**< counter for number of notifications performed */
6520 )
6521{
6522 SCIP_CONSDATA* consdata;
6523 SCIP_VAR* var;
6524 int c;
6525 int i;
6526
6527 assert(conshdlr != NULL);
6528 assert(conss != NULL || nconss == 0);
6529 assert(nnotify != NULL);
6530
6531 *nnotify = 0;
6532
6533 for( c = 0; c < nconss; ++c )
6534 {
6535 assert(conss != NULL && conss[c] != NULL);
6536
6537 consdata = SCIPconsGetData(conss[c]);
6538 assert(consdata != NULL);
6539
6540 /* consider only violated constraints */
6541 if( !isConsViolated(scip, conss[c]) )
6542 continue;
6543
6544 /* register all variables that have not been fixed yet */
6545 assert(consdata->varexprs != NULL);
6546 for( i = 0; i < consdata->nvarexprs; ++i )
6547 {
6548 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6549 assert(var != NULL);
6550
6552 {
6554 ++(*nnotify);
6555 }
6556 }
6557 }
6558
6559 return SCIP_OKAY;
6560}
6561
6562/** registers all variables in violated constraints with branching scores as external branching candidates */
6563static
6565 SCIP* scip, /**< SCIP data structure */
6566 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6567 SCIP_CONS** conss, /**< constraints */
6568 int nconss, /**< number of constraints */
6569 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6570 )
6571{
6572 SCIP_CONSDATA* consdata;
6574 int c;
6575
6576 assert(conshdlr != NULL);
6577 assert(success != NULL);
6578
6579 *success = FALSE;
6580
6581 if( branchAuxNonlinear(scip, conshdlr) )
6582 {
6585 }
6586
6587 /* register external branching candidates */
6588 for( c = 0; c < nconss; ++c )
6589 {
6590 assert(conss != NULL && conss[c] != NULL);
6591
6592 consdata = SCIPconsGetData(conss[c]);
6593 assert(consdata != NULL);
6594 assert(consdata->varexprs != NULL);
6595
6596 /* consider only violated constraints */
6597 if( !isConsViolated(scip, conss[c]) )
6598 continue;
6599
6600 if( !branchAuxNonlinear(scip, conshdlr) )
6601 {
6602 int i;
6603
6604 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6605 * only, so we can loop over variable expressions
6606 */
6607 for( i = 0; i < consdata->nvarexprs; ++i )
6608 {
6609 SCIP_Real violscore;
6610 SCIP_Real lb;
6611 SCIP_Real ub;
6612 SCIP_VAR* var;
6613
6614 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6615
6616 /* skip variable expressions that do not have a violation score */
6617 if( violscore == 0.0 )
6618 continue;
6619
6620 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6621 assert(var != NULL);
6622
6623 lb = SCIPvarGetLbLocal(var);
6624 ub = SCIPvarGetUbLocal(var);
6625
6626 /* consider variable for branching if it has not been fixed yet */
6627 if( !SCIPisEQ(scip, lb, ub) )
6628 {
6629 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6631 *success = TRUE;
6632 }
6633 else
6634 {
6635 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6636 }
6637
6638 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6639 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6640 */
6641 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6642 }
6643 }
6644 else
6645 {
6646 SCIP_EXPR* expr;
6647 SCIP_VAR* var;
6648 SCIP_Real lb;
6649 SCIP_Real ub;
6650 SCIP_Real violscore;
6651
6652 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6653 {
6655 if( violscore == 0.0 )
6656 continue;
6657
6658 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6659 * variable, so this expression should either be an original variable or have an auxiliary variable
6660 */
6662 assert(var != NULL);
6663
6664 lb = SCIPvarGetLbLocal(var);
6665 ub = SCIPvarGetUbLocal(var);
6666
6667 /* consider variable for branching if it has not been fixed yet */
6668 if( !SCIPisEQ(scip, lb, ub) )
6669 {
6670 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6671
6673 *success = TRUE;
6674 }
6675 else
6676 {
6677 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6678 }
6679 }
6680 }
6681 }
6682
6683 if( it != NULL )
6685
6686 return SCIP_OKAY;
6687}
6688
6689/** collect branching candidates from violated constraints
6690 *
6691 * Fills array with expressions that serve as branching candidates.
6692 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6693 * branching candidate.
6694 *
6695 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6696 * through variable-expressions only.
6697 */
6698static
6700 SCIP* scip, /**< SCIP data structure */
6701 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6702 SCIP_CONS** conss, /**< constraints to process */
6703 int nconss, /**< number of constraints */
6704 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6705 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6706 SCIP_Longint soltag, /**< tag of solution */
6707 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6708 int* ncands /**< number of candidates found */
6709 )
6710{
6711 SCIP_CONSHDLRDATA* conshdlrdata;
6712 SCIP_CONSDATA* consdata;
6714 int c;
6715 int attempt;
6716 SCIP_VAR* var;
6717
6718 assert(scip != NULL);
6719 assert(conshdlr != NULL);
6720 assert(cands != NULL);
6721 assert(ncands != NULL);
6722
6723 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6724 assert(conshdlrdata != NULL);
6725
6726 if( branchAuxNonlinear(scip, conshdlr) )
6727 {
6730 }
6731
6732 *ncands = 0;
6733 for( attempt = 0; attempt < 2; ++attempt )
6734 {
6735 /* collect branching candidates from violated constraints
6736 * in the first attempt, consider only constraints with large violation
6737 * in the second attempt, consider all remaining violated constraints
6738 */
6739 for( c = 0; c < nconss; ++c )
6740 {
6741 SCIP_Real consviol;
6742
6743 assert(conss != NULL && conss[c] != NULL);
6744
6745 /* consider only violated constraints */
6746 if( !isConsViolated(scip, conss[c]) )
6747 continue;
6748
6749 consdata = SCIPconsGetData(conss[c]);
6750 assert(consdata != NULL);
6751 assert(consdata->varexprs != NULL);
6752
6753 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6754
6755 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6756 continue;
6757 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6758 continue;
6759
6760 if( !branchAuxNonlinear(scip, conshdlr) )
6761 {
6762 int i;
6763
6764 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6765 * only, so we can loop over variable expressions
6766 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6767 * variable, therefore we invalidate the score of a variable after processing it.
6768 */
6769 for( i = 0; i < consdata->nvarexprs; ++i )
6770 {
6771 SCIP_Real lb;
6772 SCIP_Real ub;
6773
6774 /* skip variable expressions that do not have a valid violation score */
6775 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6776 continue;
6777
6778 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6779 assert(var != NULL);
6780
6781 lb = SCIPvarGetLbLocal(var);
6782 ub = SCIPvarGetUbLocal(var);
6783
6784 /* skip already fixed variable */
6785 if( SCIPisEQ(scip, lb, ub) )
6786 {
6787 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6788 continue;
6789 }
6790
6791 assert(*ncands + 1 < SCIPgetNVars(scip));
6792 cands[*ncands].expr = consdata->varexprs[i];
6793 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6794 ++(*ncands);
6795
6796 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6797 * several times as external branching candidate */
6798 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6799 }
6800 }
6801 else
6802 {
6803 SCIP_EXPR* expr;
6804 SCIP_Real lb;
6805 SCIP_Real ub;
6806
6807 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6808 {
6809 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6810 continue;
6811
6812 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6813 * variables, so this expression should either be an original variable or have an auxiliary variable
6814 */
6816 assert(var != NULL);
6817
6818 lb = SCIPvarGetLbLocal(var);
6819 ub = SCIPvarGetUbLocal(var);
6820
6821 /* skip already fixed variable */
6822 if( SCIPisEQ(scip, lb, ub) )
6823 {
6824 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6825 continue;
6826 }
6827
6828 assert(*ncands + 1 < SCIPgetNVars(scip));
6829 cands[*ncands].expr = expr;
6830 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6831 ++(*ncands);
6832 }
6833 }
6834 }
6835
6836 /* if we have branching candidates, then we don't need another attempt */
6837 if( *ncands > 0 )
6838 break;
6839 }
6840
6841 if( it != NULL )
6843
6844 return SCIP_OKAY;
6845}
6846
6847/** computes a branching score for a variable that reflects how important branching on this variable would be for
6848 * improving the dual bound from the LP relaxation
6849 *
6850 * Assume the Lagrangian for the current LP is something of the form
6851 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6852 * where x are the original variables, z the auxiliary variables,
6853 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6854 *
6855 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6856 * If we could have used not only an estimator, but the actual function f(x), then this would
6857 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6858 * Using a lot of handwaving, we claim that
6859 * lambda_i * (f(x) - a_i'x + b_i)
6860 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6861 * If an estimator depended on local bounds, then it could be improved by branching.
6862 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6863 *
6864 * 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.
6865 * To scale, we divide by the LP objective value (if >1).
6866 *
6867 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6868 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6869 *
6870 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6871 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6872 * would also be branching candidates
6873 */
6874static
6876 SCIP* scip, /**< SCIP data structure */
6877 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6878 SCIP_VAR* var /**< variable */
6879 )
6880{
6881 SCIP_COL* col;
6882 SCIP_ROW** rows;
6883 int nrows;
6884 int r;
6885 SCIP_Real dualscore;
6886
6887 assert(scip != NULL);
6888 assert(conshdlr != NULL);
6889 assert(var != NULL);
6890
6891 /* if LP not solved, then the dual branching score is not available */
6893 return 0.0;
6894
6895 /* if var is not in the LP, then the dual branching score is not available */
6897 return 0.0;
6898
6899 col = SCIPvarGetCol(var);
6900 assert(col != NULL);
6901
6902 if( !SCIPcolIsInLP(col) )
6903 return 0.0;
6904
6905 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6906 rows = SCIPcolGetRows(col);
6907
6908 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6909
6910 /* aggregate duals from all rows from consexpr with non-zero dual
6911 * TODO: this is a quick-and-dirty implementation, and not used by default
6912 * in the long run, this should be either removed or replaced by a proper implementation
6913 */
6914 dualscore = 0.0;
6915 for( r = 0; r < nrows; ++r )
6916 {
6917 SCIP_Real estimategap;
6918 const char* estimategapstr;
6919
6920 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6921 * these would typically be local, unless they are created at the root node
6922 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6923 if( !SCIProwIsLocal(rows[r]) )
6924 continue;
6925 */
6926 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6927 continue;
6928 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6929 continue;
6930
6931 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6932 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6933 continue;
6935 assert(estimategap >= 0.0);
6938
6939 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6940 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6941
6943 }
6944
6945 /* divide by optimal value of LP for scaling */
6947
6948 return dualscore;
6949}
6950
6951/** computes branching scores (including weighted score) for a set of candidates
6952 *
6953 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6954 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6955 *
6956 * For each score, compute the maximum over all candidates.
6957 *
6958 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6959 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6960 * score of all candidates.
6961 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6962 *
6963 * For example:
6964 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6965 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6966 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6967 * - 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.
6968 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6969 */
6970static
6972 SCIP* scip, /**< SCIP data structure */
6973 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6974 BRANCHCAND* cands, /**< branching candidates */
6975 int ncands, /**< number of candidates */
6976 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6977 )
6978{
6979 SCIP_CONSHDLRDATA* conshdlrdata;
6981 int c;
6982
6983 assert(scip != NULL);
6984 assert(conshdlr != NULL);
6985 assert(cands != NULL);
6986 assert(ncands > 0);
6987
6988 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6989 assert(conshdlrdata != NULL);
6990
6991 /* initialize counts to 0 */
6992 memset(&maxscore, 0, sizeof(BRANCHCAND));
6993
6994 for( c = 0; c < ncands; ++c )
6995 {
6996 if( conshdlrdata->branchviolweight > 0.0 )
6997 {
6998 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6999 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
7000 }
7001
7002 if( conshdlrdata->branchdomainweight > 0.0 )
7003 {
7004 SCIP_Real domainwidth;
7005 SCIP_VAR* var;
7006
7007 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7008 assert(var != NULL);
7009
7010 /* get domain width, taking infinity at 1e20 on purpose */
7012
7013 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7014 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7015 * the idea is to penalize very large and very small domains
7016 */
7017 if( domainwidth >= 1.0 )
7018 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7019 else
7021
7022 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7023 }
7024 else
7025 cands[c].domain = 0.0;
7026
7027 if( conshdlrdata->branchdualweight > 0.0 )
7028 {
7029 SCIP_VAR* var;
7030
7031 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7032 assert(var != NULL);
7033
7034 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7035 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7036 }
7037
7038 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7039 {
7040 SCIP_VAR* var;
7041
7042 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7043 assert(var != NULL);
7044
7046 cands[c].pscost = SCIP_INVALID;
7047 else
7048 {
7049 SCIP_Real brpoint;
7050 SCIP_Real pscostdown;
7051 SCIP_Real pscostup;
7052 char strategy;
7053
7054 /* decide how to compute pseudo-cost scores
7055 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7056 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7057 */
7059 strategy = conshdlrdata->branchpscostupdatestrategy;
7060 else
7061 strategy = 'l';
7062
7064
7065 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7066 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7067 * For here, I use a simple #counts >= branchpscostreliable.
7068 * TODO use SCIPgetVarPseudocostCount() instead?
7069 */
7070 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7071 {
7072 switch( strategy )
7073 {
7074 case 's' :
7076 break;
7077 case 'd' :
7079 break;
7080 case 'l' :
7085 else
7087 break;
7088 default :
7089 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7091 }
7092 }
7093 else
7095
7096 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7097 {
7098 switch( strategy )
7099 {
7100 case 's' :
7102 break;
7103 case 'd' :
7105 break;
7106 case 'l' :
7111 else
7113 break;
7114 default :
7115 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7117 }
7118 }
7119 else
7121
7122 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7123 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7124 */
7126 cands[c].pscost = SCIP_INVALID;
7127 else if( pscostdown == SCIP_INVALID )
7128 cands[c].pscost = pscostup;
7129 else if( pscostup == SCIP_INVALID )
7130 cands[c].pscost = pscostdown;
7131 else
7132 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7133 }
7134
7135 if( cands[c].pscost != SCIP_INVALID )
7136 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7137 }
7138
7139 if( conshdlrdata->branchvartypeweight > 0.0 )
7140 {
7141 SCIP_VAR* var;
7142
7143 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7144 assert(var != NULL);
7145
7146 switch( SCIPvarGetType(var) )
7147 {
7148 case SCIP_VARTYPE_BINARY :
7149 cands[c].vartype = 1.0;
7150 break;
7152 cands[c].vartype = 0.1;
7153 break;
7155 cands[c].vartype = 0.01;
7156 break;
7158 default:
7159 cands[c].vartype = 0.0;
7160 }
7161 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7162 }
7163 }
7164
7165 /* now compute a weighted score for each candidate from the single scores
7166 * the single scores are scaled to be in [0,1] for this
7167 */
7168 for( c = 0; c < ncands; ++c )
7169 {
7170 SCIP_Real weightsum;
7171
7172 ENFOLOG(
7173 SCIP_VAR* var;
7174 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7176 )
7177
7178 cands[c].weighted = 0.0;
7179 weightsum = 0.0;
7180
7181 if( maxscore.auxviol > 0.0 )
7182 {
7183 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7184 weightsum += conshdlrdata->branchviolweight;
7185
7186 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7187 }
7188
7189 if( maxscore.domain > 0.0 )
7190 {
7191 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7192 weightsum += conshdlrdata->branchdomainweight;
7193
7194 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7195 }
7196
7197 if( maxscore.dual > 0.0 )
7198 {
7199 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7200 weightsum += conshdlrdata->branchdualweight;
7201
7202 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7203 }
7204
7205 if( maxscore.pscost > 0.0 )
7206 {
7207 /* use pseudo-costs only if available */
7208 if( cands[c].pscost != SCIP_INVALID )
7209 {
7210 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7211 weightsum += conshdlrdata->branchpscostweight;
7212
7213 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7214 }
7215 else
7216 {
7217 /* do not add pscostscore, if not available, also do not add into weightsum */
7218 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7219 }
7220 }
7221
7222 if( maxscore.vartype > 0.0 )
7223 {
7224 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7225 weightsum += conshdlrdata->branchvartypeweight;
7226
7227 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7228 }
7229 assert(weightsum > 0.0); /* we should have got at least one valid score */
7230 cands[c].weighted /= weightsum;
7231
7232 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7233 }
7234}
7235
7236/** compare two branching candidates by their weighted score
7237 *
7238 * if weighted score is equal, use variable index of (aux)var
7239 */
7240static
7242{
7243 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7244
7245 if( cands[ind1].weighted != cands[ind2].weighted )
7246 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7247 else
7249}
7250
7251/** do branching or register branching candidates */
7252static
7254 SCIP* scip, /**< SCIP data structure */
7255 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7256 SCIP_CONS** conss, /**< constraints to process */
7257 int nconss, /**< number of constraints */
7258 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7259 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7260 SCIP_Longint soltag, /**< tag of solution */
7261 SCIP_RESULT* result /**< pointer to store the result of branching */
7262 )
7263{
7264 SCIP_CONSHDLRDATA* conshdlrdata;
7265 BRANCHCAND* cands;
7266 int ncands;
7267 SCIP_VAR* var;
7271
7272 assert(conshdlr != NULL);
7273 assert(result != NULL);
7274
7276
7277 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7278 assert(conshdlrdata != NULL);
7279
7280 if( conshdlrdata->branchexternal )
7281 {
7282 /* just register branching candidates as external */
7283 SCIP_Bool success;
7284
7285 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7286 if( success )
7288
7289 return SCIP_OKAY;
7290 }
7291
7292 /* collect branching candidates and their auxviol-score */
7294 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7295
7296 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7297 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7298 */
7299 if( ncands == 0 )
7300 goto TERMINATE;
7301
7302 if( ncands > 1 )
7303 {
7304 /* if there are more than one candidate, then compute scores and select */
7305 int* perm;
7306 int c;
7307 int left;
7308 int right;
7309 SCIP_Real threshold;
7310
7311 /* compute additional scores on branching candidates and weighted score */
7312 scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7313
7314 /* sort candidates by weighted score */
7315 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7316 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7317
7318 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7319 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7320 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7321
7322 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7323 left = 0;
7324 right = ncands - 1;
7325 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7326 while( left < right )
7327 {
7328 int mid = (left + right) / 2;
7329 if( cands[perm[mid]].weighted >= threshold )
7330 left = mid + 1;
7331 else
7332 right = mid;
7333 }
7334 assert(left <= ncands);
7335
7336 if( left < ncands )
7337 {
7338 if( cands[perm[left]].weighted >= threshold )
7339 {
7340 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7341 ncands = left + 1;
7342 }
7343 else
7344 {
7345 assert(cands[perm[left]].weighted < threshold);
7346 ncands = left;
7347 }
7348 }
7349 assert(ncands > 0);
7350
7351 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7352 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7353 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7354
7355 if( ncands > 1 )
7356 {
7357 /* choose at random from candidates 0..ncands-1 */
7358 if( conshdlrdata->branchrandnumgen == NULL )
7359 {
7360 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7361 }
7362 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7363 var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7364 }
7365 else
7366 var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7367
7368 SCIPfreeBufferArray(scip, &perm);
7369 }
7370 else
7371 {
7372 var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7373 }
7374 assert(var != NULL);
7375
7376 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7378
7380 &upchild) );
7381 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7383 else
7384 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7386
7387 TERMINATE:
7388 SCIPfreeBufferArray(scip, &cands);
7389
7390 return SCIP_OKAY;
7391}
7392
7393/** call enforcement or estimate callback of nonlinear handler
7394 *
7395 * Calls the enforcement callback, if available.
7396 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7397 *
7398 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7399 */
7400static
7402 SCIP* scip, /**< SCIP main data structure */
7403 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7404 SCIP_CONS* cons, /**< nonlinear constraint */
7405 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7406 SCIP_EXPR* expr, /**< expression */
7407 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7408 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7409 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7410 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7411 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7412 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7413 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7414 SCIP_RESULT* result /**< pointer to store the result */
7415 )
7416{
7417 assert(result != NULL);
7418
7419 /* call enforcement callback of the nlhdlr */
7420 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7422
7423 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7425 {
7426 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7427 SCIPnlhdlrGetName(nlhdlr), *result); )
7428 return SCIP_OKAY;
7429 }
7430 else
7431 {
7432 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7433 }
7434
7436
7437 /* now call the estimator callback of the nlhdlr */
7438 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7439 {
7440 SCIP_VAR* auxvar;
7441 SCIP_Bool sepasuccess = FALSE;
7442 SCIP_Bool branchscoresuccess = FALSE;
7444 int minidx;
7445 int maxidx;
7446 int r;
7448
7450
7451 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7452 assert(auxvar != NULL);
7453
7454 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7456
7459
7460 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7461
7462 if( !sepasuccess )
7463 {
7464 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7465 SCIPnlhdlrGetName(nlhdlr)); )
7466 }
7467
7468 for( r = minidx; r <= maxidx; ++r )
7469 {
7471
7472 assert(rowprep != NULL);
7474
7475 /* complete estimator to cut */
7476 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7477
7478 /* add the cut and/or branching scores */
7479 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7481
7483 }
7484
7486 }
7487
7488 return SCIP_OKAY;
7489}
7490
7491/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7492 *
7493 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7494 */
7495static
7497 SCIP* scip, /**< SCIP data structure */
7498 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7499 SCIP_CONS* cons, /**< nonlinear constraint */
7500 SCIP_EXPR* expr, /**< expression */
7501 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7502 SCIP_Longint soltag, /**< tag of solution */
7503 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7504 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7505 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7506 )
7507{
7508 SCIP_CONSHDLRDATA* conshdlrdata;
7509 SCIP_EXPR_OWNERDATA* ownerdata;
7510 SCIP_Real origviol;
7511 SCIP_Bool underestimate;
7512 SCIP_Bool overestimate;
7513 SCIP_Real auxviol;
7514 SCIP_Bool auxunderestimate;
7515 SCIP_Bool auxoverestimate;
7517 int e;
7518
7519 assert(scip != NULL);
7520 assert(expr != NULL);
7521 assert(result != NULL);
7522
7523 ownerdata = SCIPexprGetOwnerData(expr);
7524 assert(ownerdata != NULL);
7525 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7526
7528
7529 /* make sure that this expression has been evaluated */
7530 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7531
7532 /* decide whether under- or overestimate is required and get amount of violation */
7533 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7534
7535 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7536 assert(conshdlrdata != NULL);
7537
7538 /* no sufficient violation w.r.t. the original variables -> skip expression */
7539 if( !overestimate && !underestimate )
7540 {
7541 return SCIP_OKAY;
7542 }
7543
7544 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7545 for( e = 0; e < ownerdata->nenfos; ++e )
7546 {
7547 SCIP_NLHDLR* nlhdlr;
7548
7549 /* skip nlhdlr that do not want to participate in any separation */
7550 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7551 continue;
7552
7553 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7554 assert(nlhdlr != NULL);
7555
7556 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7557 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7558 ENFOLOG(
7559 SCIPinfoMessage(scip, enfologfile, " expr ");
7561 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7562 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7563 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7564 )
7565
7566 /* TODO if expr is root of constraint (consdata->expr == expr),
7567 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7568 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7569 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7570 * so we should enforce in these auxiliaries first
7571 * if changing this here, we must also adapt analyzeViolation()
7572 */
7573
7574 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7575 assert(auxviol >= 0.0);
7576
7577 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7578 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7579 {
7580 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7581 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7582 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7583
7584 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7585 continue;
7586 }
7587
7588 /* 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 */
7589 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7590 {
7591 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7592 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7593 underestimate, overestimate); )
7594
7595 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7596 continue;
7597 }
7598
7599 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7600 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7601 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7602
7603 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7604 * wants to be called for separation on this side, then call separation of nlhdlr
7605 */
7606 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7607 {
7608 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7610 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7611 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7612
7613 if( hdlrresult == SCIP_CUTOFF )
7614 {
7615 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7617 ownerdata->lastenforced = conshdlrdata->enforound;
7618 break;
7619 }
7620
7621 if( hdlrresult == SCIP_SEPARATED )
7622 {
7623 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7625 ownerdata->lastenforced = conshdlrdata->enforound;
7626 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7627 break;
7628 }
7629
7631 {
7632 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7634 ownerdata->lastenforced = conshdlrdata->enforound;
7635 /* TODO or should we always just stop here? */
7636 }
7637
7638 if( hdlrresult == SCIP_BRANCHED )
7639 {
7640 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7642
7643 /* separation and domain reduction takes precedence over branching */
7645 if( *result == SCIP_DIDNOTFIND )
7647 ownerdata->lastenforced = conshdlrdata->enforound;
7648 }
7649 }
7650
7651 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7652 * wants to be called for separation on this side, then call separation of nlhdlr
7653 */
7654 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7655 {
7656 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7658 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7659 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7660
7661 if( hdlrresult == SCIP_CUTOFF )
7662 {
7663 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7665 ownerdata->lastenforced = conshdlrdata->enforound;
7666 break;
7667 }
7668
7669 if( hdlrresult == SCIP_SEPARATED )
7670 {
7671 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7673 ownerdata->lastenforced = conshdlrdata->enforound;
7674 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7675 break;
7676 }
7677
7679 {
7680 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7682 ownerdata->lastenforced = conshdlrdata->enforound;
7683 /* TODO or should we always just stop here? */
7684 }
7685
7686 if( hdlrresult == SCIP_BRANCHED )
7687 {
7688 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7690
7691 /* separation takes precedence over branching */
7693 if( *result == SCIP_DIDNOTFIND )
7695 ownerdata->lastenforced = conshdlrdata->enforound;
7696 }
7697 }
7698 }
7699
7700 return SCIP_OKAY;
7701}
7702
7703/** helper function to enforce a single constraint */
7704static
7706 SCIP* scip, /**< SCIP data structure */
7707 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7708 SCIP_CONS* cons, /**< constraint to process */
7709 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7710 SCIP_Longint soltag, /**< tag of solution */
7711 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7712 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7713 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7714 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7715 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7716 )
7717{
7718 SCIP_CONSDATA* consdata;
7719 SCIP_CONSHDLRDATA* conshdlrdata;
7720 SCIP_EXPR* expr;
7721
7722 assert(conshdlr != NULL);
7723 assert(cons != NULL);
7724 assert(it != NULL);
7725 assert(result != NULL);
7726 assert(success != NULL);
7727
7728 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7729 assert(conshdlrdata != NULL);
7730
7731 consdata = SCIPconsGetData(cons);
7732 assert(consdata != NULL);
7733 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7734
7735 *success = FALSE;
7736
7737 if( inenforcement && !consdata->ispropagated )
7738 {
7739 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7740 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7741 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7742 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7743 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7744 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7745 * confuse the stalling check for how long to do separation).
7746 */
7747 SCIP_Bool infeasible;
7748 int ntightenings;
7749
7750 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7751 if( infeasible )
7752 {
7754 return SCIP_OKAY;
7755 }
7756 /* if we tightened an auxvar bound, we better communicate that */
7757 if( ntightenings > 0 )
7759 }
7760
7761 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7762 {
7763 SCIP_EXPR_OWNERDATA* ownerdata;
7765
7766 ownerdata = SCIPexprGetOwnerData(expr);
7767 assert(ownerdata != NULL);
7768
7769 /* we can only enforce if there is an auxvar to compare with */
7770 if( ownerdata->auxvar == NULL )
7771 continue;
7772
7773 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7774 if( ownerdata->lastenforced == conshdlrdata->enforound )
7775 {
7776 ENFOLOG(
7777 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7779 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7780 )
7781 *success = TRUE;
7782 continue;
7783 }
7784
7785 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7786
7787 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7788 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7789 if( ownerdata->lastenforced == conshdlrdata->enforound )
7790 *success = TRUE;
7791
7792 if( resultexpr == SCIP_CUTOFF )
7793 {
7795 break;
7796 }
7797
7798 if( resultexpr == SCIP_SEPARATED )
7800
7803
7806 }
7807
7808 return SCIP_OKAY;
7809}
7810
7811/** try to separate violated constraints and, if in enforcement, register branching scores
7812 *
7813 * Sets result to
7814 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7815 * - SCIP_CUTOFF, if node can be cutoff,
7816 * - SCIP_SEPARATED, if a cut has been added,
7817 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7818 * - SCIP_BRANCHED, if branching has been done,
7819 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7820 * - SCIP_INFEASIBLE, if external branching candidates were registered
7821 */
7822static
7824 SCIP* scip, /**< SCIP data structure */
7825 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7826 SCIP_CONS** conss, /**< constraints to process */
7827 int nconss, /**< number of constraints */
7828 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7829 SCIP_Longint soltag, /**< tag of solution */
7830 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7831 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7832 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7833 )
7834{
7835 SCIP_CONSHDLRDATA* conshdlrdata;
7837 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7838 int c;
7839
7840 assert(conshdlr != NULL);
7841 assert(conss != NULL || nconss == 0);
7842 assert(result != NULL);
7843
7844 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7845 assert(conshdlrdata != NULL);
7846
7847 /* increase tag to tell whether branching scores in expression belong to this sweep
7848 * and which expressions have already been enforced in this sweep
7849 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7850 */
7851 ++(conshdlrdata->enforound);
7852
7854
7857
7858 for( c = 0; c < nconss; ++c )
7859 {
7860 assert(conss != NULL && conss[c] != NULL);
7861
7862 /* skip constraints that are not enabled or deleted */
7863 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7864 continue;
7865 assert(SCIPconsIsActive(conss[c]));
7866
7867 /* skip constraints that have separation disabled if we are only in separation */
7869 continue;
7870
7871 /* skip non-violated constraints */
7872 if( !isConsViolated(scip, conss[c]) )
7873 continue;
7874
7875 ENFOLOG(
7876 {
7877 SCIP_CONSDATA* consdata;
7878 int i;
7879 consdata = SCIPconsGetData(conss[c]);
7880 assert(consdata != NULL);
7881 SCIPinfoMessage(scip, enfologfile, " constraint ");
7883 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7884 for( i = 0; i < consdata->nvarexprs; ++i )
7885 {
7886 SCIP_VAR* var;
7887 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7888 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7890 }
7891 })
7892
7894
7895 if( *result == SCIP_CUTOFF )
7896 break;
7897
7898 if( !consenforced && inenforcement )
7899 {
7900 SCIP_Real viol;
7901
7902 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7903 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7904 {
7905 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7906 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7907
7909
7910 if( consenforced )
7911 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7912
7913 if( *result == SCIP_CUTOFF )
7914 break;
7915 }
7916 }
7917 }
7918
7920
7922
7923 /* if having branching scores, then propagate them from expressions with children to variable expressions */
7924 if( *result == SCIP_BRANCHED )
7925 {
7926 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7927 * branching
7928 */
7929 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7930
7931 /* branching should either have branched: result == SCIP_BRANCHED,
7932 * or fixed a variable: result == SCIP_REDUCEDDOM,
7933 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7934 * or have not done anything: result == SCIP_DIDNOTFIND
7935 */
7937 }
7938
7940
7941 return SCIP_OKAY;
7942}
7943
7944/** collect (and print (if debugging enfo)) information on violation in expressions
7945 *
7946 * assumes that constraint violations have been computed
7947 */
7948static
7950 SCIP* scip, /**< SCIP data structure */
7951 SCIP_CONS** conss, /**< constraints */
7952 int nconss, /**< number of constraints */
7953 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7954 SCIP_Longint soltag, /**< tag of solution */
7955 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7956 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7957 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7958 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7959 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7960 )
7961{
7962 SCIP_CONSDATA* consdata;
7964 SCIP_EXPR* expr;
7965 SCIP_Real v;
7966 int c;
7967
7968 assert(conss != NULL || nconss == 0);
7973
7976
7977 *maxabsconsviol = 0.0;
7978 *maxrelconsviol = 0.0;
7980 *maxauxviol = 0.0;
7981 *maxvarboundviol = 0.0;
7982
7983 for( c = 0; c < nconss; ++c )
7984 {
7985 assert(conss != NULL && conss[c] != NULL);
7986
7987 consdata = SCIPconsGetData(conss[c]);
7988 assert(consdata != NULL);
7989
7990 /* skip constraints that are not enabled, deleted, or have separation disabled */
7991 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7992 continue;
7993 assert(SCIPconsIsActive(conss[c]));
7994
7995 v = getConsAbsViolation(conss[c]);
7997
7998 /* skip non-violated constraints */
7999 if( !isConsViolated(scip, conss[c]) )
8000 continue;
8001
8002 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8004
8005 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8006 {
8007 SCIP_EXPR_OWNERDATA* ownerdata;
8008 SCIP_Real auxvarvalue;
8009 SCIP_Real auxvarlb;
8010 SCIP_Real auxvarub;
8011 SCIP_Bool violunder;
8012 SCIP_Bool violover;
8013 SCIP_Real origviol;
8014 SCIP_Real auxviol;
8015 int e;
8016
8017 ownerdata = SCIPexprGetOwnerData(expr);
8018 assert(ownerdata != NULL);
8019
8020 if( ownerdata->auxvar == NULL )
8021 {
8022 /* check violation of variable bounds of original variable */
8023 if( SCIPisExprVar(scip, expr) )
8024 {
8025 SCIP_VAR* var;
8026 var = SCIPgetVarExprVar(expr);
8030
8031 origviol = 0.0;
8036 if( origviol <= 0.0 )
8037 continue;
8038
8040
8041 ENFOLOG(
8042 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8044 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8046 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8048 )
8049 }
8050
8051 continue;
8052 }
8053
8054 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8055 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8056 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8057
8058 /* check violation of variable bounds of auxiliary variable */
8063
8065
8066 ENFOLOG(
8067 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8068 {
8069 SCIPinfoMessage(scip, enfologfile, "expr ");
8071 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8072
8073 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8074 if( origviol > 0.0 )
8075 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8077 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8079 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8081 }
8082 )
8083
8084 /* no violation w.r.t. the original variables -> skip expression */
8085 if( origviol == 0.0 )
8086 continue;
8087
8088 /* compute aux-violation for each nonlinear handlers */
8089 for( e = 0; e < ownerdata->nenfos; ++e )
8090 {
8091 SCIP_NLHDLR* nlhdlr;
8092
8093 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8094 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8095 continue;
8096
8097 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8098 assert(nlhdlr != NULL);
8099
8100 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8101 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8102
8103 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8104
8105 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8106
8107 if( auxviol > 0.0 )
8108 {
8109 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8110 *maxauxviol = MAX(*maxauxviol, auxviol);
8111 *minauxviol = MIN(*minauxviol, auxviol);
8112 }
8114 }
8115 }
8116 }
8117
8119
8120 return SCIP_OKAY;
8121} /*lint !e715*/
8122
8123/** enforcement of constraints called by enfolp and enforelax */
8124static
8126 SCIP* scip, /**< SCIP data structure */
8127 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8128 SCIP_CONS** conss, /**< constraints to process */
8129 int nconss, /**< number of constraints */
8130 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8131 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8132 )
8133{
8134 SCIP_CONSHDLRDATA* conshdlrdata;
8135 SCIP_Real maxabsconsviol;
8136 SCIP_Real maxrelconsviol;
8137 SCIP_Real minauxviol;
8138 SCIP_Real maxauxviol;
8139 SCIP_Real maxvarboundviol;
8140 SCIP_Longint soltag;
8141 int nnotify;
8142 int c;
8143
8144 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8145 assert(conshdlr != NULL);
8146
8148
8150 for( c = 0; c < nconss; ++c )
8151 {
8152 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8153
8154 if( isConsViolated(scip, conss[c]) )
8156 }
8157
8158 if( *result == SCIP_FEASIBLE )
8159 {
8160 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8162 return SCIP_OKAY;
8163 }
8164
8167
8168 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8169 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8172
8174
8175 /* try to propagate */
8176 if( conshdlrdata->propinenforce )
8177 {
8179 int nchgbds = 0;
8180
8181 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8182
8184 {
8185 *result = propresult;
8186 return SCIP_OKAY;
8187 }
8188 }
8189
8190 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8191 * all violated expr/auxvar in violated constraints)
8192 */
8193 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8194 sol == NULL )
8195 {
8197 ++conshdlrdata->ntightenlp;
8198
8200
8201 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8202 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8203
8204 return SCIP_OKAY;
8205 }
8206
8207 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8208 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8209 */
8210 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8211 {
8213 ++conshdlrdata->ntightenlp;
8214
8216
8217 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8218
8219 return SCIP_OKAY;
8220 }
8221
8222 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8223
8226 return SCIP_OKAY;
8227
8229
8230 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8231 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8232
8233 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8234 {
8236 ++conshdlrdata->ntightenlp;
8237
8239
8240 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8241 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8242
8243 return SCIP_OKAY;
8244 }
8245
8246 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8247 SCIPgetLPFeastol(scip)) && sol == NULL )
8248 {
8249 /* try whether tighten the LP feasibility tolerance could help
8250 * maybe it is just some cut that hasn't been taken into account sufficiently
8251 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8252 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8253 * until the LP feastol reaches epsilon
8254 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8255 * when maxauxviol is above LP feastol)
8256 */
8258 ++conshdlrdata->ndesperatetightenlp;
8259
8261
8262 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8263
8264 return SCIP_OKAY;
8265 }
8266
8267 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8268 if( !conshdlrdata->propinenforce )
8269 {
8271 int nchgbds = 0;
8272
8273 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8274
8276 {
8277 *result = propresult;
8278 return SCIP_OKAY;
8279 }
8280 }
8281
8282 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8283 * now look if we find any unfixed variable that we could still branch on
8284 */
8285 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8286
8287 if( nnotify > 0 )
8288 {
8289 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8290 ++conshdlrdata->ndesperatebranch;
8291
8292 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8293
8294 return SCIP_OKAY;
8295 }
8296
8297 /* if everything is fixed in violated constraints, then let's cut off the node
8298 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8299 * result may not be conclusive (when constraint violations are small)
8300 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8301 * sufficiently (see st_e40)
8302 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8303 * not "desperate", but a pretty obvious thing to do
8304 */
8305 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8307
8308 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8310 ++conshdlrdata->ndesperatecutoff;
8311
8312 return SCIP_OKAY;
8313}
8314
8315/** separation for all violated constraints to be used by SEPA callbacks */
8316static
8318 SCIP* scip, /**< SCIP data structure */
8319 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8320 SCIP_CONS** conss, /**< constraints to process */
8321 int nconss, /**< number of constraints */
8322 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8323 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8324 )
8325{
8326 SCIP_Longint soltag;
8327 SCIP_Bool haveviol = FALSE;
8328 int c;
8329
8331
8333
8334 /* compute violations */
8335 for( c = 0; c < nconss; ++c )
8336 {
8337 assert(conss[c] != NULL);
8338
8339 /* skip constraints that are not enabled, deleted, or have separation disabled */
8340 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8341 continue;
8342 assert(SCIPconsIsActive(conss[c]));
8343
8344 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8345
8346 if( isConsViolated(scip, conss[c]) )
8347 haveviol = TRUE;
8348 }
8349
8350 /* if none of our constraints are violated, don't attempt separation */
8351 if( !haveviol )
8352 {
8353 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8354 return SCIP_OKAY;
8355 }
8356
8358
8359 /* call separation */
8360 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8361
8362 return SCIP_OKAY;
8363}
8364
8365/** hash key retrieval function for bilinear term entries */
8366static
8368{ /*lint --e{715}*/
8369 SCIP_CONSHDLRDATA* conshdlrdata;
8370 int idx;
8371
8372 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8373 assert(conshdlrdata != NULL);
8374
8375 idx = ((int)(size_t)elem) - 1;
8376 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8377
8378 return (void*)&conshdlrdata->bilinterms[idx];
8379}
8380
8381/** returns TRUE iff the bilinear term entries are equal */
8382static
8384{ /*lint --e{715}*/
8387
8388 /* get corresponding entries */
8391 assert(entry1->x != NULL && entry1->y != NULL);
8392 assert(entry2->x != NULL && entry2->y != NULL);
8393 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8394 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8395
8396 return entry1->x == entry2->x && entry1->y == entry2->y;
8397}
8398
8399/** returns the hash value of the key */
8400static
8411
8412/** compare two auxiliary expressions
8413 *
8414 * Compares auxiliary variables, followed by coefficients, and then constants.
8415 */
8416static
8418{
8421 int compvars;
8422 int i;
8423
8424 /* compare the auxiliary variables */
8425 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8426
8427 if( compvars != 0 )
8428 return compvars;
8429
8430 /* compare the coefficients and constants */
8431 for( i = 0; i < 3; ++i )
8432 {
8433 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8434 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8435 }
8436
8437 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8438}
8439
8440/* add an auxiliary expression to a bilinear term */
8441static
8443 SCIP* scip, /**< SCIP data structure */
8444 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8445 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8446 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8447 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8448 )
8449{
8450 SCIP_Bool found;
8451 int pos;
8452 int i;
8453
8454 *added = FALSE;
8455
8456 /* check if auxexpr has already been added to term */
8457 if( term->nauxexprs == 0 )
8458 {
8459 found = FALSE;
8460 pos = 0;
8461 }
8462 else
8463 {
8464 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8465 }
8466
8467 if( !found )
8468 {
8469 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8470 return SCIP_OKAY;
8471
8472 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8473 assert(term->auxexprssize >= term->nauxexprs + 1);
8474
8475 /* insert expression at the correct position */
8476 for( i = term->nauxexprs; i > pos; --i )
8477 {
8478 term->aux.exprs[i] = term->aux.exprs[i-1];
8479 }
8480 term->aux.exprs[pos] = auxexpr;
8481 ++(term->nauxexprs);
8482 *added = TRUE;
8483 }
8484 else
8485 {
8486 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8487 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8488 }
8489
8490 return SCIP_OKAY;
8491}
8492
8493/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8494static
8496 SCIP* scip, /**< SCIP data structure */
8497 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8498 SCIP_CONS** conss, /**< nonlinear constraints */
8499 int nconss /**< total number of nonlinear constraints */
8500 )
8501{
8502 SCIP_CONSHDLRDATA* conshdlrdata;
8504 int c;
8505
8506 assert(conss != NULL || nconss == 0);
8507
8508 if( nconss == 0 )
8509 return SCIP_OKAY;
8510
8511 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8512 assert(conshdlrdata != NULL);
8513
8514 /* check whether the bilinear terms have been stored already */
8515 if( conshdlrdata->bilinterms != NULL )
8516 return SCIP_OKAY;
8517
8518 /* create and initialize iterator */
8522
8523 /* iterate through all constraints */
8524 for( c = 0; c < nconss; ++c )
8525 {
8526 SCIP_CONSDATA* consdata;
8527 SCIP_EXPR* expr;
8528
8529 assert(conss != NULL && conss[c] != NULL);
8530 consdata = SCIPconsGetData(conss[c]);
8531 assert(consdata != NULL);
8532
8533 /* iterate through all expressions */
8534 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8535 {
8536 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8537 SCIP_VAR* x = NULL;
8538 SCIP_VAR* y = NULL;
8539
8540 /* check whether the expression is of the form f(..)^2 */
8541 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8542 {
8543 x = SCIPgetExprAuxVarNonlinear(children[0]);
8544 y = x;
8545 }
8546 /* check whether the expression is of the form f(..) * g(..) */
8547 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8548 {
8549 x = SCIPgetExprAuxVarNonlinear(children[0]);
8550 y = SCIPgetExprAuxVarNonlinear(children[1]);
8551 }
8552
8553 /* add variables to the hash table */
8554 if( x != NULL && y != NULL )
8555 {
8558 }
8559 }
8560 }
8561
8562 /* release iterator */
8564
8565 return SCIP_OKAY;
8566}
8567
8568/** store x, y and the locks in a new bilinear term */
8569static
8571 SCIP* scip, /**< SCIP data structure */
8572 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8573 SCIP_VAR* x, /**< the first variable */
8574 SCIP_VAR* y, /**< the second variable */
8575 int nlockspos, /**< number of positive locks of the bilinear term */
8576 int nlocksneg, /**< number of negative locks of the bilinear term */
8577 int* idx, /**< pointer to store the position of the term in bilinterms array */
8578 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8579 )
8580{
8581 SCIP_CONSHDLRDATA* conshdlrdata;
8583
8584 assert(conshdlr != NULL);
8585 assert(x != NULL);
8586 assert(y != NULL);
8587 assert(nlockspos >= 0);
8588 assert(nlocksneg >= 0);
8589
8590 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8591 assert(conshdlrdata != NULL);
8592
8593 /* ensure that x.index <= y.index */
8594 if( SCIPvarCompare(x, y) == 1 )
8595 {
8596 SCIPswapPointers((void**)&x, (void**)&y);
8597 }
8598 assert(SCIPvarCompare(x, y) < 1);
8599
8600 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8601
8602 /* update or create the term */
8603 if( *idx >= 0 )
8604 { /* the term has already been added */
8605 assert(conshdlrdata->bilinterms[*idx].x == x);
8606 assert(conshdlrdata->bilinterms[*idx].y == y);
8607
8608 /* get term and add locks */
8609 term = &conshdlrdata->bilinterms[*idx];
8610 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8611 term->nlockspos += nlockspos;
8612 term->nlocksneg += nlocksneg;
8613 }
8614 else
8615 { /* this is the first time we encounter this product */
8616 /* ensure size of bilinterms array */
8617 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8618
8619 *idx = conshdlrdata->nbilinterms;
8620
8621 /* get term and set values in the created bilinear term */
8622 term = &conshdlrdata->bilinterms[*idx];
8623 assert(term != NULL);
8624 term->x = x;
8625 term->y = y;
8626 term->nauxexprs = 0;
8627 term->auxexprssize = 0;
8628 term->nlockspos = nlockspos;
8629 term->nlocksneg = nlocksneg;
8630 term->existing = existing;
8631 if( existing )
8632 term->aux.var = NULL;
8633 else
8634 term->aux.exprs = NULL;
8635
8636 /* increase the total number of bilinear terms */
8637 ++(conshdlrdata->nbilinterms);
8638
8639 /* save to the hashtable */
8640 if( conshdlrdata->bilinhashtable == NULL )
8641 {
8642 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8644 (void*)conshdlrdata) );
8645 }
8646 assert(conshdlrdata->bilinhashtable != NULL);
8647
8648 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8649 * because zero can not be inserted into hash table
8650 */
8651 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8652
8653 /* capture product variables */
8656 }
8657
8658 return SCIP_OKAY;
8659}
8660
8661/** frees array of bilinear terms and hash table */
8662static
8664 SCIP* scip, /**< SCIP data structure */
8665 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8666 )
8667{
8668 int i;
8669 int j;
8670
8671 assert(conshdlrdata != NULL);
8672
8673 /* check whether bilinear terms have been stored */
8674 if( conshdlrdata->bilinterms == NULL )
8675 {
8676 assert(conshdlrdata->bilinterms == NULL);
8677 assert(conshdlrdata->nbilinterms == 0);
8678 assert(conshdlrdata->bilintermssize == 0);
8679
8680 return SCIP_OKAY;
8681 }
8682
8683 /* release variables */
8684 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8685 {
8686 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8687 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8688
8689 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8690 {
8691 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8692 {
8693 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8694 }
8695 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8696 }
8697
8698 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8699 {
8700 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8701 continue;
8702 }
8703
8704 /* the rest is for simple terms with a single auxvar */
8705
8706 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8707 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8708 {
8709 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8710 }
8711 }
8712
8713 /* free hash table */
8714 if( conshdlrdata->bilinhashtable != NULL )
8715 {
8716 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8717 }
8718
8719 /* free bilinterms array; reset counters */
8720 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8721 conshdlrdata->nbilinterms = 0;
8722 conshdlrdata->bilintermssize = 0;
8723
8724 return SCIP_OKAY;
8725}
8726
8727/*
8728 * vertex polyhedral separation
8729 */
8730
8731/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8732static
8734 SCIP* scip, /**< SCIP data structure */
8735 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8736 SCIP_LPI** lp /**< pointer to store created LP */
8737 )
8738{
8739 SCIP_Real* obj;
8740 SCIP_Real* lb;
8741 SCIP_Real* ub;
8742 SCIP_Real* val;
8743 int* beg;
8744 int* ind;
8745 unsigned int nnonz;
8746 unsigned int ncols;
8747 unsigned int nrows;
8748 unsigned int i;
8749 unsigned int k;
8750
8751 assert(scip != NULL);
8752 assert(lp != NULL);
8753 assert(nvars > 0);
8755
8756 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8757
8758 /* create lpi to store the LP */
8760
8761 nrows = (unsigned int)nvars + 1;
8762 ncols = POWEROFTWO((unsigned int)nvars);
8763 nnonz = (ncols * (nrows + 1)) / 2;
8764
8765 /* allocate necessary memory; set obj, lb, and ub to zero */
8768 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8770 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8772
8773 /* calculate nonzero entries in the LP */
8774 for( i = 0, k = 0; i < ncols; ++i )
8775 {
8776 int row;
8777 unsigned int a;
8778
8779 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8780 ub[i] = SCIPlpiInfinity(*lp);
8781
8782 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8783 beg[i] = (int)k;
8784 row = 0;
8785
8786 /* iterate through the bit representation of i */
8787 a = 1;
8788 while( a <= i )
8789 {
8790 if( (a & i) != 0 )
8791 {
8792 val[k] = 1.0;
8793 ind[k] = row;
8794
8795 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8796
8797 ++k;
8798 }
8799
8800 a <<= 1;
8801 ++row;
8802 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8803 assert(POWEROFTWO(row) == a);
8804 }
8805
8806 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8807 val[k] = 1.0;
8808 ind[k] = (int)nrows - 1;
8809 ++k;
8810 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8811 }
8812 assert(k == nnonz);
8813
8814 /* load all data into LP interface
8815 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8816 */
8817 assert(nrows <= ncols);
8819 (int)ncols, obj, lb, ub, NULL,
8820 (int)nrows, lb, lb, NULL,
8821 (int)nnonz, beg, ind, val) );
8822
8823 /* for the last row, we can set the rhs to 1.0 already */
8824 ind[0] = (int)nrows - 1;
8825 val[0] = 1.0;
8826 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8827
8828 /* free allocated memory */
8835
8836 return SCIP_OKAY;
8837}
8838
8839/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8840 * \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
8841 * set of vertices of the domain
8842 */
8843static
8845 SCIP* scip, /**< SCIP data structure */
8846 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8847 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8848 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8849 int nallvars, /**< number of all variables */
8850 int nvars, /**< number of unfixed variables */
8851 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8852 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8853 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8854 )
8855{
8856 SCIP_Real maxerror;
8857 SCIP_Real facetval;
8858 SCIP_Real funval;
8859 SCIP_Real error;
8860 unsigned int i;
8861 unsigned int ncorners;
8862 unsigned int prev;
8863
8864 assert(scip != NULL);
8865 assert(funvals != NULL);
8866 assert(box != NULL);
8869
8871 maxerror = 0.0;
8872
8873 /* check the origin (all variables at lower bound) */
8875 for( i = 0; i < (unsigned int) nallvars; ++i )
8876 facetval += facetcoefs[i] * box[2*i];
8877
8878 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8879 funval = funvals[0];
8880 if( overestimate )
8881 error = funval - facetval;
8882 else
8883 error = facetval - funval;
8884
8885 /* update maximum error */
8887
8888 prev = 0;
8889 for( i = 1; i < ncorners; ++i )
8890 {
8891 unsigned int gray;
8892 unsigned int diff;
8893 unsigned int pos;
8894 int origpos;
8895
8896 gray = i ^ (i >> 1);
8897 diff = gray ^ prev;
8898
8899 /* compute position of unique 1 of diff */
8900 pos = 0;
8901 while( (diff >>= 1) != 0 )
8902 ++pos;
8903 assert(pos < (unsigned int)nvars);
8904
8905 origpos = nonfixedpos[pos];
8906
8907 if( gray > prev )
8908 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8909 else
8910 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8911
8912 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8913 funval = funvals[gray];
8914 if( overestimate )
8915 error = funval - facetval;
8916 else
8917 error = facetval - funval;
8918
8919 /* update maximum error */
8921
8922 prev = gray;
8923 }
8924
8925 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8926
8927 return maxerror;
8928}
8929
8930/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8931static
8933 SCIP* scip, /**< SCIP data structure */
8934 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8935 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8936 SCIP_Real* xstar, /**< point to be separated */
8937 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8938 int nallvars, /**< half of the length of box */
8939 int* nonfixedpos, /**< indices of nonfixed variables */
8940 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8941 int nvars, /**< number of nonfixed variables */
8942 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8943 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8944 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8945 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8946 )
8947{ /*lint --e{715}*/
8948 SCIP_CONSHDLRDATA* conshdlrdata;
8949 SCIP_LPI* lp;
8950 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8951 int* inds;
8952 int ncols;
8953 int nrows;
8954 int i;
8955 SCIP_Real facetvalue;
8956 SCIP_Real mindomwidth;
8958
8959 assert(scip != NULL);
8960 assert(conshdlr != NULL);
8961 assert(xstar != NULL);
8962 assert(box != NULL);
8964 assert(funvals != NULL);
8965 assert(nvars >= 0);
8967 assert(success != NULL);
8970
8971 *success = FALSE;
8972
8973 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8974 assert(conshdlrdata != NULL);
8975
8976 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8977 {
8978 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8979 }
8980
8981 /* construct an LP for this size, if not having one already */
8982 if( conshdlrdata->vp_lp[nvars] == NULL )
8983 {
8984 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8985 }
8986 lp = conshdlrdata->vp_lp[nvars];
8987 assert(lp != NULL);
8988
8989 /* get number of cols and rows of separation lp */
8990 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8991 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8992
8993 /* number of columns should equal the number of corners = 2^nvars */
8994 assert(ncols == (int)POWEROFTWO(nvars));
8995
8996 /* allocate necessary memory */
8997 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8998 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8999
9000 /*
9001 * set up the described LP on the transformed space
9002 */
9003
9004 for( i = 0; i < ncols; ++i )
9005 inds[i] = i;
9006
9007 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9009 for( i = 0; i < nrows-1; ++i )
9010 {
9011 SCIP_Real solval;
9012 SCIP_Real lb;
9013 SCIP_Real ub;
9014 int varpos;
9015
9016 assert(i < nvars);
9017
9018 varpos = nonfixedpos[i];
9019 lb = box[2 * varpos];
9020 ub = box[2 * varpos + 1];
9021 solval = xstar[varpos];
9022
9023 if( ub - lb < mindomwidth )
9024 mindomwidth = ub - lb;
9025
9026 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9027 if( solval <= lb )
9028 aux[i] = 0.0;
9029 else if( solval >= ub )
9030 aux[i] = 1.0;
9031 else
9032 aux[i] = (solval - lb) / (ub - lb);
9033
9034 /* perturb point to hopefully obtain a facet of the convex envelope */
9035 if( conshdlrdata->vp_maxperturb > 0.0 )
9036 {
9037 assert(conshdlrdata->vp_randnumgen != NULL);
9038
9039 if( aux[i] == 1.0 )
9040 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9041 else if( aux[i] == 0.0 )
9042 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9043 else
9044 {
9045 SCIP_Real perturbation;
9046
9047 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9048 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9049 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9050 }
9051 assert(0.0 < aux[i] && aux[i] < 1.0);
9052 }
9053
9054 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9055 }
9056
9057 /* update LP */
9058 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9059 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9061
9062 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9063 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9064 {
9065 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9066 }
9067 /* set an iteration limit so we do not run forever */
9069 /* 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 */
9071 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9072 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9073 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9074 */
9076
9077#ifdef SCIP_DEBUG
9079#endif
9080
9081 /*
9082 * solve the LP and store the resulting facet for the transformed space
9083 */
9084 if( conshdlrdata->vp_dualsimplex )
9085 {
9087 }
9088 else
9089 {
9091 }
9093 {
9094 SCIPdebugMsg(scip, "LP error, aborting.\n");
9095 goto CLEANUP;
9096 }
9098
9099 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9100 if( !SCIPlpiIsDualFeasible(lp) )
9101 {
9102 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9103 goto CLEANUP;
9104 }
9105
9106 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9107 * columns than needed, in particular, \bar \beta is the last dual multiplier
9108 */
9109 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9110
9111 for( i = 0; i < nvars; ++i )
9112 facetcoefs[nonfixedpos[i]] = aux[i];
9113 /* last dual multiplier is the constant */
9114 *facetconstant = aux[nrows - 1];
9115
9116#ifdef SCIP_DEBUG
9117 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9118 for( i = 0; i < nallvars; ++i )
9119 {
9120 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9121 }
9122 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9123#endif
9124
9125 /*
9126 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9127 */
9128
9129 SCIPdebugMsg(scip, "facet in orig. space: ");
9130
9131 facetvalue = 0.0;
9132 for( i = 0; i < nvars; ++i )
9133 {
9134 SCIP_Real lb;
9135 SCIP_Real ub;
9136 int varpos;
9137
9138 varpos = nonfixedpos[i];
9139 lb = box[2 * varpos];
9140 ub = box[2 * varpos + 1];
9141 assert(!SCIPisEQ(scip, lb, ub));
9142
9143 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9144 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9145
9146 /* beta = beta_bar - sum_i alpha_i * lb_i */
9147 *facetconstant -= facetcoefs[varpos] * lb;
9148
9149 /* evaluate */
9150 facetvalue += facetcoefs[varpos] * xstar[varpos];
9151
9152 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9153 }
9155
9156 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9158
9159 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9160
9161 /* if overestimate, then we want facetvalue < targetvalue
9162 * if underestimate, then we want facetvalue > targetvalue
9163 * if none holds, give up
9164 * so maybe here we should check against the minimal violation
9165 */
9166 if( overestimate == (facetvalue > targetvalue) )
9167 {
9168 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9169 goto CLEANUP;
9170 }
9171
9172 /* if we made it until here, then we have a nice facet */
9173 *success = TRUE;
9174
9175CLEANUP:
9176 /* free allocated memory */
9177 SCIPfreeBufferArray(scip, &inds);
9179
9180 return SCIP_OKAY;
9181}
9182
9183/** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9184 *
9185 * In other words, compute the line that passes through two given points.
9186 */
9187static
9189 SCIP* scip, /**< SCIP data structure */
9190 SCIP_Real left, /**< left coordinate */
9191 SCIP_Real right, /**< right coordinate */
9192 SCIP_Real funleft, /**< value of function in left coordinate */
9193 SCIP_Real funright, /**< value of function in right coordinate */
9194 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9195 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9196 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9197 )
9198{
9199 assert(scip != NULL);
9200 assert(SCIPisLE(scip, left, right));
9201 assert(!SCIPisInfinity(scip, -left));
9202 assert(!SCIPisInfinity(scip, right));
9205 assert(success != NULL);
9206 assert(facetcoef != NULL);
9208
9209 *facetcoef = (funright - funleft) / (right - left);
9210 *facetconstant = funleft - *facetcoef * left;
9211
9212 *success = TRUE;
9213
9214 return SCIP_OKAY;
9215}
9216
9217/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9218 *
9219 * Three points a, b, and c are given.
9220 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9221 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9222 */
9223static
9225 SCIP* scip, /**< SCIP data structure */
9226 SCIP_Real a1, /**< first coordinate of a */
9227 SCIP_Real a2, /**< second coordinate of a */
9228 SCIP_Real a3, /**< third coordinate of a */
9229 SCIP_Real b1, /**< first coordinate of b */
9230 SCIP_Real b2, /**< second coordinate of b */
9231 SCIP_Real b3, /**< third coordinate of b */
9232 SCIP_Real c1, /**< first coordinate of c */
9233 SCIP_Real c2, /**< second coordinate of c */
9234 SCIP_Real c3, /**< third coordinate of c */
9235 SCIP_Real* alpha, /**< coefficient of first coordinate */
9236 SCIP_Real* beta, /**< coefficient of second coordinate */
9237 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9238 SCIP_Real* delta /**< constant right-hand side */
9239 )
9240{
9241 assert(scip != NULL);
9242 assert(alpha != NULL);
9243 assert(beta != NULL);
9244 assert(gamma_ != NULL);
9245 assert(delta != NULL);
9246
9247 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9248 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9249 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9250 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9251
9252 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9253
9254 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9257 {
9258 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9259 *delta = 0.0;
9260 *alpha = 0.0;
9261 *beta = 0.0;
9262 *gamma_ = 0.0;
9263 return SCIP_OKAY;
9264 }
9265
9266 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9267 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9268 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9269 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9270 {
9271 SCIP_Real m[9];
9272 SCIP_Real rhs[3];
9273 SCIP_Real x[3];
9274 SCIP_Bool success;
9275
9276 /*
9277 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));
9278 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));
9279 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));
9280 */
9281
9282 /* initialize matrix column-wise */
9283 m[0] = a1;
9284 m[1] = b1;
9285 m[2] = c1;
9286 m[3] = a2;
9287 m[4] = b2;
9288 m[5] = c2;
9289 m[6] = a3;
9290 m[7] = b3;
9291 m[8] = c3;
9292
9293 rhs[0] = 1.0;
9294 rhs[1] = 1.0;
9295 rhs[2] = 1.0;
9296
9297 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9298
9299 /* solve the linear problem */
9301
9302 *delta = rhs[0];
9303 *alpha = x[0];
9304 *beta = x[1];
9305 *gamma_ = x[2];
9306
9307 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9308 * not add a cut to SCIP and that all assertions are trivially fulfilled
9309 */
9310 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9311 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9312 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9313 {
9314 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9315 *delta = 0.0;
9316 *alpha = 0.0;
9317 *beta = 0.0;
9318 *gamma_ = 0.0;
9319 }
9320 }
9321
9322 if( *gamma_ < 0.0 )
9323 {
9324 *alpha = -*alpha;
9325 *beta = -*beta;
9326 *gamma_ = -*gamma_;
9327 *delta = -*delta;
9328 }
9329
9330 return SCIP_OKAY;
9331}
9332
9333/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9334static
9336 SCIP* scip, /**< SCIP data structure */
9337 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9338 SCIP_Real p1[2], /**< first vertex of box */
9339 SCIP_Real p2[2], /**< second vertex of box */
9340 SCIP_Real p3[2], /**< third vertex of box */
9341 SCIP_Real p4[2], /**< forth vertex of box */
9342 SCIP_Real p1val, /**< value in p1 */
9343 SCIP_Real p2val, /**< value in p2 */
9344 SCIP_Real p3val, /**< value in p3 */
9345 SCIP_Real p4val, /**< value in p4 */
9346 SCIP_Real xstar[2], /**< point to be separated */
9347 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9348 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9349 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9350 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9351 )
9352{
9353 SCIP_Real alpha, beta, gamma_, delta;
9354 SCIP_Real xstarval, candxstarval = 0.0;
9355 int leaveout;
9356
9357 assert(scip != NULL);
9358 assert(success != NULL);
9365
9366 *success = FALSE;
9367
9368 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9369 if( !overestimate )
9370 {
9371 p1val = -p1val;
9372 p2val = -p2val;
9373 p3val = -p3val;
9374 p4val = -p4val;
9375 targetvalue = -targetvalue;
9376 }
9377
9378 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9379 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9380 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9381 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9382
9383 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9384 * alpha*x + beta*y + gamma*z = delta
9385 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9386 * the fourth corner point lies below this hyperplane.
9387 * 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.,
9388 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9389 * or, equivalently,
9390 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9391 */
9392 for( leaveout = 1; leaveout <= 4; ++leaveout )
9393 {
9394 switch( leaveout)
9395 {
9396 case 1 :
9397 /* get hyperplane through p2, p3, p4 */
9398 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9399 &alpha, &beta, &gamma_, &delta) );
9400 /* if not underestimating in p1, then go to next candidate */
9401 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9402 continue;
9403 break;
9404
9405 case 2 :
9406 /* get hyperplane through p1, p3, p4 */
9407 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9408 &alpha, &beta, &gamma_, &delta) );
9409 /* if not underestimating in p2, then go to next candidate */
9410 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9411 continue;
9412 break;
9413
9414 case 3 :
9415 /* get hyperplane through p1, p2, p4 */
9416 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9417 &alpha, &beta, &gamma_, &delta) );
9418 /* if not underestimating in p3, then go to next candidate */
9419 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9420 continue;
9421 break;
9422
9423 case 4 :
9424 /* get hyperplane through p1, p2, p3 */
9425 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9426 &alpha, &beta, &gamma_, &delta) );
9427 /* if not underestimating in p4, then stop */
9428 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9429 continue;
9430 break;
9431
9432 default: /* only for lint */
9434 beta = SCIP_INVALID;
9436 delta = SCIP_INVALID;
9437 break;
9438 }
9439
9440 /* check if bad luck: should not happen if numerics are fine */
9441 if( SCIPisZero(scip, gamma_) )
9442 continue;
9444
9445 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9447 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9448 continue;
9449
9450 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9451
9452 /* value of hyperplane candidate in xstar */
9453 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9454
9455 /* if reaching target and first or better than previous candidate, then update */
9456 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9457 {
9458 /* flip hyperplane */
9459 if( !overestimate )
9460 gamma_ = -gamma_;
9461
9462 facetcoefs[0] = -alpha/gamma_;
9463 facetcoefs[1] = -beta/gamma_;
9464 *facetconstant = delta/gamma_;
9465
9466 *success = TRUE;
9468 }
9469 }
9470
9471 return SCIP_OKAY;
9472}
9473
9474/*
9475 * Callback methods of constraint handler
9476 */
9477
9478/** copy method for constraint handler plugins (called when SCIP copies plugins) */
9479static
9481{ /*lint --e{715}*/
9484 int i;
9485
9486 assert(scip != NULL);
9487 assert(conshdlr != NULL);
9488 assert(valid != NULL);
9490
9491 /* create basic data of constraint handler and include it to scip */
9493
9496 assert(targetconshdlr != conshdlr);
9497
9500
9501 /* copy nonlinear handlers */
9502 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9503 {
9505 }
9506
9507 *valid = TRUE;
9508
9509 return SCIP_OKAY;
9510}
9511
9512/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9513static
9515{ /*lint --e{715}*/
9516 SCIP_CONSHDLRDATA* conshdlrdata;
9517 int i;
9518
9519 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9520 assert(conshdlrdata != NULL);
9521
9522 /* free nonlinear handlers */
9523 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9524 {
9525 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9526 assert(conshdlrdata->nlhdlrs[i] == NULL);
9527 }
9528 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9529 conshdlrdata->nlhdlrssize = 0;
9530
9531 /* free upgrade functions */
9532 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9533 {
9534 assert(conshdlrdata->consupgrades[i] != NULL);
9535 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9536 }
9537 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9538
9539 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9540
9541 SCIPqueueFree(&conshdlrdata->reversepropqueue);
9542
9543 if( conshdlrdata->vp_randnumgen != NULL )
9544 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9545
9546 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9547 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9548 {
9549 if( conshdlrdata->vp_lp[i] != NULL )
9550 {
9551 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9552 }
9553 }
9554
9555 assert(conshdlrdata->branchrandnumgen == NULL);
9556
9557 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9558 SCIPhashmapFree(&conshdlrdata->var2expr);
9559
9560 SCIPfreeBlockMemory(scip, &conshdlrdata);
9561 SCIPconshdlrSetData(conshdlr, NULL);
9562
9563 return SCIP_OKAY;
9564}
9565
9566
9567/** initialization method of constraint handler (called after problem was transformed) */
9568static
9570{ /*lint --e{715}*/
9571 SCIP_CONSHDLRDATA* conshdlrdata;
9572 int i;
9573
9574 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9575 assert(conshdlrdata != NULL);
9576
9577 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9578 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9579 /* set to 1 so it is larger than initial value of lastenforound in exprs */
9580 conshdlrdata->enforound = 1;
9581 /* reset numbering for auxiliary variables */
9582 conshdlrdata->auxvarid = 0;
9583
9584 for( i = 0; i < nconss; ++i )
9585 {
9586 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9587 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9588 }
9589
9590 /* sort nonlinear handlers by detection priority, in decreasing order */
9591 if( conshdlrdata->nnlhdlrs > 1 )
9592 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9593
9594 /* get heuristics for later use */
9595 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9596 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9597
9598 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9599 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9600 {
9601 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9602 }
9603
9604 /* reset statistics in constraint handler */
9605 conshdlrdata->nweaksepa = 0;
9606 conshdlrdata->ntightenlp = 0;
9607 conshdlrdata->ndesperatebranch = 0;
9608 conshdlrdata->ndesperatecutoff = 0;
9609 conshdlrdata->ndesperatetightenlp = 0;
9610 conshdlrdata->nforcelp = 0;
9611 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9612 conshdlrdata->ncanonicalizecalls = 0;
9613
9614#ifdef ENFOLOGFILE
9616#endif
9617
9618 return SCIP_OKAY;
9619}
9620
9621
9622/** deinitialization method of constraint handler (called before transformed problem is freed) */
9623static
9625{ /*lint --e{715}*/
9626 SCIP_CONSHDLRDATA* conshdlrdata;
9627 SCIP_CONS** consssorted;
9628 int i;
9629
9630 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9631 assert(conshdlrdata != NULL);
9632
9633 if( nconss > 0 )
9634 {
9635 /* for better performance of dropVarEvents, we sort by index, descending */
9636 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9637 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9638
9639 for( i = 0; i < nconss; ++i )
9640 {
9641 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9642 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9643 }
9644
9645 SCIPfreeBufferArray(scip, &consssorted);
9646 }
9647
9648 conshdlrdata->subnlpheur = NULL;
9649 conshdlrdata->trysolheur = NULL;
9650
9651 if( conshdlrdata->vp_randnumgen != NULL )
9652 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9653
9654 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9655 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9656 {
9657 if( conshdlrdata->vp_lp[i] != NULL )
9658 {
9659 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9660 }
9661 }
9662
9663 if( conshdlrdata->branchrandnumgen != NULL )
9664 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9665
9666 /* deinitialize nonlinear handlers */
9667 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9668 {
9669 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9670 }
9671
9672 ENFOLOG(
9673 if( enfologfile != NULL )
9674 {
9676 enfologfile = NULL;
9677 })
9678
9679 return SCIP_OKAY;
9680}
9681
9682
9683/** presolving initialization method of constraint handler (called when presolving is about to begin) */
9684#ifdef SCIP_DISABLED_CODE
9685static
9687{ /*lint --e{715}*/
9688 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9689 SCIPABORT(); /*lint --e{527}*/
9690
9691 return SCIP_OKAY;
9692}
9693#else
9694#define consInitpreNonlinear NULL
9695#endif
9696
9697
9698/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9699static
9701{ /*lint --e{715}*/
9702 SCIP_Bool infeasible;
9703
9704 if( nconss == 0 )
9705 return SCIP_OKAY;
9706
9707 /* skip some extra work if already known to be infeasible */
9709 return SCIP_OKAY;
9710
9711 /* simplify constraints and replace common subexpressions */
9712 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9713
9714 /* currently SCIP does not offer to communicate this,
9715 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9716 * or if a constraint expression became constant
9717 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
9718 */
9719 /* assert(!infeasible); */
9720
9721 /* tell SCIP that we have something nonlinear */
9723
9724 return SCIP_OKAY;
9725}
9726
9727
9728/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9729static
9731{ /*lint --e{715}*/
9732 SCIP_CONSHDLRDATA* conshdlrdata;
9733 int i;
9734
9735 /* skip remaining initializations if we have solved already
9736 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9737 * assumes nonempty activities in expressions
9738 */
9739 switch( SCIPgetStatus(scip) )
9740 {
9745 return SCIP_OKAY;
9746 default: ;
9747 } /*lint !e788 */
9748
9749 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9750 assert(conshdlrdata != NULL);
9751
9752 /* reset one of the number of detections counter to count only current round */
9753 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9754 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9755
9756 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9757
9758 /* catch new solution event */
9759 if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9760 {
9761 SCIP_EVENTHDLR* eventhdlr;
9762
9763 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9764 assert(eventhdlr != NULL);
9765
9766 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9767 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9768 }
9769
9770 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9771 if( conshdlrdata->branchpscostweight > 0.0 )
9772 {
9773 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9774 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9775 {
9776 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9777 SCIPABORT();
9778 return SCIP_INVALIDDATA;
9779 }
9780 }
9781
9782 return SCIP_OKAY;
9783}
9784
9785
9786/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9787static
9789{ /*lint --e{715}*/
9790 SCIP_CONSHDLRDATA* conshdlrdata;
9791
9792 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9793
9794 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9795 assert(conshdlrdata != NULL);
9796
9797 /* free hash table for bilinear terms */
9798 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9799
9800 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9801 conshdlrdata->checkedvarlocks = FALSE;
9802
9803 /* drop catching new solution event, if catched before */
9804 if( conshdlrdata->newsoleventfilterpos >= 0 )
9805 {
9806 SCIP_EVENTHDLR* eventhdlr;
9807
9808 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9809 assert(eventhdlr != NULL);
9810
9811 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9812 conshdlrdata->newsoleventfilterpos = -1;
9813 }
9814
9815 return SCIP_OKAY;
9816}
9817
9818
9819/** frees specific constraint data */
9820static
9822{ /*lint --e{715}*/
9823 assert(consdata != NULL);
9824 assert(*consdata != NULL);
9825 assert((*consdata)->expr != NULL);
9826
9827 /* constraint locks should have been removed */
9828 assert((*consdata)->nlockspos == 0);
9829 assert((*consdata)->nlocksneg == 0);
9830
9831 /* free variable expressions */
9832 SCIP_CALL( freeVarExprs(scip, *consdata) );
9833
9834 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9835
9836 /* free nonlinear row representation */
9837 if( (*consdata)->nlrow != NULL )
9838 {
9839 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9840 }
9841
9842 SCIPfreeBlockMemory(scip, consdata);
9843
9844 return SCIP_OKAY;
9845}
9846
9847
9848/** transforms constraint data into data belonging to the transformed problem */
9849static
9851{ /*lint --e{715}*/
9854
9857
9858 /* get a copy of sourceexpr with transformed vars */
9859 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9860 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9861
9862 /* create transformed cons (only captures targetexpr, no need to copy again) */
9869
9870 /* release target expr */
9872
9873 return SCIP_OKAY;
9874}
9875
9876
9877/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9878static
9880{ /*lint --e{715}*/
9881 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9882 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9883 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9884 * for now, there is an assert in detectNlhdlrs to require initial if separated
9885 */
9886 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9887
9888 /* collect all bilinear terms for which an auxvar is present
9889 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9890 * addition (and removal?) of constraints during solve
9891 * this is typically the majority of constraints, but the method should be made more flexible
9892 */
9893 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9894
9895 return SCIP_OKAY;
9896}
9897
9898
9899/** separation method of constraint handler for LP solutions */
9900static
9902{ /*lint --e{715}*/
9903 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9904
9905 return SCIP_OKAY;
9906}
9907
9908
9909/** separation method of constraint handler for arbitrary primal solutions */
9910static
9912{ /*lint --e{715}*/
9913 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9914
9915 return SCIP_OKAY;
9916}
9917
9918
9919/** constraint enforcing method of constraint handler for LP solutions */
9920static
9922{ /*lint --e{715}*/
9923 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9924
9925 return SCIP_OKAY;
9926}
9927
9928
9929/** constraint enforcing method of constraint handler for relaxation solutions */
9930static
9932{ /*lint --e{715}*/
9933 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9934
9935 return SCIP_OKAY;
9936}
9937
9938
9939/** constraint enforcing method of constraint handler for pseudo solutions */
9940static
9942{ /*lint --e{715}*/
9944 SCIP_Longint soltag;
9945 int nchgbds;
9946 int nnotify;
9947 int c;
9948
9950
9952 for( c = 0; c < nconss; ++c )
9953 {
9955
9956 if( isConsViolated(scip, conss[c]) )
9958 }
9959
9960 if( *result == SCIP_FEASIBLE )
9961 return SCIP_OKAY;
9962
9963 /* try to propagate
9964 * TODO obey propinenfo parameter, but we need something to recognize cutoff
9965 */
9966 nchgbds = 0;
9967 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9968
9970 {
9971 *result = propresult;
9972 return SCIP_OKAY;
9973 }
9974
9975 /* register all unfixed variables in all violated constraints as branching candidates */
9976 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9977 if( nnotify > 0 )
9978 {
9979 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9980
9981 return SCIP_OKAY;
9982 }
9983
9984 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9986 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9987
9988 return SCIP_OKAY;
9989}
9990
9991
9992/** feasibility check method of constraint handler for integral solutions */
9993static
9995{ /*lint --e{715}*/
9996 SCIP_CONSHDLRDATA* conshdlrdata;
9997 SCIP_CONSDATA* consdata;
9998 SCIP_Real maxviol;
9999 SCIP_Bool maypropfeasible;
10000 SCIP_Longint soltag;
10001 int c;
10002
10003 assert(scip != NULL);
10004 assert(conshdlr != NULL);
10005 assert(conss != NULL || nconss == 0);
10006 assert(result != NULL);
10007
10008 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10009 assert(conshdlrdata != NULL);
10010
10013 maxviol = 0.0;
10014 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
10016
10019
10020 /* check nonlinear constraints for feasibility */
10021 for( c = 0; c < nconss; ++c )
10022 {
10023 assert(conss != NULL && conss[c] != NULL);
10024 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10025
10026 if( isConsViolated(scip, conss[c]) )
10027 {
10029 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10030
10031 consdata = SCIPconsGetData(conss[c]);
10032 assert(consdata != NULL);
10033
10034 /* print reason for infeasibility */
10035 if( printreason )
10036 {
10037 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10038 SCIPinfoMessage(scip, NULL, ";\n");
10039
10040 if( consdata->lhsviol > SCIPfeastol(scip) )
10041 {
10042 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10043 }
10044 if( consdata->rhsviol > SCIPfeastol(scip) )
10045 {
10046 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10047 }
10048 }
10049 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10050 {
10051 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10052 return SCIP_OKAY;
10053 }
10054
10055 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10058
10059 if( maypropfeasible )
10060 {
10061 if( consdata->lhsviol > SCIPfeastol(scip) )
10062 {
10063 /* check if there is a variable which may help to get the left hand side satisfied
10064 * if there is no such variable, then we cannot get feasible
10065 */
10066 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10067 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10069 }
10070 else
10071 {
10072 assert(consdata->rhsviol > SCIPfeastol(scip));
10073 /* check if there is a variable which may help to get the right hand side satisfied
10074 * if there is no such variable, then we cannot get feasible
10075 */
10076 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10077 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10079 }
10080 }
10081 }
10082 }
10083
10085 {
10086 SCIP_Bool success;
10087
10088 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10089
10090 /* do not pass solution to NLP heuristic if we made it feasible this way */
10091 if( success )
10092 return SCIP_OKAY;
10093 }
10094
10095 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10096 {
10097 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10098 }
10099
10100 return SCIP_OKAY;
10101}
10102
10103
10104/** domain propagation method of constraint handler */
10105static
10107{ /*lint --e{715}*/
10108 int nchgbds = 0;
10109
10110 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10111 assert(nchgbds >= 0);
10112
10113 /* TODO would it make sense to check for redundant constraints? */
10114
10115 return SCIP_OKAY;
10116}
10117
10118
10119/** presolving method of constraint handler */
10120static
10122{ /*lint --e{715}*/
10123 SCIP_CONSHDLRDATA* conshdlrdata;
10124 SCIP_Bool infeasible;
10125 int c;
10126
10128
10129 if( nconss == 0 )
10130 {
10132 return SCIP_OKAY;
10133 }
10134
10135 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10136 assert(conshdlrdata != NULL);
10137
10138 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10139 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10140 if( infeasible )
10141 {
10143 return SCIP_OKAY;
10144 }
10145
10146 /* merge constraints with the same root expression */
10147 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10148 {
10149 SCIP_Bool success;
10150
10151 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10152 if( success )
10154 }
10155
10156 /* propagate constraints */
10157 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10158 if( *result == SCIP_CUTOFF )
10159 return SCIP_OKAY;
10160
10161 /* propagate function domains (TODO integrate with simplify?) */
10162 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10163 {
10165 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10166 if( localresult == SCIP_CUTOFF )
10167 {
10169 return SCIP_OKAY;
10170 }
10173 }
10174
10175 /* check for redundant constraints, remove constraints that are a value expression */
10176 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10177 if( infeasible )
10178 {
10180 return SCIP_OKAY;
10181 }
10182
10183 /* try to upgrade constraints */
10184 for( c = 0; c < nconss; ++c )
10185 {
10186 SCIP_Bool upgraded;
10187
10188 /* skip inactive and deleted constraints */
10189 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10190 continue;
10191
10192 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10193 }
10194
10195 /* try to change continuous variables that appear linearly to be implicit integer */
10196 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10197 {
10198 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10199
10200 if( infeasible )
10201 {
10202 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10204 return SCIP_OKAY;
10205 }
10206 }
10207
10208 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10210 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10211 {
10212 /* run this presolving technique only once because we don't want to generate identical bound disjunction
10213 * constraints multiple times
10214 */
10215 conshdlrdata->checkedvarlocks = TRUE;
10216
10217 for( c = 0; c < nconss; ++c )
10218 {
10219 int tmpnchgvartypes = 0;
10220 int tmpnaddconss = 0;
10221
10222 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10223 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10224 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10225
10226 if( infeasible )
10227 {
10228 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10230 return SCIP_OKAY;
10231 }
10232
10233 (*nchgvartypes) += tmpnchgvartypes;
10234 (*naddconss) += tmpnaddconss;
10235 }
10236 }
10237
10238 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10240 else
10242
10243 return SCIP_OKAY;
10244}
10245
10246
10247/** propagation conflict resolving method of constraint handler */
10248#ifdef SCIP_DISABLED_CODE
10249static
10251{ /*lint --e{715}*/
10252 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10253 SCIPABORT(); /*lint --e{527}*/
10254
10255 return SCIP_OKAY;
10256}
10257#else
10258#define consRespropNonlinear NULL
10259#endif
10260
10261
10262/** variable rounding lock method of constraint handler */
10263static
10265{ /*lint --e{715}*/
10266 SCIP_CONSDATA* consdata;
10267 SCIP_EXPR_OWNERDATA* ownerdata;
10268 SCIP_Bool reinitsolve = FALSE;
10269
10270 assert(conshdlr != NULL);
10271 assert(cons != NULL);
10272
10273 consdata = SCIPconsGetData(cons);
10274 assert(consdata != NULL);
10275 assert(consdata->expr != NULL);
10276
10277 ownerdata = SCIPexprGetOwnerData(consdata->expr);
10278
10279 /* check whether we need to initSolve again because
10280 * - we have enfo initialized (nenfos >= 0)
10281 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10282 */
10283 if( ownerdata->nenfos >= 0 )
10284 {
10285 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10286 reinitsolve = TRUE;
10287 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10288 reinitsolve = TRUE;
10289 }
10290
10291 if( reinitsolve )
10292 {
10293 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10294 }
10295
10296 /* add locks */
10297 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10298
10299 if( reinitsolve )
10300 {
10301 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10302 }
10303
10304 return SCIP_OKAY;
10305}
10306
10307
10308/** constraint activation notification method of constraint handler */
10309static
10311{ /*lint --e{715}*/
10312 SCIP_CONSDATA* consdata;
10313 SCIP_Bool infeasible = FALSE;
10314
10315 consdata = SCIPconsGetData(cons);
10316 assert(consdata != NULL);
10317
10318 /* simplify root expression if the constraint has been added after presolving */
10320 {
10321 SCIP_Bool replacedroot;
10322
10323 if( !consdata->issimplified )
10324 {
10326 SCIP_Bool changed;
10327
10328 /* simplify constraint */
10329 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10330 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10332 consdata->expr = simplified;
10333 consdata->issimplified = TRUE;
10334 }
10335
10336 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10338 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10339
10340 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10341 {
10342 SCIP_CONSHDLRDATA* conshdlrdata;
10344 SCIP_EXPR* expr;
10345
10346 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10347 assert(conshdlrdata != NULL);
10348
10350 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10353 {
10354 SCIP_EXPR* child;
10356
10358 if( !SCIPisExprVar(scip, child) )
10359 continue;
10360
10361 /* check which expression is stored in the hashmap for the var of child */
10362 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10363 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10364 if( hashmapexpr != NULL && hashmapexpr != child )
10365 {
10367 }
10368 }
10370 }
10371 }
10372
10373 /* store variable expressions */
10375 {
10376 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10377 }
10378
10379 /* add manually locks to constraints that are not checked for feasibility */
10380 if( !SCIPconsIsChecked(cons) )
10381 {
10382 assert(consdata->nlockspos == 0);
10383 assert(consdata->nlocksneg == 0);
10384
10385 SCIP_CALL( addLocks(scip, cons, 1, 0) );
10386 }
10387
10388 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10389 {
10390 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10391 }
10392
10393 /* TODO deal with infeasibility */
10394 assert(!infeasible);
10395
10396 return SCIP_OKAY;
10397}
10398
10399
10400/** constraint deactivation notification method of constraint handler */
10401static
10403{ /*lint --e{715}*/
10404 SCIP_CONSHDLRDATA* conshdlrdata;
10405
10406 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10407 assert(conshdlrdata != NULL);
10408
10410 {
10411 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10412 }
10413
10415 {
10416 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10418 }
10419
10420 /* remove locks that have been added in consActiveExpr() */
10421 if( !SCIPconsIsChecked(cons) )
10422 {
10423 SCIP_CALL( addLocks(scip, cons, -1, 0) );
10424
10425 assert(SCIPconsGetData(cons)->nlockspos == 0);
10426 assert(SCIPconsGetData(cons)->nlocksneg == 0);
10427 }
10428
10429 return SCIP_OKAY;
10430}
10431
10432
10433/** constraint enabling notification method of constraint handler */
10434static
10436{ /*lint --e{715}*/
10437 SCIP_CONSHDLRDATA* conshdlrdata;
10438
10439 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10440 assert(conshdlrdata != NULL);
10441
10443 {
10444 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10445 }
10446
10447 return SCIP_OKAY;
10448}
10449
10450
10451/** constraint disabling notification method of constraint handler */
10452static
10454{ /*lint --e{715}*/
10455 SCIP_CONSHDLRDATA* conshdlrdata;
10456
10457 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10458 assert(conshdlrdata != NULL);
10459
10461 {
10462 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10463 }
10464
10465 return SCIP_OKAY;
10466}
10467
10468/** variable deletion of constraint handler */
10469#ifdef SCIP_DISABLED_CODE
10470static
10472{ /*lint --e{715}*/
10473 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10474 SCIPABORT(); /*lint --e{527}*/
10475
10476 return SCIP_OKAY;
10477}
10478#else
10479#define consDelvarsNonlinear NULL
10480#endif
10481
10482
10483/** constraint display method of constraint handler */
10484static
10486{ /*lint --e{715}*/
10487 SCIP_CONSDATA* consdata;
10488
10489 consdata = SCIPconsGetData(cons);
10490 assert(consdata != NULL);
10491 assert(consdata->expr != NULL);
10492
10493 /* print left hand side for ranged constraints */
10494 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10495 {
10496 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10497 }
10498
10499 /* print expression */
10500 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10501
10502 /* print right hand side */
10503 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10504 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10505 else if( !SCIPisInfinity(scip, consdata->rhs) )
10506 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10507 else if( !SCIPisInfinity(scip, -consdata->lhs) )
10508 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10509 else
10510 SCIPinfoMessage(scip, file, " [free]");
10511
10512 return SCIP_OKAY;
10513}
10514
10515
10516/** constraint copying method of constraint handler */
10517static
10519{ /*lint --e{715}*/
10523
10524 assert(cons != NULL);
10525
10528
10531
10532 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10533
10534 if( targetexpr == NULL )
10535 *valid = FALSE;
10536
10537 *cons = NULL;
10538 if( *valid )
10539 {
10540 /* create copy (only capture targetexpr, no need to copy again) */
10543 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10544 }
10545
10546 if( targetexpr != NULL )
10547 {
10548 /* release target expr */
10550 }
10551
10552 return SCIP_OKAY;
10553}
10554
10555
10556/** constraint parsing method of constraint handler */
10557static
10559{ /*lint --e{715}*/
10560 SCIP_Real lhs;
10561 SCIP_Real rhs;
10562 char* endptr;
10564
10565 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10566
10567 assert(scip != NULL);
10568 assert(success != NULL);
10569 assert(str != NULL);
10570 assert(name != NULL);
10571 assert(cons != NULL);
10572
10573 *success = FALSE;
10574
10575 /* return if string empty */
10576 if( !*str )
10577 return SCIP_OKAY;
10578
10579 endptr = (char*)str;
10580
10581 /* set left and right hand side to their default values */
10582 lhs = -SCIPinfinity(scip);
10583 rhs = SCIPinfinity(scip);
10584
10585 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10586
10587 /* check for left hand side */
10588 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10589 {
10590 /* there is a number coming, maybe it is a left-hand-side */
10591 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
10592 {
10593 SCIPerrorMessage("error parsing number from <%s>\n", str);
10594 return SCIP_READERROR;
10595 }
10596
10597 /* ignore whitespace */
10599
10600 if( endptr[0] != '<' || endptr[1] != '=' )
10601 {
10602 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10603 lhs = -SCIPinfinity(scip);
10604 }
10605 else
10606 {
10607 /* it was indeed a left-hand-side, so continue parsing after it */
10608 str = endptr + 2;
10609
10610 /* ignore whitespace */
10611 SCIP_CALL( SCIPskipSpace((char**)&str) );
10612 }
10613 }
10614
10615 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10616
10617 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10618 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10619
10620 /* check for left or right hand side */
10621 SCIP_CALL( SCIPskipSpace((char**)&str) );
10622
10623 /* check for free constraint */
10624 if( strncmp(str, "[free]", 6) == 0 )
10625 {
10626 if( !SCIPisInfinity(scip, -lhs) )
10627 {
10628 SCIPerrorMessage("cannot have left hand side and [free] status \n");
10630 return SCIP_OKAY;
10631 }
10632 *success = TRUE;
10633 }
10634 else
10635 {
10636 switch( *str )
10637 {
10638 case '<':
10639 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
10640 break;
10641 case '=':
10642 if( !SCIPisInfinity(scip, -lhs) )
10643 {
10644 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10646 return SCIP_OKAY;
10647 }
10648 else
10649 {
10650 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
10651 lhs = rhs;
10652 }
10653 break;
10654 case '>':
10655 if( !SCIPisInfinity(scip, -lhs) )
10656 {
10657 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10659 return SCIP_OKAY;
10660 }
10661 else
10662 {
10663 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
10664 break;
10665 }
10666 case '\0':
10667 *success = TRUE;
10668 break;
10669 default:
10670 SCIPerrorMessage("unexpected character %c\n", *str);
10672 return SCIP_OKAY;
10673 }
10674 }
10675
10676 /* create constraint */
10677 SCIP_CALL( createCons(scip, conshdlr, cons, name,
10678 consexprtree, lhs, rhs, FALSE,
10679 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10680 assert(*cons != NULL);
10681
10683
10684 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10685
10686 return SCIP_OKAY;
10687}
10688
10689
10690/** constraint method of constraint handler which returns the variables (if possible) */
10691static
10693{ /*lint --e{715}*/
10694 SCIP_CONSDATA* consdata;
10695 int i;
10696
10697 consdata = SCIPconsGetData(cons);
10698 assert(consdata != NULL);
10699
10700 /* store variable expressions if not done so far */
10701 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10702
10703 /* check whether array is too small in order to store all variables */
10704 if( varssize < consdata->nvarexprs )
10705 {
10706 *success = FALSE;
10707 return SCIP_OKAY;
10708 }
10709
10710 for( i = 0; i < consdata->nvarexprs; ++i )
10711 {
10712 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10713 assert(vars[i] != NULL);
10714 }
10715
10716 *success = TRUE;
10717
10718 return SCIP_OKAY;
10719}
10720
10721/** constraint method of constraint handler which returns the number of variables (if possible) */
10722static
10724{ /*lint --e{715}*/
10725 SCIP_CONSDATA* consdata;
10726
10727 consdata = SCIPconsGetData(cons);
10728 assert(consdata != NULL);
10729
10730 /* store variable expressions if not done so far */
10731 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10732
10733 *nvars = consdata->nvarexprs;
10734 *success = TRUE;
10735
10736 return SCIP_OKAY;
10737}
10738
10739/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10740#ifdef SCIP_DISABLED_CODE
10741static
10743{ /*lint --e{715}*/
10744 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10745 SCIPABORT(); /*lint --e{527}*/
10746
10747 return SCIP_OKAY;
10748}
10749#else
10750#define consGetDiveBdChgsNonlinear NULL
10751#endif
10752
10753/** output method of statistics table to output file stream 'file' */
10754static
10756{ /*lint --e{715}*/
10757 SCIP_CONSHDLR* conshdlr;
10758 SCIP_CONSHDLRDATA* conshdlrdata;
10759
10760 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10761 assert(conshdlr != NULL);
10762
10763 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10764 assert(conshdlrdata != NULL);
10765
10766 /* print statistics for constraint handler */
10767 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10768 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10769 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10770 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10771 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10772 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10773 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10774 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10775 SCIPinfoMessage(scip, file, "\n");
10776 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10777 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10778 SCIPinfoMessage(scip, file, "\n");
10779
10780 return SCIP_OKAY;
10781}
10782
10783/** output method of statistics table to output file stream 'file' */
10784static
10786{ /*lint --e{715}*/
10787 SCIP_CONSHDLR* conshdlr;
10788 SCIP_CONSHDLRDATA* conshdlrdata;
10789
10790 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10791 assert(conshdlr != NULL);
10792
10793 /* skip nlhdlr table if there never were active nonlinear constraints */
10794 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10795 return SCIP_OKAY;
10796
10797 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10798 assert(conshdlrdata != NULL);
10799
10800 /* print statistics for nonlinear handlers */
10801 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10802
10803 return SCIP_OKAY;
10804}
10805
10806/** execution method of display nlhdlrs dialog */
10807static
10809{ /*lint --e{715}*/
10810 SCIP_CONSHDLR* conshdlr;
10811 SCIP_CONSHDLRDATA* conshdlrdata;
10812 int i;
10813
10814 /* add dialog to history of dialogs that have been executed */
10816
10817 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10818 assert(conshdlr != NULL);
10819
10820 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10821 assert(conshdlrdata != NULL);
10822
10823 /* display list of nonlinear handler */
10824 SCIPdialogMessage(scip, NULL, "\n");
10825 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10826 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10827 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10828 {
10829 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10830 assert(nlhdlr != NULL);
10831
10832 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10833 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10836 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10837 SCIPdialogMessage(scip, NULL, "\n");
10838 }
10839 SCIPdialogMessage(scip, NULL, "\n");
10840
10841 /* next dialog will be root dialog again */
10842 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10843
10844 return SCIP_OKAY;
10845}
10846
10847/*
10848 * constraint handler specific interface methods
10849 */
10850
10851/** creates the handler for nonlinear constraints and includes it in SCIP */
10853 SCIP* scip /**< SCIP data structure */
10854 )
10855{
10856 SCIP_CONSHDLRDATA* conshdlrdata;
10858
10859 /* create nonlinear constraint handler data */
10860 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
10861 conshdlrdata->intevalvar = intEvalVarBoundTightening;
10862 conshdlrdata->curboundstag = 1;
10863 conshdlrdata->lastboundrelax = 1;
10864 conshdlrdata->curpropboundstag = 1;
10865 conshdlrdata->newsoleventfilterpos = -1;
10866 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10867 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10868 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10869
10870 /* include constraint handler */
10886
10887 /* add nonlinear constraint handler parameters */
10888 /* TODO organize into more subcategories */
10889 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10890 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10891 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10892
10893 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10894 "whether to check bounds of all auxiliary variable to seed reverse propagation",
10895 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10896
10897 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10898 "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",
10899 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10900
10901 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10902 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10903 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10904
10905 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10906 "by how much to relax constraint sides during bound tightening",
10907 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10908
10909 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10910 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10911 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10912
10913 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10914 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10915 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10916
10917 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10918 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10919 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10920
10921 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10922 "maximal number of auxiliary expressions per bilinear term",
10923 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10924
10925 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10926 "whether to reformulate products of binary variables during presolving",
10927 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10928
10929 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10930 "whether to use the AND constraint handler for reformulating binary products",
10931 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10932
10933 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10934 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10935 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10936
10937 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10938 "whether to forbid multiaggregation of nonlinear variables",
10939 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10940
10941 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10942 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10943 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10944
10945 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10946 "whether to (re)run propagation in enforcement",
10947 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10948
10949 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10950 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10951 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10952
10953 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10954 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10955 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10956
10957 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10958 "consider efficacy requirement when deciding whether a cut is \"strong\"",
10959 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10960
10961 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10962 "whether to force \"strong\" cuts in enforcement",
10963 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10964
10965 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10966 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10967 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10968
10969 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10970 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10971 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10972
10973 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10974 "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",
10975 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10976
10977 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10978 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10979 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10980
10981 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10982 "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)",
10983 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10984
10985 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10986 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10987 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10988
10989 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10990 "whether to use external branching candidates and branching rules for branching",
10991 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10992
10993 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10994 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10995 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10996
10997 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10998 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10999 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
11000
11001 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
11002 "weight by how much to consider the violation assigned to a variable for its branching score",
11003 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11004
11005 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
11006 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
11007 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11008
11009 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
11010 "weight by how much to consider the pseudo cost of a variable for its branching score",
11011 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11012
11013 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
11014 "weight by how much to consider the domain width in branching score",
11015 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11016
11017 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
11018 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11019 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11020
11021 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11022 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11023 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11024
11025 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11026 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11027 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11028
11029 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11030 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11031 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11032
11033 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11034 "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)",
11035 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11036
11037 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11038 "whether to assume that any constraint is convex",
11039 &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11040
11041 /* include handler for bound change events */
11042 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11043 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11044 assert(conshdlrdata->eventhdlr != NULL);
11045
11046 /* include tables for statistics */
11051
11056
11057 /* create, include, and release display nlhdlrs dialog */
11059 {
11061
11064
11070 }
11071
11072 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11074
11075 return SCIP_OKAY;
11076}
11077
11078/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11080 SCIP* scip, /**< SCIP data structure */
11081 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11082 int priority, /**< priority of upgrading method */
11083 SCIP_Bool active, /**< should the upgrading method by active by default? */
11084 const char* conshdlrname /**< name of the constraint handler */
11085 )
11086{
11087 SCIP_CONSHDLR* conshdlr;
11088 SCIP_CONSHDLRDATA* conshdlrdata;
11092 int i;
11093
11096
11097 /* find the nonlinear constraint handler */
11098 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11099 if( conshdlr == NULL )
11100 {
11101 SCIPerrorMessage("nonlinear constraint handler not found\n");
11102 return SCIP_PLUGINNOTFOUND;
11103 }
11104
11105 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11106 assert(conshdlrdata != NULL);
11107
11108 /* check whether upgrade method exists already */
11109 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11110 {
11111 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11112 {
11113#ifdef SCIP_DEBUG
11114 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11115#endif
11116 return SCIP_OKAY;
11117 }
11118 }
11119
11120 /* create a nonlinear constraint upgrade data object */
11122 consupgrade->consupgd = nlconsupgd;
11123 consupgrade->priority = priority;
11124 consupgrade->active = active;
11125
11126 /* insert nonlinear constraint upgrade method into constraint handler data */
11127 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11128 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11129
11130 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11131 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11132 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11133 conshdlrdata->consupgrades[i] = consupgrade;
11134 conshdlrdata->nconsupgrades++;
11135
11136 /* adds parameter to turn on and off the upgrading step */
11137 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11138 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11141 &consupgrade->active, FALSE, active, NULL, NULL) );
11142
11143 return SCIP_OKAY;
11144}
11145
11146/** creates and captures a nonlinear constraint
11147 *
11148 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11149 */
11151 SCIP* scip, /**< SCIP data structure */
11152 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11153 const char* name, /**< name of constraint */
11154 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11155 SCIP_Real lhs, /**< left hand side of constraint */
11156 SCIP_Real rhs, /**< right hand side of constraint */
11157 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11158 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11159 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11160 * Usually set to TRUE. */
11161 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11162 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11163 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11164 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11165 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11166 * Usually set to TRUE. */
11167 SCIP_Bool local, /**< is constraint only valid locally?
11168 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11169 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11170 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11171 * adds coefficients to this constraint. */
11172 SCIP_Bool dynamic, /**< is constraint subject to aging?
11173 * Usually set to FALSE. Set to TRUE for own cuts which
11174 * are separated as constraints. */
11175 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11176 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11177 )
11178{
11179 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11180 SCIP_CONSHDLR* conshdlr;
11181
11182 /* find the nonlinear constraint handler */
11183 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11184 if( conshdlr == NULL )
11185 {
11186 SCIPerrorMessage("nonlinear constraint handler not found\n");
11187 return SCIP_PLUGINNOTFOUND;
11188 }
11189
11190 /* create constraint */
11191 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11192 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11193
11194 return SCIP_OKAY;
11195}
11196
11197/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11198 *
11199 * All flags can be set via SCIPconsSetFLAGNAME-methods.
11200 *
11201 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11202 *
11203 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11204 */
11206 SCIP* scip, /**< SCIP data structure */
11207 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11208 const char* name, /**< name of constraint */
11209 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11210 SCIP_Real lhs, /**< left hand side of constraint */
11211 SCIP_Real rhs /**< right hand side of constraint */
11212 )
11213{
11214 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11216
11217 return SCIP_OKAY;
11218}
11219
11220/** creates and captures a quadratic nonlinear constraint
11221 *
11222 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11223 */
11225 SCIP* scip, /**< SCIP data structure */
11226 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11227 const char* name, /**< name of constraint */
11228 int nlinvars, /**< number of linear terms */
11229 SCIP_VAR** linvars, /**< array with variables in linear part */
11230 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11231 int nquadterms, /**< number of quadratic terms */
11232 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11233 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11234 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11235 SCIP_Real lhs, /**< left hand side of quadratic equation */
11236 SCIP_Real rhs, /**< right hand side of quadratic equation */
11237 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11238 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11239 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11240 * Usually set to TRUE. */
11241 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11242 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11243 SCIP_Bool check, /**< should the constraint be checked for feasibility?
11244 * TRUE for model constraints, FALSE for additional, redundant constraints. */
11245 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11246 * Usually set to TRUE. */
11247 SCIP_Bool local, /**< is constraint only valid locally?
11248 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11249 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11250 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11251 * adds coefficients to this constraint. */
11252 SCIP_Bool dynamic, /**< is constraint subject to aging?
11253 * Usually set to FALSE. Set to TRUE for own cuts which
11254 * are separated as constraints. */
11255 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11256 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11257 )
11258{
11259 SCIP_CONSHDLR* conshdlr;
11260 SCIP_EXPR* expr;
11261
11262 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11263 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11264
11265 /* get nonlinear constraint handler */
11266 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11267 if( conshdlr == NULL )
11268 {
11269 SCIPerrorMessage("nonlinear constraint handler not found\n");
11270 return SCIP_PLUGINNOTFOUND;
11271 }
11272
11273 /* create quadratic expression */
11274 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11275 assert(expr != NULL);
11276
11277 /* create nonlinear constraint */
11278 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11279 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11280
11281 /* release quadratic expression (captured by constraint now) */
11282 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11283
11284 return SCIP_OKAY;
11285}
11286
11287/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11288 *
11289 * All flags can be set via SCIPconsSetFLAGNAME-methods.
11290 *
11291 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11292 *
11293 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11294 */
11296 SCIP* scip, /**< SCIP data structure */
11297 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11298 const char* name, /**< name of constraint */
11299 int nlinvars, /**< number of linear terms */
11300 SCIP_VAR** linvars, /**< array with variables in linear part */
11301 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11302 int nquadterms, /**< number of quadratic terms */
11303 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11304 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11305 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11306 SCIP_Real lhs, /**< left hand side of quadratic equation */
11307 SCIP_Real rhs /**< right hand side of quadratic equation */
11308 )
11309{
11310 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11312
11313 return SCIP_OKAY;
11314}
11315
11316/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11317 *
11318 * \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$
11319 *
11320 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11321 */
11323 SCIP* scip, /**< SCIP data structure */
11324 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11325 const char* name, /**< name of constraint */
11326 int nvars, /**< number of variables on left hand side of constraint (n) */
11327 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11328 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11329 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11330 SCIP_Real constant, /**< constant on left hand side (gamma) */
11331 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11332 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11333 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11334 )
11335{
11336 SCIP_EXPR* expr;
11338 SCIP_EXPR* terms[2];
11339 SCIP_Real termcoefs[2];
11340 int i;
11341
11342 assert(vars != NULL || nvars == 0);
11343
11344 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11345 for( i = 0; i < nvars; ++i )
11346 {
11349
11350 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11351 if( offsets != NULL && offsets[i] != 0.0 )
11352 {
11353 SCIP_EXPR* sum;
11354 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11355 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11356 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11357 }
11358 else
11359 {
11360 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11361 }
11362
11363 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11366 }
11367
11368 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11370 termcoefs[0] = 1.0;
11371
11372 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11373 termcoefs[1] = -rhscoeff;
11374
11375 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11376
11379
11381
11382 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11383
11384 return SCIP_OKAY;
11385}
11386
11387/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11388 *
11389 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11390 *
11391 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11392 */
11394 SCIP* scip, /**< SCIP data structure */
11395 SCIP_CONS** cons, /**< pointer to hold the created constraint */
11396 const char* name, /**< name of constraint */
11397 SCIP_VAR* x, /**< nonlinear variable x in constraint */
11398 SCIP_VAR* z, /**< linear variable z in constraint */
11399 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11400 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11401 SCIP_Real zcoef, /**< coefficient of z in constraint */
11402 SCIP_Real lhs, /**< left hand side of constraint */
11403 SCIP_Real rhs /**< right hand side of constraint */
11404 )
11405{
11407 SCIP_EXPR* terms[2];
11408 SCIP_Real coefs[2];
11410
11411 assert(x != NULL);
11412 assert(z != NULL);
11413
11415 if( xoffset != 0.0 )
11416 {
11417 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11418 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11419
11421 }
11422 else
11423 {
11424 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11425 }
11426 coefs[0] = 1.0;
11427
11429 coefs[1] = zcoef;
11430
11431 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11432
11433 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11434
11439
11440 return SCIP_OKAY;
11441}
11442
11443/** gets tag indicating current local variable bounds */
11445 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11446 )
11447{
11448 SCIP_CONSHDLRDATA* conshdlrdata;
11449
11450 assert(conshdlr != NULL);
11451 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11452
11453 return conshdlrdata->curboundstag;
11454}
11455
11456/** gets the `curboundstag` from the last time where variable bounds were relaxed */
11458 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11459 )
11460{
11461 SCIP_CONSHDLRDATA* conshdlrdata;
11462
11463 assert(conshdlr != NULL);
11464 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11465
11466 return conshdlrdata->lastboundrelax;
11467}
11468
11469/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11470 *
11471 * @attention This method is not intended for normal use.
11472 * These tags are maintained by the event handler for variable bound change events.
11473 * This method is used by some unittests.
11474 */
11476 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11477 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11478 )
11479{
11480 SCIP_CONSHDLRDATA* conshdlrdata;
11481
11482 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11483 assert(conshdlrdata != NULL);
11484
11485 ++conshdlrdata->curboundstag;
11486 assert(conshdlrdata->curboundstag > 0);
11487
11488 if( boundrelax )
11489 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11490}
11491
11492/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11494 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11495 )
11496{
11497 assert(conshdlr != NULL);
11498
11499 return SCIPconshdlrGetData(conshdlr)->var2expr;
11500}
11501
11502/** processes a rowprep for cut addition and maybe report branchscores */
11504 SCIP* scip, /**< SCIP data structure */
11505 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11506 SCIP_CONS* cons, /**< nonlinear constraint */
11507 SCIP_EXPR* expr, /**< expression */
11508 SCIP_ROWPREP* rowprep, /**< cut to be added */
11509 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11510 SCIP_VAR* auxvar, /**< auxiliary variable */
11511 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11512 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11513 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11514 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11515 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11516 SCIP_RESULT* result /**< pointer to store the result */
11517 )
11518{
11519 SCIP_Real cutviol;
11520 SCIP_CONSHDLRDATA* conshdlrdata;
11521 SCIP_Real auxvarvalue = SCIP_INVALID;
11522 SCIP_Bool sepasuccess;
11523 SCIP_Real estimateval = SCIP_INVALID;
11524 SCIP_Real mincutviolation;
11525
11526 assert(nlhdlr != NULL);
11527 assert(cons != NULL);
11528 assert(expr != NULL);
11529 assert(rowprep != NULL);
11530 assert(auxvar != NULL);
11531 assert(result != NULL);
11532
11533 /* decide on minimal violation of cut */
11534 if( sol == NULL )
11535 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11536 else
11537 mincutviolation = SCIPfeastol(scip);
11538
11539 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11540 assert(conshdlrdata != NULL);
11541
11542 sepasuccess = TRUE;
11543
11545 if( cutviol > 0.0 )
11546 {
11547 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11548
11549 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11550 if( !allowweakcuts && auxvalue != SCIP_INVALID )
11551 {
11552 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11553 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11554 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11555 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11556 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11557 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11558 *
11559 * if we are overestimating, we have z >= c'x-b >= f(x)
11560 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11561 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11562 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11563 *
11564 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11565 */
11566 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11567 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11568 {
11569 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11570 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11572 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11574 }
11575 }
11576
11577 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11578 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11579 }
11580 else
11581 {
11583 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11584 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11585 }
11586
11587 /* clean up estimator */
11588 if( sepasuccess )
11589 {
11590 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11591 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11592 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11594
11595 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11596 * instead, may even scale them down, that is, scale so that max coef is close to 1
11597 */
11598 if( !allowweakcuts )
11599 {
11600 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11601
11602 if( !sepasuccess )
11603 {
11604 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11605 }
11606 else
11607 {
11609 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11610 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11611 if( sepasuccess )
11612 sepasuccess = cutviol > mincutviolation;
11613 }
11614
11615 if( sepasuccess && auxvalue != SCIP_INVALID )
11616 {
11617 /* check whether cut is weak now
11618 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11619 * reconstructing estimateval from cutviol (TODO improve or remove?)
11620 */
11621 SCIP_Real auxvarcoef = 0.0;
11622 int i;
11623
11624 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11625 * it should be...
11626 */
11627 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11628 {
11629 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11630 {
11632 break;
11633 }
11634 }
11635
11636 if( auxvarcoef == 0.0 ||
11637 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11638 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11639 {
11640 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11641 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11643 }
11644 }
11645 }
11646 else
11647 {
11648 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11649
11650 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11651 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11652 */
11653 if( !branchscoresuccess )
11655
11656 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11657
11658 if( !sepasuccess )
11659 {
11660 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11662 }
11663
11664 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11665 * changed
11666 */
11668 {
11669 SCIP_Real violscore;
11670
11671#ifdef BRSCORE_ABSVIOL
11672 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11673#else
11675#endif
11677
11678 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11679 * - were fixed,
11680 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11681 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11682 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11683 * so I'm disabling the assert for now
11684 */
11685 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11686 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11687 }
11688 }
11689 }
11690
11691 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11692 if( sepasuccess )
11693 {
11694 SCIP_ROW* row;
11695
11696 if( conshdlrdata->branchdualweight > 0.0 )
11697 {
11698 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11699 * skip if gap is zero
11700 */
11701 if( auxvalue == SCIP_INVALID )
11702 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11703 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11704 {
11705 char gap[40];
11706 (void) SCIPsnprintf(gap, 40, "_estimategap=%g", REALABS(auxvalue - estimateval));
11708 }
11709 }
11710
11712
11713 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11714 {
11715 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11717 }
11718 else if( !SCIPisCutApplicable(scip, row) )
11719 {
11720 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11721 }
11722 else
11723 {
11724 SCIP_Bool infeasible;
11725
11726 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11728
11729 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11730 * if we haven't found strong cuts before)
11731 */
11732 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11733
11734 /* mark row as not removable from LP for current node (this can prevent some cycling) */
11735 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11737
11738 if( infeasible )
11739 {
11742 }
11743 else
11744 {
11747 }
11748 }
11749
11750 SCIP_CALL( SCIPreleaseRow(scip, &row) );
11751 }
11752 else if( branchscoresuccess )
11753 {
11754 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11755 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11756
11757 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11758 * expressions eligible for branching candidate, see enforceConstraints() and branching()
11759 */
11761 }
11762 else
11763 {
11764 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11765 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11766 " (!)" : ""); )
11767 }
11768
11769 return SCIP_OKAY;
11770}
11771
11772/** returns whether all nonlinear constraints are assumed to be convex */
11774 SCIP_CONSHDLR* conshdlr
11775 )
11776{
11777 SCIP_CONSHDLRDATA* conshdlrdata;
11778
11779 assert(conshdlr != NULL);
11780
11781 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11782 assert(conshdlrdata != NULL);
11783
11784 return conshdlrdata->assumeconvex;
11785}
11786
11787/** collects all bilinear terms for a given set of constraints
11788 *
11789 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11790 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11791 */
11793 SCIP* scip, /**< SCIP data structure */
11794 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11795 SCIP_CONS** conss, /**< nonlinear constraints */
11796 int nconss /**< total number of nonlinear constraints */
11797 )
11798{
11799 assert(conshdlr != NULL);
11800 assert(conss != NULL || nconss == 0);
11801
11802 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11803
11804 return SCIP_OKAY;
11805}
11806
11807/** returns the total number of bilinear terms that are contained in all nonlinear constraints
11808 *
11809 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11810 */
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->nbilinterms;
11823}
11824
11825/** returns all bilinear terms that are contained in all nonlinear constraints
11826 *
11827 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11828 * @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.
11829 */
11831 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11832 )
11833{
11834 SCIP_CONSHDLRDATA* conshdlrdata;
11835
11836 assert(conshdlr != NULL);
11837
11838 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11839 assert(conshdlrdata != NULL);
11840
11841 return conshdlrdata->bilinterms;
11842}
11843
11844/** returns the index of the bilinear term representing the product of the two given variables
11845 *
11846 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11847 * @return The method returns -1 if the variables do not appear bilinearly.
11848 */
11850 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11851 SCIP_VAR* x, /**< first variable */
11852 SCIP_VAR* y /**< second variable */
11853 )
11854{
11855 SCIP_CONSHDLRDATA* conshdlrdata;
11857 int idx;
11858
11859 assert(conshdlr != NULL);
11860 assert(x != NULL);
11861 assert(y != NULL);
11862
11863 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11864 assert(conshdlrdata != NULL);
11865
11866 if( conshdlrdata->bilinhashtable == NULL )
11867 {
11868 return -1;
11869 }
11870
11871 /* ensure that x.index <= y.index */
11872 if( SCIPvarCompare(x, y) == 1 )
11873 {
11874 SCIPswapPointers((void**)&x, (void**)&y);
11875 }
11876 assert(SCIPvarCompare(x, y) < 1);
11877
11878 /* use a new entry to find the image in the bilinear hash table */
11879 entry.x = x;
11880 entry.y = y;
11881 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11882 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11883 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11884 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11885
11886 return idx;
11887}
11888
11889/** returns the bilinear term that represents the product of two given variables
11890 *
11891 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11892 * @return The method returns NULL if the variables do not appear bilinearly.
11893 */
11895 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11896 SCIP_VAR* x, /**< first variable */
11897 SCIP_VAR* y /**< second variable */
11898 )
11899{
11900 SCIP_CONSHDLRDATA* conshdlrdata;
11901 int idx;
11902
11903 assert(conshdlr != NULL);
11904 assert(x != NULL);
11905 assert(y != NULL);
11906
11907 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11908 assert(conshdlrdata != NULL);
11909
11910 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11911 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11912
11913 if( idx >= 0 )
11914 {
11915 return &conshdlrdata->bilinterms[idx];
11916 }
11917
11918 return NULL;
11919}
11920
11921/** evaluates an auxiliary expression for a bilinear term */
11923 SCIP* scip, /**< SCIP data structure */
11924 SCIP_VAR* x, /**< first variable of the bilinear term */
11925 SCIP_VAR* y, /**< second variable of the bilinear term */
11926 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11927 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11928 )
11929{
11930 assert(scip != NULL);
11931 assert(x != NULL);
11932 assert(y != NULL);
11933 assert(auxexpr != NULL);
11934 assert(auxexpr->auxvar != NULL);
11935
11936 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11937 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11938}
11939
11940/** stores the variables of a bilinear term in the data of the constraint handler */
11942 SCIP* scip, /**< SCIP data structure */
11943 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11944 SCIP_VAR* x, /**< first variable */
11945 SCIP_VAR* y, /**< second variable */
11946 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11947 int nlockspos, /**< number of positive expression locks */
11948 int nlocksneg /**< number of negative expression locks */
11949 )
11950{
11951 SCIP_CONSHDLRDATA* conshdlrdata;
11953 int idx;
11954
11955 assert(conshdlr != NULL);
11956
11957 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11958 assert(conshdlrdata != NULL);
11959
11960 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11961
11962 term = &conshdlrdata->bilinterms[idx];
11963 assert(term != NULL);
11964 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11965 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) */
11966
11967 /* store and capture auxiliary variable */
11968 if( auxvar != NULL )
11969 {
11970 term->aux.var = auxvar;
11971 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11972 }
11973
11974 return SCIP_OKAY;
11975}
11976
11977/** stores the variables of a bilinear term in the data of the constraint handler */
11979 SCIP* scip, /**< SCIP data structure */
11980 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11981 SCIP_VAR* x, /**< first variable */
11982 SCIP_VAR* y, /**< second variable */
11983 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11984 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11985 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11986 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11987 SCIP_Real cst, /**< constant of the auxiliary expression */
11988 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11989 )
11990{
11991 SCIP_CONSHDLRDATA* conshdlrdata;
11994 int idx;
11995 int nlockspos;
11996 int nlocksneg;
11997 SCIP_Bool added;
11998
11999 assert(conshdlr != NULL);
12000
12001 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12002 assert(conshdlrdata != NULL);
12003
12004 nlockspos = overestimate ? 1 : 0;
12005 nlocksneg = overestimate ? 0 : 1;
12006
12007 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
12008
12009 term = &conshdlrdata->bilinterms[idx];
12010 assert(term != NULL);
12011 assert(SCIPvarCompare(term->x, term->y) < 1);
12012
12013 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
12014 {
12016 /* this is the case where we are adding an implicitly defined relation for a product that has already
12017 * been explicitly defined; convert auxvar into an auxexpr */
12018
12019 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12020 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12021 return SCIP_OKAY;
12022
12024 auxvarexpr->cst = 0.0;
12025 auxvarexpr->coefs[0] = 1.0;
12026 auxvarexpr->coefs[1] = 0.0;
12027 auxvarexpr->coefs[2] = 0.0;
12028 auxvarexpr->auxvar = term->aux.var;
12029 auxvarexpr->underestimate = term->nlocksneg > 0;
12030 auxvarexpr->overestimate = term->nlockspos > 0;
12031
12032 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12033 term->aux.exprs = NULL;
12034
12035 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12036
12037 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12038 assert(added);
12039 }
12040
12041 /* create and add auxexpr */
12043 auxexpr->underestimate = !overestimate;
12044 auxexpr->overestimate = overestimate;
12045 auxexpr->auxvar = auxvar;
12046 auxexpr->coefs[0] = coefaux;
12047 if( term->x == x )
12048 {
12049 assert(term->y == y);
12050 auxexpr->coefs[1] = coefx;
12051 auxexpr->coefs[2] = coefy;
12052 }
12053 else
12054 {
12055 assert(term->x == y);
12056 assert(term->y == x);
12057 auxexpr->coefs[1] = coefy;
12058 auxexpr->coefs[2] = coefx;
12059 }
12060 auxexpr->cst = cst;
12061 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12062
12063 if( !added )
12064 {
12066 }
12067 else if( auxvar != NULL )
12068 { /* capture auxiliary variable */
12069 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12070 }
12071
12072 return SCIP_OKAY;
12073}
12074
12075/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12077 SCIP* scip, /**< SCIP data structure */
12078 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12079 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12080 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12081 void* fundata, /**< data for function evaluation (can be NULL) */
12082 SCIP_Real* xstar, /**< point to be separated */
12083 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12084 int nallvars, /**< half of the length of box */
12085 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12086 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12087 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12088 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12089 )
12090{
12091 SCIP_Real* corner;
12092 SCIP_Real* funvals;
12093 int* nonfixedpos;
12094 SCIP_Real maxfaceterror;
12095 int nvars; /* number of nonfixed variables */
12096 unsigned int ncorners;
12097 unsigned int i;
12098 int j;
12099
12100 assert(scip != NULL);
12101 assert(conshdlr != NULL);
12102 assert(function != NULL);
12103 assert(xstar != NULL);
12104 assert(box != NULL);
12105 assert(success != NULL);
12108
12109 *success = FALSE;
12110
12111 /* identify fixed variables */
12113 nvars = 0;
12114 for( j = 0; j < nallvars; ++j )
12115 {
12116 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12117 continue;
12118 nonfixedpos[nvars] = j;
12119 nvars++;
12120 }
12121
12122 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12123 * if too many variables are not fixed, then we do nothing currently
12124 */
12125 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12126 {
12127 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12129 return SCIP_OKAY;
12130 }
12131
12132 /* compute f(v^i) for each corner v^i of [l,u] */
12135 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12136 for( j = 0; j < nallvars; ++j )
12137 {
12138 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12139 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12140 }
12141 for( i = 0; i < ncorners; ++i )
12142 {
12143 SCIPdebugMsg(scip, "corner %u: ", i);
12144 for( j = 0; j < nvars; ++j )
12145 {
12146 int varpos = nonfixedpos[j];
12147 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12148 * we check this by shifting i for j positions to the right and checking whether the last bit is set
12149 */
12150 if( (i >> j) & 0x1 )
12151 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12152 else
12153 corner[varpos] = box[2 * varpos ]; /* lb of var */
12154 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12156 }
12157
12158 funvals[i] = function(corner, nallvars, fundata);
12159
12160 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12161
12163 {
12164 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12165 goto CLEANUP;
12166 }
12167 }
12168
12169 /* clear coefs array; below we only fill in coefs for nonfixed variables */
12171
12172 if( nvars == 1 )
12173 {
12175
12176 /* check whether target has been missed */
12177 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12178 {
12179 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12180 *success = FALSE;
12181 }
12182 }
12183 else if( nvars == 2 )
12184 {
12185 int idx1 = nonfixedpos[0];
12186 int idx2 = nonfixedpos[1];
12187 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12188 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12189 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12190 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12191 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12192 SCIP_Real coefs[2] = { 0.0, 0.0 };
12193
12194 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12195
12196 facetcoefs[idx1] = coefs[0];
12197 facetcoefs[idx2] = coefs[1];
12198 }
12199 else
12200 {
12201 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12202 }
12203 if( !*success )
12204 {
12205 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12206 goto CLEANUP;
12207 }
12208
12209 /*
12210 * check and adjust facet with the algorithm of Rikun et al.
12211 */
12212
12214
12215 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12216 if( maxfaceterror > 0.0 )
12217 {
12218 SCIP_CONSHDLRDATA* conshdlrdata;
12219 SCIP_Real midval;
12220 SCIP_Real feastol;
12221
12223
12224 /* evaluate function in middle point to get some idea for a scaling */
12225 for( j = 0; j < nvars; ++j )
12226 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12227 midval = function(corner, nallvars, fundata);
12228 if( midval == SCIP_INVALID )
12229 midval = 1.0;
12230
12231 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12232 assert(conshdlrdata != NULL);
12233
12234 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12235 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12236 {
12237 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12238 *success = FALSE;
12239 goto CLEANUP;
12240 }
12241
12242 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12243
12244 if( overestimate )
12246 else
12248 }
12249
12250 /* if we made it until here, then we have a nice facet */
12251 assert(*success);
12252
12253CLEANUP:
12254 /* free allocated memory */
12258
12259 return SCIP_OKAY;
12260}
12261
12262/*
12263 * constraint specific interface methods
12264 */
12265
12266/** returns the expression of the given nonlinear constraint */
12268 SCIP_CONS* cons /**< constraint data */
12269 )
12270{
12271 SCIP_CONSDATA* consdata;
12272
12273 assert(cons != NULL);
12275
12276 consdata = SCIPconsGetData(cons);
12277 assert(consdata != NULL);
12278
12279 return consdata->expr;
12280}
12281
12282/** gets the left hand side of a nonlinear constraint */
12284 SCIP_CONS* cons /**< constraint data */
12285 )
12286{
12287 SCIP_CONSDATA* consdata;
12288
12289 assert(cons != NULL);
12291
12292 consdata = SCIPconsGetData(cons);
12293 assert(consdata != NULL);
12294
12295 return consdata->lhs;
12296}
12297
12298/** gets the right hand side of a nonlinear constraint */
12300 SCIP_CONS* cons /**< constraint data */
12301 )
12302{
12303 SCIP_CONSDATA* consdata;
12304
12305 assert(cons != NULL);
12307
12308 consdata = SCIPconsGetData(cons);
12309 assert(consdata != NULL);
12310
12311 return consdata->rhs;
12312}
12313
12314/** gets the nonlinear constraint as a nonlinear row representation. */
12316 SCIP* scip, /**< SCIP data structure */
12317 SCIP_CONS* cons, /**< constraint */
12318 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12319 )
12320{
12321 SCIP_CONSDATA* consdata;
12322
12323 assert(cons != NULL);
12324 assert(nlrow != NULL);
12326
12327 consdata = SCIPconsGetData(cons);
12328 assert(consdata != NULL);
12329
12330 if( consdata->nlrow == NULL )
12331 {
12332 SCIP_CALL( createNlRow(scip, cons) );
12333 }
12334 assert(consdata->nlrow != NULL);
12335 *nlrow = consdata->nlrow;
12336
12337 return SCIP_OKAY;
12338}
12339
12340/** returns the curvature of the expression of a given nonlinear constraint
12341 *
12342 * @note The curvature information is computed during CONSINITSOL.
12343 */
12345 SCIP_CONS* cons /**< constraint data */
12346 )
12347{
12348 SCIP_CONSDATA* consdata;
12349
12350 assert(cons != NULL);
12352
12353 consdata = SCIPconsGetData(cons);
12354 assert(consdata != NULL);
12355
12356 return consdata->curv;
12357}
12358
12359/** checks whether expression of constraint can be represented as quadratic form
12360 *
12361 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12362 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12363 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12364 */
12366 SCIP* scip, /**< SCIP data structure */
12367 SCIP_CONS* cons, /**< constraint data */
12368 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12369 )
12370{
12371 SCIP_CONSDATA* consdata;
12372
12373 assert(scip != NULL);
12374 assert(cons != NULL);
12377
12378 consdata = SCIPconsGetData(cons);
12379 assert(consdata != NULL);
12380 assert(consdata->expr != NULL);
12381
12382 /* check whether constraint expression is quadratic in extended formulation */
12383 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12384
12385 /* if not quadratic in non-extended formulation, then do indicate quadratic */
12386 if( *isquadratic )
12388
12389 return SCIP_OKAY;
12390}
12391
12392/** changes left-hand-side of a nonlinear constraint
12393 *
12394 * @attention This method can only be called in the problem stage.
12395 */
12397 SCIP* scip, /**< SCIP data structure */
12398 SCIP_CONS* cons, /**< constraint data */
12399 SCIP_Real lhs /**< new left-hand-side */
12400 )
12401{
12402 SCIP_CONSDATA* consdata;
12403
12404 assert(scip != NULL);
12405 assert(cons != NULL);
12407
12409 {
12410 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12411 return SCIP_INVALIDCALL;
12412 }
12413
12414 /* we should have an original constraint */
12416
12417 consdata = SCIPconsGetData(cons);
12418 assert(consdata != NULL);
12419
12420 if( consdata->lhs == lhs )
12421 return SCIP_OKAY;
12422
12423 consdata->lhs = lhs;
12424
12425 /* not sure we care about any of these flags for original constraints */
12426 consdata->ispropagated = FALSE;
12427
12428 return SCIP_OKAY;
12429}
12430
12431/** changes right-hand-side of a nonlinear constraint
12432 *
12433 * @attention This method can only be called in the problem stage.
12434 */
12436 SCIP* scip, /**< SCIP data structure */
12437 SCIP_CONS* cons, /**< constraint data */
12438 SCIP_Real rhs /**< new right-hand-side */
12439 )
12440{
12441 SCIP_CONSDATA* consdata;
12442
12443 assert(scip != NULL);
12444 assert(cons != NULL);
12446
12448 {
12449 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12450 return SCIP_INVALIDCALL;
12451 }
12452
12453 /* we should have an original constraint */
12455
12456 consdata = SCIPconsGetData(cons);
12457 assert(consdata != NULL);
12458
12459 if( consdata->rhs == rhs )
12460 return SCIP_OKAY;
12461
12462 consdata->rhs = rhs;
12463
12464 /* not sure we care about any of these flags for original constraints */
12465 consdata->ispropagated = FALSE;
12466
12467 return SCIP_OKAY;
12468}
12469
12470/** changes expression of a nonlinear constraint
12471 *
12472 * @attention This method can only be called in the problem stage.
12473 */
12475 SCIP* scip, /**< SCIP data structure */
12476 SCIP_CONS* cons, /**< constraint data */
12477 SCIP_EXPR* expr /**< new expression */
12478 )
12479{
12480 SCIP_CONSHDLR* conshdlr;
12481 SCIP_CONSDATA* consdata;
12482
12483 assert(scip != NULL);
12484 assert(cons != NULL);
12485 assert(expr != NULL);
12486
12488 {
12489 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12490 return SCIP_INVALIDCALL;
12491 }
12492
12493 /* we should have an original constraint */
12495
12496 conshdlr = SCIPconsGetHdlr(cons);
12497 assert(conshdlr != NULL);
12499
12500 consdata = SCIPconsGetData(cons);
12501 assert(consdata != NULL);
12502 assert(consdata->expr != NULL);
12503
12504 /* we should not have collected additional data for the expr
12505 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12506 */
12507 assert(consdata->nvarexprs == 0);
12508 assert(consdata->varexprs == NULL);
12509 assert(!consdata->catchedevents);
12510
12511 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12512
12513 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12514 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12515
12516 /* not sure we care about any of these flags for original constraints */
12517 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12518 consdata->issimplified = FALSE;
12519 consdata->ispropagated = FALSE;
12520
12521 return SCIP_OKAY;
12522}
12523
12524/** adds coef * var to nonlinear constraint
12525 *
12526 * @attention This method can only be called in the problem stage.
12527 */
12529 SCIP* scip, /**< SCIP data structure */
12530 SCIP_CONS* cons, /**< constraint data */
12531 SCIP_VAR* var, /**< variable */
12532 SCIP_Real coef /**< coefficient */
12533 )
12534{
12535 SCIP_CONSHDLR* conshdlr;
12536 SCIP_CONSDATA* consdata;
12538
12539 assert(scip != NULL);
12540 assert(cons != NULL);
12541
12543 {
12544 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12545 return SCIP_INVALIDCALL;
12546 }
12547
12548 /* we should have an original constraint */
12550
12551 if( coef == 0.0 )
12552 return SCIP_OKAY;
12553
12554 conshdlr = SCIPconsGetHdlr(cons);
12555 assert(conshdlr != NULL);
12557
12558 consdata = SCIPconsGetData(cons);
12559 assert(consdata != NULL);
12560 assert(consdata->expr != NULL);
12561
12562 /* we should not have collected additional data for it
12563 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12564 */
12565 assert(consdata->nvarexprs == 0);
12566 assert(consdata->varexprs == NULL);
12567 assert(!consdata->catchedevents);
12568
12569 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12570
12571 /* append to sum, if consdata->expr is sum and not used anywhere else */
12572 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12573 {
12574 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12575 }
12576 else
12577 {
12578 /* create new expression = 1 * consdata->expr + coef * var */
12579 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12580 SCIP_Real coefs[2] = { 1.0, coef };
12581
12582 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12583
12584 /* release old root expr */
12585 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12586 }
12587
12589
12590 /* not sure we care about any of these flags for original constraints */
12591 consdata->issimplified = FALSE;
12592 consdata->ispropagated = FALSE;
12593
12594 return SCIP_OKAY;
12595}
12596
12597/** adds coef * expr to nonlinear constraint
12598 *
12599 * @attention This method can only be called in the problem stage.
12600 */
12602 SCIP* scip, /**< SCIP data structure */
12603 SCIP_CONS* cons, /**< nonlinear constraint */
12604 SCIP_EXPR* expr, /**< expression */
12605 SCIP_Real coef /**< coefficient */
12606 )
12607{
12608 SCIP_CONSHDLR* conshdlr;
12609 SCIP_CONSDATA* consdata;
12611
12612 assert(scip != NULL);
12613 assert(cons != NULL);
12614
12616 {
12617 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12618 return SCIP_INVALIDCALL;
12619 }
12620
12621 /* we should have an original constraint */
12623
12624 if( coef == 0.0 )
12625 return SCIP_OKAY;
12626
12627 conshdlr = SCIPconsGetHdlr(cons);
12628 assert(conshdlr != NULL);
12630
12631 consdata = SCIPconsGetData(cons);
12632 assert(consdata != NULL);
12633 assert(consdata->expr != NULL);
12634
12635 /* we should not have collected additional data for it
12636 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12637 */
12638 assert(consdata->nvarexprs == 0);
12639 assert(consdata->varexprs == NULL);
12640 assert(!consdata->catchedevents);
12641
12642 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12643 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12644
12645 /* append to sum, if consdata->expr is sum and not used anywhere else */
12646 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12647 {
12648 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12649 }
12650 else
12651 {
12652 /* create new expression = 1 * consdata->expr + coef * var */
12653 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12654 SCIP_Real coefs[2] = { 1.0, coef };
12655
12656 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12657
12658 /* release old root expr */
12659 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12660 }
12661
12663
12664 /* not sure we care about any of these flags for original constraints */
12665 consdata->issimplified = FALSE;
12666 consdata->ispropagated = FALSE;
12667
12668 return SCIP_OKAY;
12669}
12670
12671/** gets absolute violation of nonlinear constraint
12672 *
12673 * This function evaluates the constraints in the given solution.
12674 *
12675 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12676 */
12678 SCIP* scip, /**< SCIP data structure */
12679 SCIP_CONS* cons, /**< constraint */
12680 SCIP_SOL* sol, /**< solution to check */
12681 SCIP_Real* viol /**< buffer to store computed violation */
12682 )
12683{
12684 assert(cons != NULL);
12685 assert(viol != NULL);
12686
12687 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12688 *viol = getConsAbsViolation(cons);
12689
12690 return SCIP_OKAY;
12691}
12692
12693/** gets scaled violation of nonlinear constraint
12694 *
12695 * This function evaluates the constraints in the given solution.
12696 *
12697 * The scaling that is applied to the absolute violation of the constraint
12698 * depends on the setting of parameter constraints/nonlinear/violscale.
12699 */
12701 SCIP* scip, /**< SCIP data structure */
12702 SCIP_CONS* cons, /**< constraint */
12703 SCIP_SOL* sol, /**< solution to check */
12704 SCIP_Real* viol /**< buffer to store computed violation */
12705 )
12706{
12707 assert(cons != NULL);
12708 assert(viol != NULL);
12709
12710 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12711 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12712
12713 return SCIP_OKAY;
12714}
12715
12716/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12718 SCIP* scip, /**< SCIP data structure */
12719 SCIP_CONS* cons, /**< nonlinear constraint */
12720 SCIP_VAR** var, /**< pointer to store the variable */
12721 SCIP_Real* coef /**< pointer to store the coefficient */
12722 )
12723{
12724 SCIP_CONSDATA* consdata;
12725
12726 assert(cons != NULL);
12727 assert(var != NULL);
12728 assert(coef != NULL);
12729
12730 /* check for a linear variable that can be increased or decreased without harming feasibility */
12732
12733 consdata = SCIPconsGetData(cons);
12734 assert(consdata != NULL);
12735
12736 *var = consdata->linvardecr;
12737 *coef = consdata->linvardecrcoef;
12738}
12739
12740/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12742 SCIP* scip, /**< SCIP data structure */
12743 SCIP_CONS* cons, /**< nonlinear constraint */
12744 SCIP_VAR** var, /**< pointer to store the variable */
12745 SCIP_Real* coef /**< pointer to store the coefficient */
12746 )
12747{
12748 SCIP_CONSDATA* consdata;
12749
12750 assert(cons != NULL);
12751 assert(var != NULL);
12752 assert(coef != NULL);
12753
12754 /* check for a linear variable that can be increased or decreased without harming feasibility */
12756
12757 consdata = SCIPconsGetData(cons);
12758 assert(consdata != NULL);
12759
12760 *var = consdata->linvarincr;
12761 *coef = consdata->linvarincrcoef;
12762}
12763
12764
12765/*
12766 * Methods for Expressions in Nonlinear Constraints
12767 */
12768
12769/** returns the number of positive rounding locks of an expression */
12771 SCIP_EXPR* expr /**< expression */
12772 )
12773{
12774 assert(expr != NULL);
12776
12777 return SCIPexprGetOwnerData(expr)->nlockspos;
12778}
12779
12780/** returns the number of negative rounding locks of an expression */
12782 SCIP_EXPR* expr /**< expression */
12783 )
12784{
12785 assert(expr != NULL);
12787
12788 return SCIPexprGetOwnerData(expr)->nlocksneg;
12789}
12790
12791/** returns the variable used for linearizing a given expression (return value might be NULL)
12792 *
12793 * @note for variable expression it returns the corresponding variable
12794 */
12796 SCIP_EXPR* expr /**< expression */
12797 )
12798{
12799 SCIP_EXPR_OWNERDATA* ownerdata;
12800
12801 assert(expr != NULL);
12802
12803 ownerdata = SCIPexprGetOwnerData(expr);
12804 assert(ownerdata != NULL);
12805
12806 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12807}
12808
12809/** returns the number of enforcements for an expression */
12811 SCIP_EXPR* expr /**< expression */
12812 )
12813{
12814 assert(expr != NULL);
12816
12817 return SCIPexprGetOwnerData(expr)->nenfos;
12818}
12819
12820/** returns the data for one of the enforcements of an expression */
12822 SCIP_EXPR* expr, /**< expression */
12823 int idx, /**< position of enforcement in enfos array */
12824 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12825 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12826 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12827 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12828 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12829 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12830 )
12831{
12832 SCIP_EXPR_OWNERDATA* ownerdata;
12833
12834 assert(expr != NULL);
12835
12836 ownerdata = SCIPexprGetOwnerData(expr);
12837 assert(ownerdata != NULL);
12838 assert(idx >= 0);
12840 assert(ownerdata->enfos[idx] != NULL);
12841 assert(nlhdlr != NULL);
12842
12843 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12844
12845 if( nlhdlrexprdata != NULL )
12846 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12847
12848 if( nlhdlrparticipation != NULL )
12849 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12850
12851 if( sepabelowusesactivity != NULL )
12852 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12853
12854 if( sepaaboveusesactivity != NULL )
12855 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12856
12857 if( auxvalue != NULL )
12858 *auxvalue = ownerdata->enfos[idx]->auxvalue;
12859}
12860
12861/** sets the auxiliary value of expression for one of the enforcements of an expression */
12863 SCIP_EXPR* expr, /**< expression */
12864 int idx, /**< position of enforcement in enfos array */
12865 SCIP_Real auxvalue /**< the new value of auxval */
12866 )
12867{
12868 SCIP_EXPR_OWNERDATA* ownerdata;
12869
12870 assert(expr != NULL);
12871
12872 ownerdata = SCIPexprGetOwnerData(expr);
12873 assert(ownerdata != NULL);
12874
12875 assert(idx >= 0);
12877 assert(ownerdata->enfos[idx] != NULL);
12878
12879 ownerdata->enfos[idx]->auxvalue = auxvalue;
12880}
12881
12882/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12883 *
12884 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12885 */
12887 SCIP_EXPR* expr /**< expression */
12888 )
12889{
12890 assert(expr != NULL);
12892
12893 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12894}
12895
12896/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12897 *
12898 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12899 */
12901 SCIP_EXPR* expr /**< expression */
12902 )
12903{
12904 assert(expr != NULL);
12906
12907 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12908}
12909
12910/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12911 *
12912 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12913 */
12915 SCIP_EXPR* expr /**< expression */
12916 )
12917{
12918 assert(expr != NULL);
12920
12921 return SCIPexprGetOwnerData(expr)->nauxvaruses;
12922}
12923
12924/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12925 *
12926 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12927 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12928 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12929 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12930 * and also increments this count for all variables in the expression.
12931 *
12932 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12933 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12934 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12935 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12936 */
12938 SCIP* scip, /**< SCIP data structure */
12939 SCIP_EXPR* expr, /**< expression */
12940 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12941 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12942 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12943 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12944 )
12945{
12946 SCIP_EXPR_OWNERDATA* ownerdata;
12947
12948 assert(expr != NULL);
12949
12950 ownerdata = SCIPexprGetOwnerData(expr);
12951 assert(ownerdata != NULL);
12952
12953 /* do not store auxvar request for variable expressions */
12954 if( useauxvar && SCIPisExprVar(scip, expr) )
12955 useauxvar = FALSE;
12956
12957 if( ownerdata->nenfos >= 0 &&
12958 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12959 (ownerdata->nauxvaruses == 0 && useauxvar)
12960 ) )
12961 {
12962 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12963 * we require additional enforcement methods, that is,
12964 * - activity of expr was not used before but will be used now, or
12965 * - auxiliary variable of expr was not required before but will be used now
12966 */
12967 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12968 }
12969
12970 if( useauxvar )
12971 ++ownerdata->nauxvaruses;
12972
12973 if( useactivityforprop )
12974 ++ownerdata->nactivityusesprop;
12975
12977 ++ownerdata->nactivityusessepa;
12978
12979 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12980 * information is used in detectNlhdlr()
12981 */
12983 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12985 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12986
12987 if( useactivityforprop )
12988 {
12989 /* if activity will be used for propagation, then make sure there is a valid activity
12990 * this way, we can do a reversepropcall after detectNlhdlr
12991 */
12993 }
12994
12995 /* increase the nactivityusedsepa counter for all variables used in the given expression */
12997 {
12999
13000 /* create and initialize iterator */
13003
13004 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13005 if( SCIPisExprVar(scip, expr) )
13006 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
13007
13008 /* free iterator */
13010 }
13011
13012 return SCIP_OKAY;
13013}
13014
13015/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
13016 *
13017 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
13018 * Assume that f(x) is associated with auxiliary variable z.
13019 *
13020 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13021 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13022 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13023 *
13024 * If necessary, f is evaluated in the given solution. If that fails (domain error),
13025 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13026 */
13028 SCIP* scip, /**< SCIP data structure */
13029 SCIP_EXPR* expr, /**< expression */
13030 SCIP_SOL* sol, /**< solution */
13031 SCIP_Longint soltag, /**< tag of solution */
13032 SCIP_Real* viol, /**< buffer to store computed violation */
13033 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13034 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13035 )
13036{
13037 assert(scip != NULL);
13038 assert(expr != NULL);
13039 assert(viol != NULL);
13040
13041 /* make sure expression has been evaluated */
13042 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13043
13044 /* get violation from internal method */
13046
13047 return SCIP_OKAY;
13048}
13049
13050/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13051 *
13052 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13053 * Assume that f(w) is associated with auxiliary variable z.
13054 *
13055 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13056 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13057 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13058 *
13059 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13060 * both `violover` and `violunder` are set to TRUE.
13061 */
13063 SCIP* scip, /**< SCIP data structure */
13064 SCIP_EXPR* expr, /**< expression */
13065 SCIP_Real auxvalue, /**< the value of f(w) */
13066 SCIP_SOL* sol, /**< solution that has been evaluated */
13067 SCIP_Real* viol, /**< buffer to store computed violation */
13068 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13069 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13070 )
13071{
13072 assert(scip != NULL);
13073 assert(expr != NULL);
13074 assert(viol != NULL);
13075
13076 /* get violation from internal method */
13077 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13078
13079 return SCIP_OKAY;
13080}
13081
13082
13083/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13084 *
13085 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13086 * Assume that f(w) is associated with auxiliary variable z.
13087 *
13088 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13089 * the absolute violation divided by max(1,|f(w)|).
13090 *
13091 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13092 * both `violover` and `violunder` are set to TRUE.
13093 */
13095 SCIP* scip, /**< SCIP data structure */
13096 SCIP_EXPR* expr, /**< expression */
13097 SCIP_Real auxvalue, /**< the value of f(w) */
13098 SCIP_SOL* sol, /**< solution that has been evaluated */
13099 SCIP_Real* viol, /**< buffer to store computed violation */
13100 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13101 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13102 )
13103{
13104 assert(scip != NULL);
13105 assert(expr != NULL);
13106 assert(viol != NULL);
13107
13108 /* get violation from internal method */
13109 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13110
13111 if( !SCIPisInfinity(scip, *viol) )
13112 {
13113 assert(auxvalue != SCIP_INVALID);
13114 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13115 *viol /= MAX(1.0, REALABS(auxvalue));
13116 }
13117
13118 return SCIP_OKAY;
13119}
13120
13121/** returns bounds on the expression
13122 *
13123 * This gives an intersection of bounds from
13124 * - activity calculation (SCIPexprGetActivity()), if valid,
13125 * - auxiliary variable, if present,
13126 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13127 *
13128 * @note The returned interval can be empty!
13129 */
13131 SCIP* scip, /**< SCIP data structure */
13132 SCIP_EXPR* expr /**< expression */
13133 )
13134{
13135 SCIP_EXPR_OWNERDATA* ownerdata;
13136 SCIP_CONSHDLRDATA* conshdlrdata;
13137 SCIP_INTERVAL bounds;
13138
13139 assert(scip != NULL);
13140 assert(expr != NULL);
13141
13142 ownerdata = SCIPexprGetOwnerData(expr);
13143 assert(ownerdata != NULL);
13144
13145 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13146 assert(conshdlrdata != NULL);
13147
13148 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13149
13150 /* start with propbounds if they belong to current propagation */
13151 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13152 {
13153 bounds = ownerdata->propbounds;
13154 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13155 }
13156 else
13158
13159 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13160 {
13161 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13162 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13164 }
13165
13166 if( ownerdata->auxvar != NULL )
13167 {
13168 /* apply auxiliary variable bounds to bounds */
13170
13171 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13172 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13174 }
13175
13176 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13177
13178 return bounds;
13179}
13180
13181/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13182 * corresponding (auxiliary) variable (if any)
13183 *
13184 * @attention this function should only be called during domain propagation in cons_nonlinear
13185 */
13187 SCIP* scip, /**< SCIP data structure */
13188 SCIP_EXPR* expr, /**< expression to be tightened */
13189 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13190 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13191 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13192 )
13193{
13194 SCIP_EXPR_OWNERDATA* ownerdata;
13195 SCIP_CONSHDLRDATA* conshdlrdata;
13196
13197 assert(scip != NULL);
13198 assert(expr != NULL);
13199 assert(cutoff != NULL);
13200
13201 ownerdata = SCIPexprGetOwnerData(expr);
13202 assert(ownerdata != NULL);
13203 assert(ownerdata->conshdlr != NULL);
13204
13205 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13206 assert(conshdlrdata != NULL);
13207
13208 /* the code below assumes that current activity is valid
13209 * if it turns out that we cannot ensure that, then we should change code
13210 */
13211 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13213
13214 *cutoff = FALSE;
13215
13216#ifdef DEBUG_PROP
13217 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13218 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13219 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13220#endif
13221
13222 if( SCIPexprIsIntegral(expr) )
13223 {
13224 /* apply integrality to new bounds
13225 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13226 */
13228 newbounds.inf = SCIPceil(scip, newbounds.inf);
13230 newbounds.sup = SCIPfloor(scip, newbounds.sup);
13231#ifdef DEBUG_PROP
13232 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13233#endif
13234 }
13235
13237 {
13238 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13239
13240 *cutoff = TRUE;
13241 return SCIP_OKAY;
13242 }
13243
13244 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13246 {
13247 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13248
13249 *cutoff = TRUE;
13250 return SCIP_OKAY;
13251 }
13252
13253 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13254 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13255 {
13256 /* if already having propbounds in expr, then tighten newbounds by propbounds */
13257 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13258 }
13259 else
13260 {
13261 /* first time we have propbounds for expr in this propagation rounds:
13262 * intersect with activity (though don't let it become empty if very close intervals)
13263 */
13265 }
13266#ifdef DEBUG_PROP
13267 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13268#endif
13269
13270 /* check if the new bounds lead to an empty interval */
13272 {
13273 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13274
13275 *cutoff = TRUE;
13276 return SCIP_OKAY;
13277 }
13278
13279 /* if expr is not constant or variable, then store newbounds in expr->propbounds
13280 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13281 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13282 */
13283 if( SCIPexprGetNChildren(expr) > 0 )
13284 {
13285 ownerdata->propbounds = newbounds;
13286 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13287 }
13288
13289 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13290 * propagation or update of auxvar bounds
13291 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13292 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13293 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13294 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13295 * one or should we not even update propbounds to newbounds if the update is small?
13296 */
13297 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13298 {
13299#ifdef DEBUG_PROP
13300 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);
13301#endif
13302 return SCIP_OKAY;
13303 }
13304
13305 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13306 {
13307 /* add expression to propagation queue if not there yet and not var or constant and
13308 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13309 */
13310#ifdef DEBUG_PROP
13311 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13312#endif
13313 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13314 ownerdata->inpropqueue = TRUE;
13315 }
13316
13317 /* update bounds on variable or auxiliary variable */
13318 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13319
13320 return SCIP_OKAY;
13321}
13322
13323/** mark constraints that include this expression to be propagated again
13324 *
13325 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13326 * a change of variable bounds, e.g., because new information on the expression is available
13327 * that could potentially lead to tighter expression activity values.
13328 *
13329 * Note, that this call marks also constraints for propagation which only share some variable
13330 * with this expression.
13331 */
13333 SCIP* scip, /**< SCIP data structure */
13334 SCIP_EXPR* expr /**< expression to propagate again */
13335 )
13336{
13338 SCIP_CONSDATA* consdata;
13339 SCIP_EXPR_OWNERDATA* ownerdata;
13340 int c;
13341
13342 assert(scip != NULL);
13343 assert(expr != NULL);
13344
13345 ownerdata = SCIPexprGetOwnerData(expr);
13346 assert(ownerdata != NULL);
13347
13348 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13349
13352
13353 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13354 {
13355 if( !SCIPisExprVar(scip, expr) )
13356 continue;
13357
13358 ownerdata = SCIPexprGetOwnerData(expr);
13359 assert(ownerdata != NULL);
13360
13361 for( c = 0; c < ownerdata->nconss; ++c )
13362 {
13363 consdata = SCIPconsGetData(ownerdata->conss[c]);
13364 assert(consdata != NULL);
13365 consdata->ispropagated = FALSE;
13366 }
13367 }
13368
13370
13371 return SCIP_OKAY;
13372}
13373
13374/** adds violation-branching score to an expression
13375 *
13376 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13377 * The expression must either be a variable expression or have an aux-variable.
13378 * In the latter case, branching on auxiliary variables must have been enabled.
13379 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13380 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13381 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13382 *
13383 * @see SCIPaddExprsViolScoreNonlinear()
13384 */
13386 SCIP* scip, /**< SCIP data structure */
13387 SCIP_EXPR* expr, /**< expression where to add branching score */
13388 SCIP_Real violscore /**< violation score to add to expression */
13389 )
13390{
13391 SCIP_EXPR_OWNERDATA* ownerdata;
13392 SCIP_CONSHDLRDATA* conshdlrdata;
13393
13394 assert(scip != NULL);
13395 assert(expr != NULL);
13396 assert(violscore >= 0.0);
13397
13398 ownerdata = SCIPexprGetOwnerData(expr);
13399 assert(ownerdata != NULL);
13400
13401 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13402 assert(conshdlrdata != NULL);
13403
13404 /* if not allowing to branch on auxvars, then expr must be a var-expr */
13405 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13406 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13407 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13408
13409 /* reset branching score if we are in a different enfo round */
13410 if( ownerdata->violscoretag != conshdlrdata->enforound )
13411 {
13412 ownerdata->violscoresum = violscore;
13413 ownerdata->violscoremax = violscore;
13414 ownerdata->nviolscores = 1;
13415 ownerdata->violscoretag = conshdlrdata->enforound;
13416 return;
13417 }
13418
13419 ownerdata->violscoresum += violscore;
13420 if( violscore > ownerdata->violscoremax )
13421 ownerdata->violscoremax = violscore;
13422 ++ownerdata->nviolscores;
13423}
13424
13425/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13426 *
13427 * Each expression must either be a variable expression or have an aux-variable.
13428 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13429 * variables present in `exprs`.
13430 */
13432 SCIP* scip, /**< SCIP data structure */
13433 SCIP_EXPR** exprs, /**< expressions where to add branching score */
13434 int nexprs, /**< number of expressions */
13435 SCIP_Real violscore, /**< violation score to add to expression */
13436 SCIP_SOL* sol, /**< current solution */
13437 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13438 )
13439{
13441 SCIP_EXPR** varexprs;
13442 SCIP_EXPR* e;
13443 int nvars;
13444 int varssize;
13445 int i;
13446
13447 assert(exprs != NULL || nexprs == 0);
13448 assert(success != NULL);
13449
13450 if( nexprs == 0 )
13451 {
13452 *success = FALSE;
13453 return SCIP_OKAY;
13454 }
13455
13456 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13457 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13458 {
13459 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13460 return SCIP_OKAY;
13461 }
13462
13463 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13464 nvars = 0;
13465 varssize = 5;
13466 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13467
13470
13471 for( i = 0; i < nexprs; ++i )
13472 {
13474 {
13475 assert(e != NULL);
13476
13477 if( SCIPisExprVar(scip, e) )
13478 {
13479 /* add variable expression to vars array */
13480 if( varssize == nvars )
13481 {
13482 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13483 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13484 }
13485 assert(varssize > nvars);
13486
13487 varexprs[nvars++] = e;
13488 }
13489 }
13490 }
13491
13493
13495
13496 SCIPfreeBufferArray(scip, &varexprs);
13497
13498 return SCIP_OKAY;
13499}
13500
13501/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13503 SCIP_EXPR* expr /**< expression */
13504 )
13505{
13506 SCIP_EXPR_OWNERDATA* ownerdata;
13507 SCIP_CONSHDLRDATA* conshdlrdata;
13508
13509 assert(expr != NULL);
13510
13511 ownerdata = SCIPexprGetOwnerData(expr);
13512 assert(ownerdata != NULL);
13513
13514 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13515 assert(conshdlrdata != NULL);
13516
13517 if( conshdlrdata->enforound != ownerdata->violscoretag )
13518 return 0.0;
13519
13520 if( ownerdata->nviolscores == 0 )
13521 return 0.0;
13522
13523 switch( conshdlrdata->branchscoreagg )
13524 {
13525 case 'a' :
13526 /* average */
13527 return ownerdata->violscoresum / ownerdata->nviolscores;
13528
13529 case 'm' :
13530 /* maximum */
13531 return ownerdata->violscoremax;
13532
13533 case 's' :
13534 /* sum */
13535 return ownerdata->violscoresum;
13536
13537 default:
13538 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13539 SCIPABORT();
13540 return SCIP_INVALID;
13541 }
13542}
13543
13544/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13545 *
13546 * @see SCIPexprGetDerivative()
13547 */
13549 SCIP* scip, /**< SCIP data structure */
13550 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13551 SCIP_VAR* var /**< variable (needs to be in the expression) */
13552 )
13553{
13554 SCIP_EXPR_OWNERDATA* ownerdata;
13555 SCIP_CONSHDLRDATA* conshdlrdata;
13557
13558 assert(scip != NULL);
13559 assert(expr != NULL);
13560 assert(var != NULL);
13561
13562 /* return 0.0 for value expression */
13563 if( SCIPisExprValue(scip, expr) )
13564 {
13565 assert(SCIPexprGetDerivative(expr) == 0.0);
13566 return 0.0;
13567 }
13568
13569 /* check if an error occurred during the last SCIPevalExprGradient() call */
13570 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13571 return SCIP_INVALID;
13572
13573 ownerdata = SCIPexprGetOwnerData(expr);
13574 assert(ownerdata != NULL);
13575
13576 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13577 assert(conshdlrdata != NULL);
13578
13579 /* use variable to expressions mapping which is stored in the constraint handler data */
13580 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13581
13582 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13583 assert(varexpr != NULL);
13585
13586 /* use difftag to decide whether the variable belongs to the expression */
13588}
13589
13590/** 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)
13591 *
13592 * @see SCIPexprGetBardot()
13593 */
13595 SCIP* scip, /**< SCIP data structure */
13596 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13597 SCIP_VAR* var /**< variable (needs to be in the expression) */
13598 )
13599{
13600 SCIP_EXPR_OWNERDATA* ownerdata;
13601 SCIP_CONSHDLRDATA* conshdlrdata;
13603
13604 assert(scip != NULL);
13605 assert(expr != NULL);
13606 assert(var != NULL);
13607
13608 /* return 0.0 for value expression */
13609 if( SCIPisExprValue(scip, expr) )
13610 return 0.0;
13611
13612 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13613 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13614 return SCIP_INVALID;
13615
13616 ownerdata = SCIPexprGetOwnerData(expr);
13617 assert(ownerdata != NULL);
13618
13619 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13620 assert(conshdlrdata != NULL);
13621
13622 /* use variable to expressions mapping which is stored in the constraint handler data;
13623 * if this fails it means that we are asking for the var's component of H*u for a var
13624 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13625 */
13626 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13627
13628 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13629 assert(varexpr != NULL);
13631
13632 /* use difftag to decide whether the variable belongs to the expression */
13634}
13635
13636/** evaluates quadratic term in a solution w.r.t. auxiliary variables
13637 *
13638 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13639 */
13641 SCIP* scip, /**< SCIP data structure */
13642 SCIP_EXPR* expr, /**< quadratic expression */
13643 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13644 )
13645{
13646 SCIP_Real auxvalue;
13647 int nlinexprs;
13648 SCIP_Real* lincoefs;
13649 SCIP_EXPR** linexprs;
13650 int nquadexprs;
13651 int nbilinexprs;
13652 int i;
13653
13654 assert(scip != NULL);
13655 assert(expr != NULL);
13656
13657 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13658
13659 /* linear terms */
13660 for( i = 0; i < nlinexprs; ++i )
13661 {
13662 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13663 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13664 }
13665
13666 /* quadratic terms */
13667 for( i = 0; i < nquadexprs; ++i )
13668 {
13670 SCIP_Real lincoef;
13671 SCIP_Real sqrcoef;
13672 SCIP_Real solval;
13673
13674 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13675
13677
13679 auxvalue += (lincoef + sqrcoef * solval) * solval;
13680 }
13681
13682 /* bilinear terms */
13683 for( i = 0; i < nbilinexprs; ++i )
13684 {
13685 SCIP_EXPR* expr1;
13686 SCIP_EXPR* expr2;
13687 SCIP_Real coef;
13688
13689 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13690
13694 }
13695
13696 return auxvalue;
13697}
13698
13699/**@addtogroup PublicNlhdlrInterfaceMethods
13700 * @{
13701 */
13702
13703/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13705 SCIP* scip, /**< SCIP data structure */
13706 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13707 const char* name, /**< name of nonlinear handler (must not be NULL) */
13708 const char* desc, /**< description of nonlinear handler (can be NULL) */
13709 int detectpriority, /**< detection priority of nonlinear handler */
13710 int enfopriority, /**< enforcement priority of nonlinear handler */
13711 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13712 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13713 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13714 )
13715{
13716 SCIP_CONSHDLR* conshdlr;
13717 SCIP_CONSHDLRDATA* conshdlrdata;
13718
13719 assert(scip != NULL);
13720 assert(nlhdlr != NULL);
13721 assert(detect != NULL);
13722
13723 /* find myself */
13724 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13725 if( conshdlr == NULL )
13726 {
13727 SCIPerrorMessage("nonlinear constraint handler not found");
13728 return SCIP_PLUGINNOTFOUND;
13729 }
13730
13731 /* create nlhdlr */
13732 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13733
13734 /* include into constraint handler */
13735 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13736 assert(conshdlrdata != NULL);
13737
13738 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13739
13740 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13741 ++conshdlrdata->nnlhdlrs;
13742
13743 /* sort nonlinear handlers by detection priority, in decreasing order
13744 * will happen in INIT, so only do when called late
13745 */
13746 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13747 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13748
13749 return SCIP_OKAY;
13750}
13751
13752/** get number of nonlinear handler */
13754 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13755 )
13756{
13757 SCIP_CONSHDLRDATA* conshdlrdata;
13758
13759 assert(conshdlr != NULL);
13760
13761 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13762 assert(conshdlrdata != NULL);
13763
13764 return conshdlrdata->nnlhdlrs;
13765}
13766
13767/** get nonlinear handlers */
13769 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13770 )
13771{
13772 SCIP_CONSHDLRDATA* conshdlrdata;
13773
13774 assert(conshdlr != NULL);
13775
13776 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13777 assert(conshdlrdata != NULL);
13778
13779 return conshdlrdata->nlhdlrs;
13780}
13781
13782/** returns a nonlinear handler of a given name (or NULL if not found) */
13784 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13785 const char* name /**< name of nonlinear handler */
13786 )
13787{
13788 SCIP_CONSHDLRDATA* conshdlrdata;
13789 int h;
13790
13791 assert(conshdlr != NULL);
13792 assert(name != NULL);
13793
13794 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13795 assert(conshdlrdata != NULL);
13796
13797 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13798 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13799 return conshdlrdata->nlhdlrs[h];
13800
13801 return NULL;
13802}
13803
13804/** gives expression data that a given nonlinear handler stored in an expression
13805 *
13806 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13807 */
13809 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13810 SCIP_EXPR* expr /**< expression */
13811 )
13812{
13813 SCIP_EXPR_OWNERDATA* ownerdata;
13814 int e;
13815
13816 assert(nlhdlr != NULL);
13817 assert(expr != NULL);
13818
13819 ownerdata = SCIPexprGetOwnerData(expr);
13820 assert(ownerdata != NULL);
13821
13822 for( e = 0; e < ownerdata->nenfos; ++e )
13823 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13824 return ownerdata->enfos[e]->nlhdlrexprdata;
13825
13826 return NULL;
13827}
13828
13829/** @} */
static GRAPHNODE ** active
SCIP_VAR * h
SCIP_VAR * w
SCIP_VAR * a
SCIP_VAR ** y
SCIP_VAR ** x
Constraint handler for AND constraints, .
constraint handler for bound disjunction constraints
Constraint handler for linear constraints in their most general form, .
static SCIP_Bool isBinaryProduct(SCIP *scip, SCIP_EXPR *expr)
static SCIP_RETCODE createExprVar(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR **expr, SCIP_VAR *var)
static SCIP_Real computeVertexPolyhedralMaxFacetError(SCIP *scip, SCIP_Bool overestimate, SCIP_Real *funvals, SCIP_Real *box, int nallvars, int nvars, int *nonfixedpos, SCIP_Real *facetcoefs, SCIP_Real facetconstant)
#define ENFOLOG(x)
#define DIALOG_DESC
#define CONSHDLR_NEEDSCONS
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE analyzeViolation(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *maxabsconsviol, SCIP_Real *maxrelconsviol, SCIP_Real *minauxviol, SCIP_Real *maxauxviol, SCIP_Real *maxvarboundviol)
static SCIP_RETCODE presolveRedundantConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss, int *nchgbds)
static SCIP_RETCODE reversePropQueue(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool *infeasible, int *ntightenings)
#define BRANCH_RANDNUMINITSEED
static SCIP_RETCODE dropVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE forbidNonlinearVariablesMultiaggration(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE computeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
static SCIP_RETCODE propagateLocks(SCIP *scip, SCIP_EXPR *expr, int nlockspos, int nlocksneg)
#define CONSHDLR_CHECKPRIORITY
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
#define CONSHDLR_DESC
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_EXPRITER *it, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Bool *success)
static SCIP_RETCODE bilinTermAddAuxExpr(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSNONLINEAR_BILINTERM *term, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Bool *added)
static SCIP_RETCODE freeVarExprs(SCIP *scip, SCIP_CONSDATA *consdata)
#define DIALOG_NAME
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
#define consRespropNonlinear
static SCIP_RETCODE addTightEstimatorCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, EXPRENFO *exprenfo, SCIP_SOL *sol, SCIP_Bool overestimate, SCIP_PTRARRAY *rowpreps)
static SCIP_RETCODE consSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
#define CONSHDLR_PROP_TIMING
static void addExprsViolScore(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE tightenAuxVarBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL bounds, SCIP_Bool *cutoff, int *ntightenings)
#define TABLE_DESC_NLHDLR
static SCIP_RETCODE replaceBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_HASHMAP *exprmap, SCIP_EXPRITER *it, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE computeVertexPolyhedralFacetBivariate(SCIP *scip, SCIP_Bool overestimate, SCIP_Real p1[2], SCIP_Real p2[2], SCIP_Real p3[2], SCIP_Real p4[2], SCIP_Real p1val, SCIP_Real p2val, SCIP_Real p3val, SCIP_Real p4val, SCIP_Real xstar[2], SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
#define consInitpreNonlinear
static SCIP_RETCODE addExprViolScoresAuxVars(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore, SCIP_VAR **auxvars, int nauxvars, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE detectNlhdlr(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE computeVertexPolyhedralFacetLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_Real *xstar, SCIP_Real *box, int nallvars, int *nonfixedpos, SCIP_Real *funvals, int nvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
#define TABLE_EARLIEST_STAGE_NLHDLR
#define VERTEXPOLY_RANDNUMINITSEED
static SCIP_RETCODE getFactorizedBinaryQuadraticExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *sumexpr, int minterms, SCIP_EXPR **newexpr, int *naddconss)
#define consDelvarsNonlinear
static SCIP_RETCODE enforceExprNlhdlr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_Real auxvalue, SCIP_Bool overestimate, SCIP_Bool separated, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result)
static SCIP_RETCODE reformulateFactorizedBinaryQuadratic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_VAR *facvar, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_EXPR **newexpr, int *naddconss)
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_SOL *sol)
#define CONSHDLR_SEPAPRIORITY
static SCIP_RETCODE getConsRelViolation(SCIP *scip, SCIP_CONS *cons, SCIP_Real *viol, SCIP_SOL *sol, SCIP_Longint soltag)
#define consGetDiveBdChgsNonlinear
static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE getBinaryProductExprDo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, SCIP_Bool empathy4and)
static SCIP_RETCODE registerBranchingCandidatesAllUnfixed(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
static SCIP_Bool isIntervalBetter(SCIP *scip, SCIP_Bool subsetsufficient, SCIP_INTERVAL newinterval, SCIP_INTERVAL oldinterval)
static SCIP_RETCODE detectNlhdlrs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE enforceExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result)
#define TABLE_EARLIEST_STAGE_NONLINEAR
static SCIP_RETCODE getBinaryProductExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *exprmap, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
#define TABLE_DESC_NONLINEAR
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getViolSplitWeight(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var, SCIP_SOL *sol)
static SCIP_RETCODE freeEnfoData(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool freeauxvar)
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE getBilinearBinaryTerms(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_VAR **xs, SCIP_VAR **ys, int *childidxs, int *nterms)
static SCIP_RETCODE storeVarExprs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata)
static SCIP_RETCODE buildVertexPolyhedralSeparationLP(SCIP *scip, int nvars, SCIP_LPI **lp)
static SCIP_RETCODE propConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool force, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
static SCIP_RETCODE forwardPropExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *rootexpr, SCIP_Bool tightenauxvars, SCIP_Bool *infeasible, int *ntightenings)
static SCIP_RETCODE consEnfo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_Bool isSingleLockedCand(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Bool branchAuxNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE presolveImplint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nchgvartypes, SCIP_Bool *infeasible)
#define TABLE_NAME_NONLINEAR
#define TABLE_NAME_NLHDLR
static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
static SCIP_RETCODE deinitSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
#define VERTEXPOLY_MAXPERTURBATION
static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE catchVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
#define DIALOG_ISSUBMENU
static SCIP_RETCODE addTightEstimatorCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol)
static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
#define VERTEXPOLY_USEDUALSIMPLEX
#define CONSHDLR_PROPFREQ
static SCIP_RETCODE initSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *infeasible)
static SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(SCIP *scip, SCIP_Real left, SCIP_Real right, SCIP_Real funleft, SCIP_Real funright, SCIP_Bool *success, SCIP_Real *facetcoef, SCIP_Real *facetconstant)
#define POWEROFTWO(x)
#define CONSHDLR_PRESOLTIMING
static SCIP_RETCODE collectBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, BRANCHCAND *cands, int *ncands)
static SCIP_RETCODE branching(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_RESULT *result)
static SCIP_RETCODE bilinearTermsInsertAll(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define VERTEXPOLY_ADJUSTFACETFACTOR
#define TABLE_POSITION_NONLINEAR
static SCIP_RETCODE initSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE removeSingleLockedVars(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRITER *it, SCIP_HASHMAP *exprcands)
#define CONSHDLR_EAGERFREQ
static void findUnlockedLinearVar(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
static SCIP_RETCODE propExprDomains(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getConsAbsViolation(SCIP_CONS *cons)
static SCIP_RETCODE bilinearTermsFree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
#define CONSHDLR_ENFOPRIORITY
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE createCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool copyexpr, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE bilinearTermsInsertEntry(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, int nlockspos, int nlocksneg, int *idx, SCIP_Bool existing)
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
static SCIP_Real getExprAbsOrigViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
#define CONSHDLR_NAME
static SCIP_RETCODE presolveMergeConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
#define TABLE_POSITION_NLHDLR
static SCIP_RETCODE canonicalizeConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_PRESOLTIMING presoltiming, SCIP_Bool *infeasible, int *ndelconss, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
#define CONSHDLR_DELAYPROP
#define BILIN_MAXNAUXEXPRS
constraint handler for nonlinear constraints specified by algebraic expressions
Constraint handler for variable bound constraints .
methods for debugging
#define SCIPdebugAddSolVal(scip, var, val)
Definition debug.h:298
#define SCIP_MAXSTRLEN
Definition def.h:302
#define EPSROUND(x, eps)
Definition def.h:221
#define SCIP_REAL_MAX
Definition def.h:187
#define SCIP_INVALID
Definition def.h:206
#define SCIP_INTERVAL_INFINITY
Definition def.h:208
#define EPSFRAC(x, eps)
Definition def.h:222
#define TRUE
Definition def.h:95
#define FALSE
Definition def.h:96
#define SCIPABORT()
Definition def.h:360
#define REALABS(x)
Definition def.h:210
#define SCIP_CALL(x)
Definition def.h:388
default user interface dialog
power and signed power expression handlers
sum expression handler
constant value expression handler
variable expression handler
SCIP_Real SCIPevalBilinAuxExprNonlinear(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_SOL *sol)
SCIP_RETCODE SCIPcheckQuadraticNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *isquadratic)
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
#define SCIP_DECL_NONLINCONSUPGD(x)
SCIP_RETCODE SCIPmarkExprPropagateNonlinear(SCIP *scip, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *z, SCIP_Real exponent, SCIP_Real xoffset, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPgetExprViolScoreNonlinear(SCIP_EXPR *expr)
unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
void SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
void SCIPgetExprEnfoDataNonlinear(SCIP_EXPR *expr, int idx, SCIP_NLHDLR **nlhdlr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_NLHDLR_METHOD *nlhdlrparticipation, SCIP_Bool *sepabelowusesactivity, SCIP_Bool *sepaaboveusesactivity, SCIP_Real *auxvalue)
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *coefs, SCIP_Real *offsets, SCIP_Real constant, SCIP_VAR *rhsvar, SCIP_Real rhscoeff, SCIP_Real rhsoffset)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsBasicVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, SCIP_Real coefx, SCIP_Real coefy, SCIP_Real coefaux, SCIP_Real cst, SCIP_Bool overestimate)
void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_RETCODE SCIPgetAbsViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPassumeConvexNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
int SCIPgetBilinTermIdxNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
void SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, int nlockspos, int nlocksneg)
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
SCIP_RETCODE SCIPprocessRowprepNonlinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_VAR *auxvar, SCIP_Real auxvalue, SCIP_Bool allowweakcuts, SCIP_Bool branchscoresuccess, SCIP_Bool inenforcement, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Real SCIPgetExprPartialDiffNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPcollectBilinTermsNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_DECL_VERTEXPOLYFUN((*function)), void *fundata, SCIP_Real *xstar, SCIP_Real *box, int nallvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
#define SCIP_DECL_VERTEXPOLYFUN(f)
SCIP_RETCODE SCIPgetRelViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition cons_and.c:5107
unsigned int SCIPgetExprNPropUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPchgExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr)
SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
void SCIPaddExprViolScoreNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore)
void SCIPincrementCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_Bool boundrelax)
SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Real SCIPevalExprQuadraticAuxNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol)
#define SCIP_MAXVERTEXPOLYDIM
SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_var.c:390
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition expr_sum.c:1116
SCIP_RETCODE SCIPcreateExprSignpower(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_pow.c:3198
SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_sum.c:1079
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_value.c:270
SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_pow.c:3174
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNObjVars(SCIP *scip)
Definition scip_prob.c:2220
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1668
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2082
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2172
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:2770
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:2843
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:1947
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2037
int SCIPgetNTotalVars(SCIP *scip)
Definition scip_prob.c:2569
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3058
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3231
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3211
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3106
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition misc.c:3483
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3024
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3373
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3142
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3389
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2296
#define SCIPhashTwo(a, b)
Definition pub_misc.h:519
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2246
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2558
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2497
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition lpi_clp.cpp:1167
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition lpi_clp.cpp:3919
SCIP_RETCODE SCIPlpiChgObjsen(SCIP_LPI *lpi, SCIP_OBJSEN objsen)
Definition lpi_clp.cpp:1220
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition lpi_clp.cpp:3833
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition lpi_clp.cpp:643
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition lpi_clp.cpp:2609
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition lpi_clp.cpp:3692
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition lpi_clp.cpp:2788
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition lpi_clp.cpp:1880
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition lpi_clp.cpp:1805
SCIP_RETCODE SCIPlpiLoadColLP(SCIP_LPI *lpi, SCIP_OBJSEN objsen, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition lpi_clp.cpp:677
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition lpi_clp.cpp:531
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition lpi_clp.cpp:1240
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition lpi_clp.cpp:1435
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition lpi_clp.cpp:1417
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3474
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
SCIP_RETCODE SCIPsolveLinearEquationsIpopt(int N, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
#define SCIPisFinite(x)
Definition pub_misc.h:1901
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:167
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition scip_param.c:326
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10307
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition misc.c:10294
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition lp.c:17151
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition lp.c:17140
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition lp.c:17115
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4210
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4929
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4595
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4180
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:886
SCIP_RETCODE SCIPincludeConshdlr(SCIP *scip, const char *name, const char *desc, int sepapriority, int enfopriority, int chckpriority, int sepafreq, int propfreq, int eagerfreq, int maxprerounds, SCIP_Bool delaysepa, SCIP_Bool delayprop, SCIP_Bool needscons, SCIP_PROPTIMING proptiming, SCIP_PRESOLTIMING presoltiming, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSFREE((*consfree)), SCIP_DECL_CONSINIT((*consinit)), SCIP_DECL_CONSEXIT((*consexit)), SCIP_DECL_CONSINITPRE((*consinitpre)), SCIP_DECL_CONSEXITPRE((*consexitpre)), SCIP_DECL_CONSINITSOL((*consinitsol)), SCIP_DECL_CONSEXITSOL((*consexitsol)), SCIP_DECL_CONSDELETE((*consdelete)), SCIP_DECL_CONSTRANS((*constrans)), SCIP_DECL_CONSINITLP((*consinitlp)), SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFORELAX((*consenforelax)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSPROP((*consprop)), SCIP_DECL_CONSPRESOL((*conspresol)), SCIP_DECL_CONSRESPROP((*consresprop)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_DECL_CONSACTIVE((*consactive)), SCIP_DECL_CONSDEACTIVE((*consdeactive)), SCIP_DECL_CONSENABLE((*consenable)), SCIP_DECL_CONSDISABLE((*consdisable)), SCIP_DECL_CONSDELVARS((*consdelvars)), SCIP_DECL_CONSPRINT((*consprint)), SCIP_DECL_CONSCOPY((*conscopy)), SCIP_DECL_CONSPARSE((*consparse)), SCIP_DECL_CONSGETVARS((*consgetvars)), SCIP_DECL_CONSGETNVARS((*consgetnvars)), SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:82
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4200
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4552
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8118
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8347
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8108
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition cons.c:8206
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8257
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2482
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition cons.c:8387
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8287
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8217
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8277
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8149
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:943
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8307
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8327
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition cons.c:8185
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8088
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition cons.c:8195
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8337
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1119
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8267
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8357
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:361
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:94
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition scip_cut.c:207
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:250
SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
Definition dialog.c:436
SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
Definition dialog.c:995
SCIP_RETCODE SCIPdialoghdlrAddHistory(SCIP_DIALOGHDLR *dialoghdlr, SCIP_DIALOG *dialog, const char *command, SCIP_Bool escapecommand)
Definition dialog.c:726
SCIP_RETCODE SCIPincludeDialog(SCIP *scip, SCIP_DIALOG **dialog, SCIP_DECL_DIALOGCOPY((*dialogcopy)), SCIP_DECL_DIALOGEXEC((*dialogexec)), SCIP_DECL_DIALOGDESC((*dialogdesc)), SCIP_DECL_DIALOGFREE((*dialogfree)), const char *name, const char *desc, SCIP_Bool issubmenu, SCIP_DIALOGDATA *dialogdata)
Definition scip_dialog.c:59
SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
Definition dialog.c:1028
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPclearPtrarray(SCIP *scip, SCIP_PTRARRAY *ptrarray)
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:104
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition scip_event.c:234
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1030
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition event.c:1337
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:354
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:400
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1053
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:286
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:320
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:532
SCIP_Bool SCIPexprhdlrHasMonotonicity(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:652
SCIP_Bool SCIPexprhdlrHasReverseProp(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:662
void SCIPexprSetActivity(SCIP_EXPR *expr, SCIP_INTERVAL activity, SCIP_Longint activitytag)
Definition expr.c:3983
SCIP_RETCODE SCIPcreateExprQuadratic(SCIP *scip, SCIP_EXPR **expr, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1023
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1625
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3801
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition expr.c:4145
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1989
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition expr_pow.c:3351
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1454
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1657
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition expriter.c:968
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition scip_expr.c:1641
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:929
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition expr.c:3862
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition expr.c:3901
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1443
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition scip_expr.c:2032
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition expr.c:3888
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition expr.c:4020
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition expr.c:4181
void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
Definition expr.c:4060
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition scip_expr.c:1238
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1166
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition expriter.c:755
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1432
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:2354
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1407
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition expriter.c:682
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition expriter.c:663
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1421
SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1370
SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition expriter.c:629
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition scip_expr.c:2296
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition expr.c:4030
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition scip_expr.c:1476
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition expr_value.c:294
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition expriter.c:805
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1465
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition expr.c:3875
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition expr.c:3973
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition scip_expr.c:1794
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition expriter.c:857
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition scip_expr.c:2336
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition expr.c:3929
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3811
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1181
SCIP_RETCODE SCIPcopyExpr(SCIP *sourcescip, SCIP *targetscip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *valid)
Definition scip_expr.c:1308
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition expr_var.c:416
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition expriter.c:837
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition expr.c:3957
void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
Definition expr.c:4105
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:706
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition scip_expr.c:2310
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:695
SCIP_RETCODE SCIPduplicateExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_MAPEXPR((*mapexpr)), void *mapexprdata, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1271
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition scip_expr.c:1399
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition expriter.c:500
int SCIPexprGetNUses(SCIP_EXPR *expr)
Definition expr.c:3791
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition scip_expr.c:2070
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition expr.c:3944
SCIP_RETCODE SCIPsimplifyExpr(SCIP *scip, SCIP_EXPR *rootexpr, SCIP_EXPR **simplified, SCIP_Bool *changed, SCIP_Bool *infeasible, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1763
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1707
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition expr.c:3824
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:720
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition scip_heur.c:258
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition heur.c:1450
void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:168
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition scip_lp.c:247
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition scip_lp.c:438
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition scip_lp.c:428
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition scip_mem.h:91
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition scip_mem.h:107
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:391
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:363
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
void SCIPenableNLP(SCIP *scip)
Definition scip_nlp.c:95
SCIP_RETCODE SCIPsetNlRowExpr(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPR *expr)
Definition scip_nlp.c:1203
SCIP_RETCODE SCIPaddLinearCoefToNlRow(SCIP *scip, SCIP_NLROW *nlrow, SCIP_VAR *var, SCIP_Real val)
Definition scip_nlp.c:1116
void SCIPnlrowSetCurvature(SCIP_NLROW *nlrow, SCIP_EXPRCURV curvature)
Definition nlp.c:1842
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1025
SCIP_RETCODE SCIPchgNlRowConstant(SCIP *scip, SCIP_NLROW *nlrow, SCIP_Real constant)
Definition scip_nlp.c:1093
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:921
const char * SCIPnlhdlrGetDesc(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:160
SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:210
int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:170
SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:190
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:150
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:250
SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
SCIP_Bool SCIPnlhdlrHasInitSepa(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:226
int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:180
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:7444
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
Definition lp.c:17456
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2212
const char * SCIProwGetName(SCIP_ROW *row)
Definition lp.c:17351
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1562
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1868
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17312
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition scip_sepa.c:339
SCIP_SOLORIGIN SCIPsolGetOrigin(SCIP_SOL *sol)
Definition sol.c:2545
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:618
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition sol.c:2638
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:370
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1190
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition scip_sol.c:1318
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1221
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1361
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1491
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition scip_table.c:94
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition scip_table.c:56
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition scip_timing.c:76
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Real SCIPgetHugeValue(SCIP *scip)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:670
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5203
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition scip_var.c:4317
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition var.c:17611
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition scip_var.c:8950
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:17360
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:17966
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:17748
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition var.c:17546
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5320
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:17406
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:17910
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:17580
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:17241
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1248
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition scip_var.c:4645
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition scip_var.c:8814
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition scip_var.c:4613
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:17432
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition scip_var.c:8176
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18252
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:17956
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18263
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:17900
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:8715
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:11931
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition scip_var.c:194
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:3295
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition scip_var.c:1439
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1214
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition misc.c:967
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition misc.c:943
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition misc.c:1029
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition misc.c:1184
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition misc.c:1080
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10041
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition misc.c:10019
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
SCIP_Bool SCIProwprepIsLocal(SCIP_ROWPREP *rowprep)
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition misc.c:5989
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortDownIntPtr(int *intarray, void **ptrarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10788
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10777
return SCIP_OKAY
SCIPfreeSol(scip, &heurdata->sol))
SCIPfreeRandom(scip, &heurdata->randnumgen)
int c
SCIP_Bool cutoff
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
static SCIP_SOL * sol
int r
SCIP_Real obj
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
SCIP_Real alpha
NLP local search primal heuristic using sub-SCIPs.
primal heuristic that tries a given solution
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition implics.c:1141
static volatile int nterms
Definition interrupt.c:47
static const char * paramname[]
Definition lpi_msk.c:5096
#define NULL
Definition lpi_spx1.cpp:161
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:132
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition nlhdlr.c:363
SCIP_RETCODE SCIPnlhdlrCreate(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
Definition nlhdlr.c:315
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition nlhdlr.c:698
private functions of nonlinear handlers of nonlinear constraints
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition nlhdlr.h:128
#define SCIPnlhdlrResetNDetectionslast(nlhdlr)
Definition nlhdlr.h:126
#define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
Definition nlhdlr.h:127
nonlinear handlers for convex and concave expressions, respectively
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
Ipopt NLP interface.
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebugPrintCons(x, y, z)
SCIP_Real dual
SCIP_Real vartype
SCIP_Real pscost
SCIP_Real domain
SCIP_Real weighted
SCIP_Real auxviol
SCIP_EXPR * expr
SCIP_DECL_NONLINCONSUPGD((*consupgd))
SCIP_Bool active
SCIP_NLHDLR_METHOD nlhdlrparticipation
SCIP_NLHDLR * nlhdlr
SCIP_Bool sepaaboveusesactivity
SCIP_Bool sepabelowusesactivity
SCIP_Bool issepainit
SCIP_Real auxvalue
SCIP_NLHDLREXPRDATA * nlhdlrexprdata
SCIP_Real sup
SCIP_Real inf
#define MAX(x, y)
Definition tclique_def.h:92
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:362
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:155
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:228
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:135
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:865
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:200
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:767
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:287
#define SCIP_DECL_CONSDISABLE(x)
Definition type_cons.h:734
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:387
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition type_cons.h:918
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:504
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:883
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:610
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:689
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:430
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:843
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:238
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:704
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:559
#define SCIP_DECL_CONSENABLE(x)
Definition type_cons.h:719
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:258
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:179
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:674
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:808
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:125
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:473
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:107
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:215
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:115
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:319
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:751
#define SCIP_DECL_DIALOGEXEC(x)
Definition type_dialog.h:96
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition type_event.h:125
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:173
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:253
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition type_event.h:105
#define SCIP_EVENTTYPE_FORMAT
Definition type_event.h:152
#define SCIP_EVENTTYPE_BOUNDRELAXED
Definition type_event.h:124
#define SCIP_EVENTTYPE_SOLFOUND
Definition type_event.h:144
uint64_t SCIP_EVENTTYPE
Definition type_event.h:151
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition type_event.h:123
#define SCIP_DECL_EXPR_OWNERCREATE(x)
Definition type_expr.h:140
SCIP_EXPRCURV
Definition type_expr.h:58
@ SCIP_EXPRCURV_CONVEX
Definition type_expr.h:60
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:62
@ SCIP_EXPRCURV_UNKNOWN
Definition type_expr.h:59
@ SCIP_EXPRCURV_CONCAVE
Definition type_expr.h:61
#define SCIP_EXPRITER_VISITINGCHILD
Definition type_expr.h:677
#define SCIP_DECL_EXPR_OWNERPRINT(x)
Definition type_expr.h:106
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition type_expr.h:77
SCIP_MONOTONE
Definition type_expr.h:67
@ SCIP_MONOTONE_CONST
Definition type_expr.h:71
@ SCIP_MONOTONE_UNKNOWN
Definition type_expr.h:68
@ SCIP_MONOTONE_INC
Definition type_expr.h:69
@ SCIP_MONOTONE_DEC
Definition type_expr.h:70
#define SCIP_DECL_EXPR_INTEVALVAR(x)
Definition type_expr.h:160
@ SCIP_EXPRITER_BFS
Definition type_expr.h:699
@ SCIP_EXPRITER_DFS
Definition type_expr.h:700
@ SCIP_EXPRITER_RTOPOLOGIC
Definition type_expr.h:698
#define SCIP_DECL_EXPR_MAPEXPR(x)
Definition type_expr.h:179
#define SCIP_DECL_EXPR_OWNERFREE(x)
Definition type_expr.h:92
#define SCIP_EXPRITER_LEAVEEXPR
Definition type_expr.h:679
#define SCIP_DECL_EXPR_OWNEREVALACTIVITY(x)
Definition type_expr.h:122
#define SCIP_EXPRITER_ENTEREXPR
Definition type_expr.h:676
@ SCIP_BRANCHDIR_DOWNWARDS
@ SCIP_BRANCHDIR_UPWARDS
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:57
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:56
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:59
@ SCIP_SIDETYPE_RIGHT
Definition type_lp.h:65
@ SCIP_SIDETYPE_LEFT
Definition type_lp.h:64
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:43
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition type_lp.h:45
@ SCIP_LPPAR_LPINFO
Definition type_lpi.h:55
@ SCIP_LPPAR_DUALFEASTOL
Definition type_lpi.h:57
@ SCIP_LPPAR_FEASTOL
Definition type_lpi.h:56
@ SCIP_LPPAR_LPITLIM
Definition type_lpi.h:60
@ SCIP_LPPAR_OBJLIM
Definition type_lpi.h:59
@ SCIP_OBJSEN_MAXIMIZE
Definition type_lpi.h:42
@ SCIP_OBJSEN_MINIMIZE
Definition type_lpi.h:43
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:188
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:194
#define SCIP_DECL_SORTINDCOMP(x)
Definition type_misc.h:180
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:191
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:197
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition type_nlhdlr.h:52
#define SCIP_DECL_NLHDLREVALAUX(x)
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition type_nlhdlr.h:53
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition type_nlhdlr.h:54
unsigned int SCIP_NLHDLR_METHOD
Definition type_nlhdlr.h:57
#define SCIP_DECL_NLHDLRDETECT(x)
#define SCIP_NLHDLR_METHOD_NONE
Definition type_nlhdlr.h:50
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
#define SCIP_NLHDLR_METHOD_ALL
Definition type_nlhdlr.h:55
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition type_nlhdlr.h:51
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_BRANCHED
Definition type_result.h:54
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SOLVELP
Definition type_result.h:55
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_LPERROR
@ SCIP_READERROR
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
@ SCIP_STAGE_PROBLEM
Definition type_set.h:45
@ SCIP_STAGE_INITPRESOLVE
Definition type_set.h:48
@ SCIP_STAGE_SOLVED
Definition type_set.h:54
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
@ SCIP_STAGE_TRANSFORMED
Definition type_set.h:47
@ SCIP_STAGE_INITSOLVE
Definition type_set.h:52
@ SCIP_STAGE_EXITPRESOLVE
Definition type_set.h:50
@ SCIP_STAGE_EXITSOLVE
Definition type_set.h:55
@ SCIP_STAGE_INIT
Definition type_set.h:44
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_SOLORIGIN_LPSOL
Definition type_sol.h:44
@ SCIP_STATUS_OPTIMAL
Definition type_stat.h:61
@ SCIP_STATUS_UNBOUNDED
Definition type_stat.h:63
@ SCIP_STATUS_INFORUNBD
Definition type_stat.h:64
@ SCIP_STATUS_INFEASIBLE
Definition type_stat.h:62
#define SCIP_DECL_TABLEOUTPUT(x)
Definition type_table.h:122
#define SCIP_PRESOLTIMING_ALWAYS
Definition type_timing.h:58
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition type_timing.h:61
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:63
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_IMPLINT
Definition type_var.h:64
@ SCIP_VARTYPE_BINARY
Definition type_var.h:62
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:51
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:97
enum SCIP_Vartype SCIP_VARTYPE
Definition type_var.h:73