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-2024 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_varidx.h"
60#include "scip/expr_abs.h"
61#include "scip/expr_sum.h"
62#include "scip/expr_value.h"
63#include "scip/expr_pow.h"
64#include "scip/expr_trig.h"
65#include "scip/nlhdlr_convex.h"
66#include "scip/cons_linear.h"
67#include "scip/cons_varbound.h"
68#include "scip/cons_and.h"
70#include "scip/heur_subnlp.h"
71#include "scip/heur_trysol.h"
72#include "scip/lapack_calls.h"
73#include "scip/debug.h"
74#include "scip/dialog_default.h"
75#include "scip/scip_expr.h"
76#include "scip/symmetry_graph.h"
77#include "scip/prop_symmetry.h"
79#include "scip/pub_misc_sort.h"
80
81
82/* fundamental constraint handler properties */
83#define CONSHDLR_NAME "nonlinear"
84#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
85#define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
86#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
89#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
90
91/* optional constraint handler properties */
92#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
93#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
94#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
95
96#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
97#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
98#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
99
100#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
101#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
102
103/* properties of the nonlinear constraint handler statistics table */
104#define TABLE_NAME_NONLINEAR "cons_nonlinear"
105#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
106#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
107#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
108
109/* properties of the nonlinear handler statistics table */
110#define TABLE_NAME_NLHDLR "nlhdlr"
111#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
112#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
113#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
114
115#define DIALOG_NAME "nlhdlrs"
116#define DIALOG_DESC "display nonlinear handlers"
117#define DIALOG_ISSUBMENU FALSE
118
119#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
120#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
121#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
122#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
123
124#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
125
126#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
127
128/** translate from one value of infinity to another
129 *
130 * if val is &ge; infty1, then give infty2, else give val
131 */
132#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
133
134/** translates x to 2^x for non-negative integer x */
135#define POWEROFTWO(x) (0x1u << (x))
136
137#ifdef ENFO_LOGGING
138#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
140#else
141#define ENFOLOG(x)
142#endif
143
144/*
145 * Data structures
146 */
147
148/** enforcement data of an expression */
149typedef struct
150{
151 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
152 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
153 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
154 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
155 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
156 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
157 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
158} EXPRENFO;
159
160/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
161struct SCIP_Expr_OwnerData
162{
163 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
164
165 /* locks and monotonicity */
166 int nlockspos; /**< positive locks counter */
167 int nlocksneg; /**< negative locks counter */
168 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
169 int monotonicitysize; /**< length of monotonicity array */
170
171 /* propagation (in addition to activity that is stored in expr) */
172 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
173 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
174 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
175
176 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
177 EXPRENFO** enfos; /**< enforcements */
178 int nenfos; /**< number of enforcements, or -1 if not initialized */
179 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
180 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
181 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
182 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
183 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
184
185 /* branching */
186 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
187 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
188 int nviolscores; /**< number of violation scores stored for this expression */
189 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
190
191 /* additional data for variable expressions (TODO move into sub-struct?) */
192 SCIP_CONS** conss; /**< constraints in which this variable appears */
193 int nconss; /**< current number of constraints in conss */
194 int consssize; /**< length of conss array */
195 SCIP_Bool consssorted; /**< is the array of constraints sorted */
196
197 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
198};
199
200/** constraint data for nonlinear constraints */
201struct SCIP_ConsData
202{
203 /* data that defines the constraint: expression and sides */
204 SCIP_EXPR* expr; /**< expression that represents this constraint */
205 SCIP_Real lhs; /**< left-hand side */
206 SCIP_Real rhs; /**< right-hand side */
207
208 /* variables */
209 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
210 int nvarexprs; /**< total number of variable expressions */
211 SCIP_Bool catchedevents; /**< do we catch events on variables? */
212
213 /* constraint violation */
214 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
215 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
216 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
217 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
218
219 /* status flags */
220 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
221 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
222
223 /* locks */
224 int nlockspos; /**< number of positive locks */
225 int nlocksneg; /**< number of negative locks */
226
227 /* repair infeasible solutions */
228 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
229 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
230 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
231 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
232
233 /* miscellaneous */
234 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
235 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
236 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
237};
238
239/** constraint upgrade method */
240typedef struct
241{
242 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
243 int priority; /**< priority of upgrading method */
244 SCIP_Bool active; /**< is upgrading enabled */
246
247/** constraint handler data */
248struct SCIP_ConshdlrData
249{
250 /* nonlinear handler */
251 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
252 int nnlhdlrs; /**< number of nonlinear handlers */
253 int nlhdlrssize; /**< size of nlhdlrs array */
254 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
255 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
256 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
257
258 /* constraint upgrades */
259 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
260 int consupgradessize; /**< size of consupgrades array */
261 int nconsupgrades; /**< number of constraint upgrade methods */
262
263 /* other plugins */
264 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
265 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
266 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
267
268 /* tags and counters */
269 int auxvarid; /**< unique id for the next auxiliary variable */
270 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
271 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
272 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
273 unsigned int enforound; /**< total number of enforcement calls, including current one */
274 int lastconsindex; /**< last used consindex, plus one */
275
276 /* activity intervals and domain propagation */
277 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
278 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
279 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
280 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
281 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
282
283 /* parameters */
284 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
285 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
286 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
287 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
288 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
289 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
290 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
291 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
292 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
293 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
294 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
295 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
296 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
297 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
298 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
299 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
300 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
301 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
302 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
303 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
304 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 */
305 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
306 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) */
307 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
308 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
309 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
310 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
311 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
312 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
313 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
314 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
315 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
316 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
317 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
318 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
319 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) */
320 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
321
322 /* statistics */
323 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
324 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
325 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 */
326 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
327 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
328 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
329 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
330 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
331
332 /* facets of envelops of vertex-polyhedral functions */
333 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
334 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
335
336 /* hashing of bilinear terms */
337 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
338 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
339 int nbilinterms; /**< total number of bilinear terms */
340 int bilintermssize; /**< size of bilinterms array */
341 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
342
343 /* branching */
344 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
345 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
346
347 /* misc */
348 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
349 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
350 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
351};
352
353/** branching candidate with various scores */
354typedef struct
355{
356 SCIP_EXPR* expr; /**< expression that holds branching candidate */
357 SCIP_Real auxviol; /**< aux-violation score of candidate */
358 SCIP_Real domain; /**< domain score of candidate */
359 SCIP_Real dual; /**< dual score of candidate */
360 SCIP_Real pscost; /**< pseudo-cost score of candidate */
361 SCIP_Real vartype; /**< variable type score of candidate */
362 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
363} BRANCHCAND;
364
365/*
366 * Local methods
367 */
368
369/* forward declaration */
370static
372 SCIP* scip, /**< SCIP data structure */
373 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
374 SCIP_EXPR* rootexpr, /**< expression */
375 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
376 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
377 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
378 );
379
380/** frees auxiliary variables of expression, if any */
381static
383 SCIP* scip, /**< SCIP data structure */
384 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
385 )
386{
388
389 assert(scip != NULL);
390 assert(expr != NULL);
391
393 assert(mydata != NULL);
394
395 if( mydata->auxvar == NULL )
396 return SCIP_OKAY;
397
398 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
399
400 /* remove variable locks
401 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
402 */
403 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
404
405 /* release auxiliary variable */
406 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
407 assert(mydata->auxvar == NULL);
408
409 return SCIP_OKAY;
410}
411
412/** frees data used for enforcement of expression, that is, nonlinear handlers
413 *
414 * can also clear indicators whether expr needs enforcement methods, that is,
415 * free an associated auxiliary variable and reset the nactivityuses counts
416 */
417static
419 SCIP* scip, /**< SCIP data structure */
420 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
421 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
422 )
423{
425 int e;
426
428 assert(mydata != NULL);
429
430 if( freeauxvar )
431 {
432 /* free auxiliary variable */
433 SCIP_CALL( freeAuxVar(scip, expr) );
434 assert(mydata->auxvar == NULL);
435
436 /* reset count on activity and auxvar usage */
437 mydata->nactivityusesprop = 0;
438 mydata->nactivityusessepa = 0;
439 mydata->nauxvaruses = 0;
440 }
441
442 /* free data stored by nonlinear handlers */
443 for( e = 0; e < mydata->nenfos; ++e )
444 {
445 SCIP_NLHDLR* nlhdlr;
446
447 assert(mydata->enfos[e] != NULL);
448
449 nlhdlr = mydata->enfos[e]->nlhdlr;
450 assert(nlhdlr != NULL);
451
452 if( mydata->enfos[e]->issepainit )
453 {
454 /* call the separation deinitialization callback of the nonlinear handler */
455 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
456 mydata->enfos[e]->issepainit = FALSE;
457 }
458
459 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
460 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
461 {
462 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
463 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
464 }
465
466 /* free enfo data */
467 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
468 }
469
470 /* free array with enfo data */
472
473 /* we need to look at this expression in detect again */
474 mydata->nenfos = -1;
475
476 return SCIP_OKAY;
477}
478
479/** callback that frees data that this conshdlr stored in an expression */
480static
482{
483 assert(scip != NULL);
484 assert(expr != NULL);
485 assert(ownerdata != NULL);
486 assert(*ownerdata != NULL);
487
488 /* expression should not be locked anymore */
489 assert((*ownerdata)->nlockspos == 0);
490 assert((*ownerdata)->nlocksneg == 0);
491
492 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
493
494 /* expression should not be enforced anymore */
495 assert((*ownerdata)->nenfos <= 0);
496 assert((*ownerdata)->auxvar == NULL);
497
498 if( SCIPisExprVar(scip, expr) )
499 {
500 SCIP_CONSHDLRDATA* conshdlrdata;
501 SCIP_VAR* var;
502
503 /* there should be no constraints left that still use this variable */
504 assert((*ownerdata)->nconss == 0);
505 /* thus, there should also be no variable event catched (via this exprhdlr) */
506 assert((*ownerdata)->filterpos == -1);
507
508 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
509
510 /* update var2expr hashmap in conshdlrdata */
511 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
512 assert(conshdlrdata != NULL);
513
514 var = SCIPgetVarExprVar(expr);
515 assert(var != NULL);
516
517 /* remove var -> expr map from hashmap if present
518 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
519 * if variable-expression stored for var is different, then also do nothing)
520 */
521 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
522 {
523 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
524 }
525 }
526
527 SCIPfreeBlockMemory(scip, ownerdata);
528
529 return SCIP_OKAY;
530}
531
532static
534{ /*lint --e{715}*/
535 assert(ownerdata != NULL);
536
537 /* print nl handlers associated to expr */
538 if( ownerdata->nenfos > 0 )
539 {
540 int i;
541 SCIPinfoMessage(scip, file, " {");
542
543 for( i = 0; i < ownerdata->nenfos; ++i )
544 {
545 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
546 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
547 SCIPinfoMessage(scip, file, "a");
548 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
549 SCIPinfoMessage(scip, file, "u");
550 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
551 SCIPinfoMessage(scip, file, "o");
552 if( i < ownerdata->nenfos-1 )
553 SCIPinfoMessage(scip, file, ", ");
554 }
555
556 SCIPinfoMessage(scip, file, "}");
557 }
558
559 /* print aux var associated to expr */
560 if( ownerdata->auxvar != NULL )
561 {
562 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
563 }
564 SCIPinfoMessage(scip, file, "\n");
565
566 return SCIP_OKAY;
567}
568
569/** possibly reevaluates and then returns the activity of the expression
570 *
571 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
572 */
573static
575{
576 SCIP_CONSHDLRDATA* conshdlrdata;
577
578 assert(scip != NULL);
579 assert(expr != NULL);
580 assert(ownerdata != NULL);
581
582 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
583 assert(conshdlrdata != NULL);
584
585 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
586 {
587 /* update activity of expression */
588 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
589
590 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
591 }
592
593 return SCIP_OKAY;
594}
595
596/** callback that creates data that this conshdlr wants to store in an expression */
597static
599{
600 assert(scip != NULL);
601 assert(expr != NULL);
602 assert(ownerdata != NULL);
603
605 (*ownerdata)->nenfos = -1;
606 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
607
608 if( SCIPisExprVar(scip, expr) )
609 {
610 SCIP_CONSHDLRDATA* conshdlrdata;
611 SCIP_VAR* var;
612
613 (*ownerdata)->filterpos = -1;
614
615 /* add to var2expr hashmap if not having expr for var yet */
616
617 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
618 assert(conshdlrdata != NULL);
619
620 var = SCIPgetVarExprVar(expr);
621
622 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
623 {
624 /* store the variable expression in the hashmap */
625 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
626 }
627 else
628 {
629 /* if expr was just created, then it shouldn't already be stored as image of var */
630 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
631 }
632 }
633 else
634 {
635 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
636 (*ownerdata)->filterpos = -2;
637 }
638
642
643 return SCIP_OKAY;
644}
645
646/** creates a variable expression or retrieves from hashmap in conshdlr data */
647static
649 SCIP* scip, /**< SCIP data structure */
650 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
651 SCIP_EXPR** expr, /**< pointer where to store expression */
652 SCIP_VAR* var /**< variable to be stored */
653 )
654{
655 assert(conshdlr != NULL);
656 assert(expr != NULL);
657 assert(var != NULL);
658
659 /* get variable expression representing the given variable if there is one already */
660 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
661
662 if( *expr == NULL )
663 {
664 /* create a new variable expression; this also captures the expression */
665 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
666 assert(*expr != NULL);
667 /* exprownerCreate should have added var->expr to var2expr */
668 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
669 }
670 else
671 {
672 /* only capture already existing expr to get a consistent uses-count */
673 SCIPcaptureExpr(*expr);
674 }
675
676 return SCIP_OKAY;
677}
678
679/* map var exprs to var-expr from var2expr hashmap */
680static
682{ /*lint --e{715}*/
684
685 assert(sourcescip != NULL);
691
692 /* do not provide map if not variable */
693 if( !SCIPisExprVar(sourcescip, sourceexpr) )
694 return SCIP_OKAY;
695
697
698 return SCIP_OKAY;
699}
700
701/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
702static
704{ /*lint --e{715}*/
706 SCIP_VAR* var;
707
708 assert(sourcescip != NULL);
714
715 /* do not provide map if not variable */
716 if( !SCIPisExprVar(sourcescip, sourceexpr) )
717 return SCIP_OKAY;
718
720 assert(var != NULL);
721
722 /* transform variable */
723 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
724 assert(var != NULL);
725
727
728 return SCIP_OKAY;
729}
730
731/** stores all variable expressions into a given constraint */
732static
734 SCIP* scip, /**< SCIP data structure */
735 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
736 SCIP_CONSDATA* consdata /**< constraint data */
737 )
738{
739 SCIP_CONSHDLRDATA* conshdlrdata;
740 int varexprssize;
741 int i;
742
743 assert(consdata != NULL);
744
745 /* skip if we have stored the variable expressions already */
746 if( consdata->varexprs != NULL )
747 return SCIP_OKAY;
748
749 assert(consdata->varexprs == NULL);
750 assert(consdata->nvarexprs == 0);
751
752 /* get an upper bound on number of variable expressions */
753 if( consdata->issimplified )
754 {
755 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
756 * so we cannot have more variable expression than the number of active variables
757 */
759 }
760 else
761 {
762 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
763 }
764
765 /* create array to store all variable expressions */
766 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
767
768 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
769 assert(varexprssize >= consdata->nvarexprs);
770
771 /* shrink array if there are less variables in the expression than in the problem */
772 if( varexprssize > consdata->nvarexprs )
773 {
774 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
775 }
776
777 conshdlrdata = SCIPconshdlrGetData(conshdlr);
778 assert(conshdlrdata != NULL);
779 assert(conshdlrdata->var2expr != NULL);
780
781 /* ensure that for every variable an entry exists in the var2expr hashmap
782 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
783 */
784 for( i = 0; i < consdata->nvarexprs; ++i )
785 {
786 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
787 {
788 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
789 }
790 }
791
792 return SCIP_OKAY;
793}
794
795/** frees all variable expression stored in storeVarExprs() */
796static
798 SCIP* scip, /**< SCIP data structure */
799 SCIP_CONSDATA* consdata /**< constraint data */
800 )
801{
802 int i;
803
804 assert(consdata != NULL);
805
806 /* skip if we have stored the variable expressions already*/
807 if( consdata->varexprs == NULL )
808 return SCIP_OKAY;
809
810 assert(consdata->varexprs != NULL);
811 assert(consdata->nvarexprs >= 0);
812
813 /* release variable expressions */
814 for( i = 0; i < consdata->nvarexprs; ++i )
815 {
816 assert(consdata->varexprs[i] != NULL);
817 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
818 assert(consdata->varexprs[i] == NULL);
819 }
820
821 /* free variable expressions */
822 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
823 consdata->varexprs = NULL;
824 consdata->nvarexprs = 0;
825
826 return SCIP_OKAY;
827}
828
829/** interval evaluation of variables as used in bound tightening
830 *
831 * Returns slightly relaxed local variable bounds of a variable as interval.
832 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
833 */
834static
836{
838 SCIP_CONSHDLRDATA* conshdlrdata;
839 SCIP_Real lb;
840 SCIP_Real ub;
841
842 assert(scip != NULL);
843 assert(var != NULL);
844
845 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
846 assert(conshdlrdata != NULL);
847
848 if( conshdlrdata->globalbounds )
849 {
852 }
853 else
854 {
857 }
858 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
859
860 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
862 {
863 lb = EPSROUND(lb, 0.0); /*lint !e835*/
864 ub = EPSROUND(ub, 0.0); /*lint !e835*/
865 }
866
867 /* integer variables should always have integral bounds in SCIP */
868 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
869 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
870
871 switch( conshdlrdata->varboundrelax )
872 {
873 case 'n' : /* no relaxation */
874 break;
875
876 case 'a' : /* relax by absolute value */
877 {
878 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
880 break;
881
882 if( !SCIPisInfinity(scip, -lb) )
883 {
884 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
885 SCIP_Real bnd = floor(lb);
886 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
887 }
888
889 if( !SCIPisInfinity(scip, ub) )
890 {
891 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
892 SCIP_Real bnd = ceil(ub);
893 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
894 }
895
896 break;
897 }
898
899 case 'b' : /* relax always by absolute value */
900 {
901 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
903 break;
904
905 if( !SCIPisInfinity(scip, -lb) )
906 lb -= conshdlrdata->varboundrelaxamount;
907
908 if( !SCIPisInfinity(scip, ub) )
909 ub += conshdlrdata->varboundrelaxamount;
910
911 break;
912 }
913
914 case 'r' : /* relax by relative value */
915 {
916 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
918 break;
919
920 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
921 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
922 * further, do not relax beyond next integer value
923 */
924 if( !SCIPisInfinity(scip, -lb) )
925 {
926 SCIP_Real bnd = floor(lb);
927 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
928 }
929
930 if( !SCIPisInfinity(scip, ub) )
931 {
932 SCIP_Real bnd = ceil(ub);
933 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
934 }
935
936 break;
937 }
938
939 default :
940 {
941 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
942 SCIPABORT();
943 break;
944 }
945 }
946
947 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
950 assert(lb <= ub);
951
953
954 return interval;
955}
956
957/** compares two nonlinear constraints by its index
958 *
959 * Usable as compare operator in array sort functions.
960 */
961static
972
973/** processes variable fixing or bound change event */
974static
976{ /*lint --e{715}*/
977 SCIP_EVENTTYPE eventtype;
978 SCIP_EXPR* expr;
979 SCIP_EXPR_OWNERDATA* ownerdata;
980 SCIP_Bool boundtightened = FALSE;
981
982 eventtype = SCIPeventGetType(event);
984
985 assert(eventdata != NULL);
986 expr = (SCIP_EXPR*) eventdata;
987 assert(SCIPisExprVar(scip, expr));
988
989 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
993
994 ownerdata = SCIPexprGetOwnerData(expr);
995 assert(ownerdata != NULL);
996 /* we only catch varevents for variables in constraints, so there should be constraints */
997 assert(ownerdata->nconss > 0);
998 assert(ownerdata->conss != NULL);
999
1000 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1002
1003 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1004 * however, if the boundchange is smaller than epsilon, such an event will be omitted
1005 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1006 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1007 * as a boundtightening (and usually it is, I would think)
1008 */
1009 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1011
1012 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1013 * because we will round the bounds and no longer consider relaxing them
1014 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1015 * (mainly to avoid a failing assert, see github issue #70)
1016 * usually, a change to implicit-integer would result in a boundchange on the variable as well, but not if the bound was already almost integral
1017 */
1021
1022 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1023 * - propagation can only find something new if a bound was tightened
1024 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1025 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1026 */
1027 if( boundtightened )
1028 {
1029 SCIP_CONSDATA* consdata;
1030 int c;
1031
1032 for( c = 0; c < ownerdata->nconss; ++c )
1033 {
1034 assert(ownerdata->conss[c] != NULL);
1035 consdata = SCIPconsGetData(ownerdata->conss[c]);
1036
1037 /* if bound tightening, then mark constraints to be propagated again
1038 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1039 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1040 * the locks don't help since they are not available separately for each constraint
1041 */
1042 consdata->ispropagated = FALSE;
1043 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1044
1045 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1047 {
1048 consdata->issimplified = FALSE;
1049 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1050 }
1051 }
1052 }
1053
1054 /* update curboundstag, lastboundrelax, and expr activity */
1055 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1056 {
1057 SCIP_CONSHDLRDATA* conshdlrdata;
1058 SCIP_INTERVAL activity;
1059
1060 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1061 assert(conshdlrdata != NULL);
1062
1063 /* increase tag on bounds */
1064 ++conshdlrdata->curboundstag;
1065 assert(conshdlrdata->curboundstag > 0);
1066
1067 /* remember also if we relaxed bounds now */
1068 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1069 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1070
1071 /* update the activity of the var-expr here immediately
1072 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1073 */
1074 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1075 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1076#ifdef DEBUG_PROP
1077 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1078#endif
1079 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1080 }
1081
1082 return SCIP_OKAY;
1083}
1084
1085/** registers event handler to catch variable events on variable
1086 *
1087 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1088 * When an event occurs, all stored constraints are notified.
1089 */
1090static
1092 SCIP* scip, /**< SCIP data structure */
1093 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1094 SCIP_EXPR* expr, /**< variable expression */
1095 SCIP_CONS* cons /**< nonlinear constraint */
1096 )
1097{
1098 SCIP_EXPR_OWNERDATA* ownerdata;
1099
1100 assert(eventhdlr != NULL);
1101 assert(expr != NULL);
1102 assert(SCIPisExprVar(scip, expr));
1103 assert(cons != NULL);
1104
1105 ownerdata = SCIPexprGetOwnerData(expr);
1106 assert(ownerdata != NULL);
1107
1108#ifndef NDEBUG
1109 /* assert that constraint does not double-catch variable */
1110 {
1111 int i;
1112 for( i = 0; i < ownerdata->nconss; ++i )
1113 assert(ownerdata->conss[i] != cons);
1114 }
1115#endif
1116
1117 /* append cons to ownerdata->conss */
1118 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1119 ownerdata->conss[ownerdata->nconss++] = cons;
1120 /* we're not capturing the constraint here to avoid circular references */
1121
1122 /* updated sorted flag */
1123 if( ownerdata->nconss <= 1 )
1124 ownerdata->consssorted = TRUE;
1125 else if( ownerdata->consssorted )
1126 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1127
1128 /* catch variable events, if not done so yet (first constraint) */
1129 if( ownerdata->filterpos < 0 )
1130 {
1131 SCIP_EVENTTYPE eventtype;
1132
1133 assert(ownerdata->nconss == 1);
1134
1136
1137 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1138 assert(ownerdata->filterpos >= 0);
1139 }
1140
1141 return SCIP_OKAY;
1142}
1143
1144/** catch variable events */
1145static
1147 SCIP* scip, /**< SCIP data structure */
1148 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1149 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1150 )
1151{
1152 SCIP_CONSHDLRDATA* conshdlrdata;
1153 SCIP_CONSDATA* consdata;
1154 SCIP_EXPR* expr;
1155 int i;
1156
1157 assert(eventhdlr != NULL);
1158 assert(cons != NULL);
1159
1160 consdata = SCIPconsGetData(cons);
1161 assert(consdata != NULL);
1162 assert(consdata->varexprs != NULL);
1163 assert(consdata->nvarexprs >= 0);
1164
1165 /* check if we have catched variable events already */
1166 if( consdata->catchedevents )
1167 return SCIP_OKAY;
1168
1169 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1170 assert(conshdlrdata != NULL);
1171#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1172 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1173#endif
1174
1175 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1176
1177 for( i = 0; i < consdata->nvarexprs; ++i )
1178 {
1179 expr = consdata->varexprs[i];
1180
1181 assert(expr != NULL);
1182 assert(SCIPisExprVar(scip, expr));
1183
1184 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1185
1186 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1187 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1188 */
1189 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1190 {
1191 SCIP_INTERVAL activity;
1192 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1193 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1194 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1195#ifdef DEBUG_PROP
1196 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1197#endif
1198 }
1199 }
1200
1201 consdata->catchedevents = TRUE;
1202
1203 return SCIP_OKAY;
1204}
1205
1206/** unregisters event handler to catch variable events on variable
1207 *
1208 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1209 * If this was the last constraint, then the event handler is unregistered for this variable.
1210 */
1211static
1213 SCIP* scip, /**< SCIP data structure */
1214 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1215 SCIP_EXPR* expr, /**< variable expression */
1216 SCIP_CONS* cons /**< expr constraint */
1217 )
1218{
1219 SCIP_EXPR_OWNERDATA* ownerdata;
1220 int pos;
1221
1222 assert(eventhdlr != NULL);
1223 assert(expr != NULL);
1224 assert(SCIPisExprVar(scip, expr));
1225 assert(cons != NULL);
1226
1227 ownerdata = SCIPexprGetOwnerData(expr);
1228 assert(ownerdata != NULL);
1229 assert(ownerdata->nconss > 0);
1230
1231 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1232 {
1233 pos = ownerdata->nconss-1;
1234 }
1235 else
1236 {
1237 if( !ownerdata->consssorted )
1238 {
1239 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1240 ownerdata->consssorted = TRUE;
1241 }
1242
1243 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1244 {
1245 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1246 return SCIP_ERROR;
1247 }
1248 assert(pos >= 0 && pos < ownerdata->nconss);
1249 }
1250 assert(ownerdata->conss[pos] == cons);
1251
1252 /* move last constraint into position of removed constraint */
1253 if( pos < ownerdata->nconss-1 )
1254 {
1255 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1256 ownerdata->consssorted = FALSE;
1257 }
1258 --ownerdata->nconss;
1259
1260 /* drop variable events if that was the last constraint */
1261 if( ownerdata->nconss == 0 )
1262 {
1263 SCIP_EVENTTYPE eventtype;
1264
1265 assert(ownerdata->filterpos >= 0);
1266
1268
1269 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1270 ownerdata->filterpos = -1;
1271 }
1272
1273 return SCIP_OKAY;
1274}
1275
1276/** drop variable events */
1277static
1279 SCIP* scip, /**< SCIP data structure */
1280 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1281 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1282 )
1283{
1284 SCIP_CONSDATA* consdata;
1285 int i;
1286
1287 assert(eventhdlr != NULL);
1288 assert(cons != NULL);
1289
1290 consdata = SCIPconsGetData(cons);
1291 assert(consdata != NULL);
1292
1293 /* check if we have catched variable events already */
1294 if( !consdata->catchedevents )
1295 return SCIP_OKAY;
1296
1297 assert(consdata->varexprs != NULL);
1298 assert(consdata->nvarexprs >= 0);
1299
1300 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1301
1302 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1303 {
1304 assert(consdata->varexprs[i] != NULL);
1305
1306 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1307 }
1308
1309 consdata->catchedevents = FALSE;
1310
1311 return SCIP_OKAY;
1312}
1313
1314/** creates and captures a nonlinear constraint
1315 *
1316 * @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
1317 */
1318static
1320 SCIP* scip, /**< SCIP data structure */
1321 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1322 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1323 const char* name, /**< name of constraint */
1324 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1325 SCIP_Real lhs, /**< left hand side of constraint */
1326 SCIP_Real rhs, /**< right hand side of constraint */
1327 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1328 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1329 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1330 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1331 * Usually set to TRUE. */
1332 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1333 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1334 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1335 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1336 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1337 * Usually set to TRUE. */
1338 SCIP_Bool local, /**< is constraint only valid locally?
1339 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1340 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1341 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1342 * adds coefficients to this constraint. */
1343 SCIP_Bool dynamic, /**< is constraint subject to aging?
1344 * Usually set to FALSE. Set to TRUE for own cuts which
1345 * are separated as constraints. */
1346 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1347 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1348 )
1349{
1350 SCIP_CONSHDLRDATA* conshdlrdata;
1351 SCIP_CONSDATA* consdata;
1352
1353 assert(conshdlr != NULL);
1354 assert(expr != NULL);
1355
1356 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1357 assert(conshdlrdata != NULL);
1358
1359 if( local && SCIPgetDepth(scip) != 0 )
1360 {
1361 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1362 return SCIP_INVALIDCALL;
1363 }
1364
1365 /* TODO we should allow for non-initial nonlinear constraints */
1366 if( !initial )
1367 {
1368 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1369 return SCIP_INVALIDCALL;
1370 }
1371
1372 /* create constraint data */
1374
1375 if( copyexpr )
1376 {
1377 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1378 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1379 }
1380 else
1381 {
1382 consdata->expr = expr;
1383 SCIPcaptureExpr(consdata->expr);
1384 }
1385 consdata->lhs = lhs;
1386 consdata->rhs = rhs;
1387 consdata->consindex = conshdlrdata->lastconsindex++;
1388 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1389
1390 /* create constraint */
1391 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1392 local, modifiable, dynamic, removable, FALSE) );
1393
1394 return SCIP_OKAY;
1395}
1396
1397/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1398 *
1399 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1400 * Assume that f(x) is associated with auxiliary variable z.
1401 *
1402 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1403 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1404 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1405 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1406 *
1407 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1408 */
1409static
1411 SCIP* scip, /**< SCIP data structure */
1412 SCIP_EXPR* expr, /**< expression */
1413 SCIP_SOL* sol, /**< solution that has been evaluated */
1414 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1415 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1416 )
1417{
1418 SCIP_EXPR_OWNERDATA* ownerdata;
1419 SCIP_Real auxvarvalue;
1420
1421 assert(expr != NULL);
1422
1423 ownerdata = SCIPexprGetOwnerData(expr);
1424 assert(ownerdata != NULL);
1425 assert(ownerdata->auxvar != NULL);
1426
1427 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1428 {
1429 if( violunder != NULL )
1430 *violunder = TRUE;
1431 if( violover != NULL )
1432 *violover = TRUE;
1433 return SCIPinfinity(scip);
1434 }
1435
1436 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1437
1438 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1439 {
1440 if( violunder != NULL )
1441 *violunder = FALSE;
1442 if( violover != NULL )
1443 *violover = TRUE;
1444 return auxvarvalue - SCIPexprGetEvalValue(expr);
1445 }
1446
1447 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1448 {
1449 if( violunder != NULL )
1450 *violunder = TRUE;
1451 if( violover != NULL )
1452 *violover = FALSE;
1453 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1454 }
1455
1456 if( violunder != NULL )
1457 *violunder = FALSE;
1458 if( violover != NULL )
1459 *violover = FALSE;
1460 return 0.0;
1461}
1462
1463/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1464 *
1465 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1466 * Assume that f(w) is associated with auxiliary variable z.
1467 *
1468 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1469 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1470 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1471 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1472 *
1473 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1474 */
1475static
1477 SCIP* scip, /**< SCIP data structure */
1478 SCIP_EXPR* expr, /**< expression */
1479 SCIP_Real auxvalue, /**< value of f(w) */
1480 SCIP_SOL* sol, /**< solution that has been evaluated */
1481 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1482 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1483 )
1484{
1485 SCIP_EXPR_OWNERDATA* ownerdata;
1486 SCIP_Real auxvarvalue;
1487
1488 assert(expr != NULL);
1489
1490 ownerdata = SCIPexprGetOwnerData(expr);
1491 assert(ownerdata != NULL);
1492 assert(ownerdata->auxvar != NULL);
1493
1494 if( auxvalue == SCIP_INVALID )
1495 {
1496 if( violunder != NULL )
1497 *violunder = TRUE;
1498 if( violover != NULL )
1499 *violover = TRUE;
1500 return SCIPinfinity(scip);
1501 }
1502
1503 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1504
1505 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1506 {
1507 if( violunder != NULL )
1508 *violunder = FALSE;
1509 if( violover != NULL )
1510 *violover = TRUE;
1511 return auxvarvalue - auxvalue;
1512 }
1513
1514 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1515 {
1516 if( violunder != NULL )
1517 *violunder = TRUE;
1518 if( violover != NULL )
1519 *violover = FALSE;
1520 return auxvalue - auxvarvalue;
1521 }
1522
1523 if( violunder != NULL )
1524 *violunder = FALSE;
1525 if( violover != NULL )
1526 *violover = FALSE;
1527
1528 return 0.0;
1529}
1530
1531/** computes violation of a constraint */
1532static
1534 SCIP* scip, /**< SCIP data structure */
1535 SCIP_CONS* cons, /**< constraint */
1536 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1537 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1538 )
1539{
1540 SCIP_CONSDATA* consdata;
1541 SCIP_Real activity;
1542
1543 assert(scip != NULL);
1544 assert(cons != NULL);
1545
1546 consdata = SCIPconsGetData(cons);
1547 assert(consdata != NULL);
1548
1549 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1550 activity = SCIPexprGetEvalValue(consdata->expr);
1551
1552 /* consider constraint as violated if it is undefined in the current point */
1553 if( activity == SCIP_INVALID )
1554 {
1555 consdata->lhsviol = SCIPinfinity(scip);
1556 consdata->rhsviol = SCIPinfinity(scip);
1557 return SCIP_OKAY;
1558 }
1559
1560 /* compute violations */
1561 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1562 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1563
1564 return SCIP_OKAY;
1565}
1566
1567/** returns absolute violation of a constraint
1568 *
1569 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1570 */
1571static
1573 SCIP_CONS* cons /**< constraint */
1574 )
1575{
1576 SCIP_CONSDATA* consdata;
1577
1578 assert(cons != NULL);
1579
1580 consdata = SCIPconsGetData(cons);
1581 assert(consdata != NULL);
1582
1583 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1584}
1585
1586/** computes relative violation of a constraint
1587 *
1588 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1589 */
1590static
1592 SCIP* scip, /**< SCIP data structure */
1593 SCIP_CONS* cons, /**< constraint */
1594 SCIP_Real* viol, /**< buffer to store violation */
1595 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1596 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1597 )
1598{
1599 SCIP_CONSHDLR* conshdlr;
1600 SCIP_CONSHDLRDATA* conshdlrdata;
1601 SCIP_CONSDATA* consdata;
1602 SCIP_Real scale;
1603
1604 assert(cons != NULL);
1605 assert(viol != NULL);
1606
1607 conshdlr = SCIPconsGetHdlr(cons);
1608 assert(conshdlr != NULL);
1609
1610 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1611 assert(conshdlrdata != NULL);
1612
1613 *viol = getConsAbsViolation(cons);
1614
1615 if( conshdlrdata->violscale == 'n' )
1616 return SCIP_OKAY;
1617
1618 if( SCIPisInfinity(scip, *viol) )
1619 return SCIP_OKAY;
1620
1621 consdata = SCIPconsGetData(cons);
1622 assert(consdata != NULL);
1623
1624 if( conshdlrdata->violscale == 'a' )
1625 {
1626 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1627
1628 /* consider value of side that is violated for scaling, too */
1629 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1630 {
1631 assert(!SCIPisInfinity(scip, -consdata->lhs));
1632 scale = REALABS(consdata->lhs);
1633 }
1634 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1635 {
1636 assert(!SCIPisInfinity(scip, consdata->rhs));
1637 scale = REALABS(consdata->rhs);
1638 }
1639
1640 *viol /= scale;
1641 return SCIP_OKAY;
1642 }
1643
1644 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1645 assert(conshdlrdata->violscale == 'g');
1646 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1647 {
1648 /* we need the varexprs to conveniently access the gradient */
1649 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1650
1651 /* update cached value of norm of gradient */
1652 consdata->gradnorm = 0.0;
1653
1654 /* compute gradient */
1655 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1656
1657 /* gradient evaluation error -> no scaling */
1658 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1659 {
1660 int i;
1661 for( i = 0; i < consdata->nvarexprs; ++i )
1662 {
1663 SCIP_Real deriv;
1664
1665 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1666 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1667 if( deriv == SCIP_INVALID )
1668 {
1669 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1670 consdata->gradnorm = 0.0;
1671 break;
1672 }
1673
1674 consdata->gradnorm += deriv*deriv;
1675 }
1676 }
1677 consdata->gradnorm = sqrt(consdata->gradnorm);
1678 consdata->gradnormsoltag = soltag;
1679 }
1680
1681 *viol /= MAX(1.0, consdata->gradnorm);
1682
1683 return SCIP_OKAY;
1684}
1685
1686/** returns whether constraint is currently violated
1687 *
1688 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1689 */
1690static
1692 SCIP* scip, /**< SCIP data structure */
1693 SCIP_CONS* cons /**< constraint */
1694 )
1695{
1696 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1697}
1698
1699/** checks for a linear variable that can be increased or decreased without harming feasibility */
1700static
1702 SCIP* scip, /**< SCIP data structure */
1703 SCIP_CONS* cons /**< constraint */
1704 )
1705{
1706 SCIP_CONSDATA* consdata;
1707 int poslock;
1708 int neglock;
1709 int i;
1710
1711 assert(cons != NULL);
1712
1713 consdata = SCIPconsGetData(cons);
1714 assert(consdata != NULL);
1715
1716 consdata->linvarincr = NULL;
1717 consdata->linvardecr = NULL;
1718 consdata->linvarincrcoef = 0.0;
1719 consdata->linvardecrcoef = 0.0;
1720
1721 /* root expression is not a sum -> no unlocked linear variable available */
1722 if( !SCIPisExprSum(scip, consdata->expr) )
1723 return;
1724
1725 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1726 {
1727 SCIP_EXPR* child;
1728
1729 child = SCIPexprGetChildren(consdata->expr)[i];
1730 assert(child != NULL);
1731
1732 /* check whether the child is a variable expression */
1733 if( SCIPisExprVar(scip, child) )
1734 {
1735 SCIP_VAR* var = SCIPgetVarExprVar(child);
1736 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1737
1738 if( coef > 0.0 )
1739 {
1740 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1741 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1742 }
1743 else
1744 {
1745 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1746 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1747 }
1749
1751 {
1752 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1753 * if we have already one candidate, then take the one where the loss in the objective function is less
1754 */
1755 if( (consdata->linvardecr == NULL) ||
1756 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1757 {
1758 consdata->linvardecr = var;
1759 consdata->linvardecrcoef = coef;
1760 }
1761 }
1762
1764 {
1765 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1766 * if we have already one candidate, then take the one where the loss in the objective function is less
1767 */
1768 if( (consdata->linvarincr == NULL) ||
1769 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1770 {
1771 consdata->linvarincr = var;
1772 consdata->linvarincrcoef = coef;
1773 }
1774 }
1775 }
1776 }
1777
1778 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1779 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1780
1781 if( consdata->linvarincr != NULL )
1782 {
1783 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1784 }
1785 if( consdata->linvardecr != NULL )
1786 {
1787 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1788 }
1789}
1790
1791/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1792 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1793 *
1794 * The method assumes that this is always possible and that not all constraints are feasible already.
1795 */
1796static
1798 SCIP* scip, /**< SCIP data structure */
1799 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1800 SCIP_CONS** conss, /**< constraints to process */
1801 int nconss, /**< number of constraints */
1802 SCIP_SOL* sol, /**< solution to process */
1803 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1804 )
1805{
1806 SCIP_CONSHDLRDATA* conshdlrdata;
1808 int c;
1809
1810 assert(scip != NULL);
1811 assert(conshdlr != NULL);
1812 assert(conss != NULL || nconss == 0);
1813 assert(success != NULL);
1814
1815 *success = FALSE;
1816
1817 /* don't propose new solutions if not in presolve or solving */
1819 return SCIP_OKAY;
1820
1821 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1822 assert(conshdlrdata != NULL);
1823
1824 if( sol != NULL )
1825 {
1827 }
1828 else
1829 {
1831 }
1833 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1834 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1835
1836 for( c = 0; c < nconss; ++c )
1837 {
1838 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1839 SCIP_Real viol = 0.0;
1840 SCIP_Real delta;
1841 SCIP_Real gap;
1842
1843 assert(consdata != NULL);
1844
1845 /* get absolute violation and sign */
1846 if( consdata->lhsviol > SCIPfeastol(scip) )
1847 viol = consdata->lhsviol; /* lhs - activity */
1848 else if( consdata->rhsviol > SCIPfeastol(scip) )
1849 viol = -consdata->rhsviol; /* rhs - activity */
1850 else
1851 continue; /* constraint is satisfied */
1852
1853 if( consdata->linvarincr != NULL &&
1854 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1855 {
1856 SCIP_VAR* var = consdata->linvarincr;
1857
1858 /* compute how much we would like to increase var */
1859 delta = viol / consdata->linvarincrcoef;
1860 assert(delta > 0.0);
1861
1862 /* if var has an upper bound, may need to reduce delta */
1864 {
1866 delta = MIN(MAX(0.0, gap), delta);
1867 }
1868 if( SCIPisPositive(scip, delta) )
1869 {
1870 /* if variable is integral, round delta up so that it will still have an integer value */
1871 if( SCIPvarIsIntegral(var) )
1872 delta = SCIPceil(scip, delta);
1873
1874 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1875 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1876 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1877
1878 /* adjust constraint violation, if satisfied go on to next constraint */
1879 viol -= consdata->linvarincrcoef * delta;
1880 if( SCIPisZero(scip, viol) )
1881 continue;
1882 }
1883 }
1884
1885 assert(viol != 0.0);
1886 if( consdata->linvardecr != NULL &&
1887 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1888 {
1889 SCIP_VAR* var = consdata->linvardecr;
1890
1891 /* compute how much we would like to decrease var */
1892 delta = viol / consdata->linvardecrcoef;
1893 assert(delta < 0.0);
1894
1895 /* if var has a lower bound, may need to reduce delta */
1897 {
1899 delta = MAX(MIN(0.0, gap), delta);
1900 }
1901 if( SCIPisNegative(scip, delta) )
1902 {
1903 /* if variable is integral, round delta down so that it will still have an integer value */
1904 if( SCIPvarIsIntegral(var) )
1905 delta = SCIPfloor(scip, delta);
1906 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1907 /*lint --e{613} */
1908 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1909 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1910
1911 /* adjust constraint violation, if satisfied go on to next constraint */
1912 viol -= consdata->linvardecrcoef * delta;
1913 if( SCIPisZero(scip, viol) )
1914 continue;
1915 }
1916 }
1917
1918 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1919 break;
1920 }
1921
1922 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1923 * then pass it to the trysol heuristic
1924 */
1926 {
1927 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1928
1929 assert(conshdlrdata->trysolheur != NULL);
1930 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1931
1932 *success = TRUE;
1933 }
1934
1936
1937 return SCIP_OKAY;
1938}
1939
1940/** notify nonlinear handlers to add linearization in new solution that has been found
1941 *
1942 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1943 *
1944 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1945 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1946 * cut that is valid and supporting in the given solution.
1947 * For example, for convex constraints, we achieve this by linearizing.
1948 * For SOC, we also linearize, but on a a convex reformulation.
1949 *
1950 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1951 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1952 */
1953static
1955 SCIP* scip, /**< SCIP data structure */
1956 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1957 SCIP_CONS** conss, /**< constraints */
1958 int nconss, /**< number of constraints */
1959 SCIP_SOL* sol, /**< reference point where to estimate */
1960 SCIP_Bool solisbest /**< whether solution is best */
1961 )
1962{
1963 SCIP_CONSDATA* consdata;
1964 SCIP_Longint soltag;
1966 SCIP_EXPR* expr;
1967 int c, e;
1968
1969 assert(scip != NULL);
1970 assert(conshdlr != NULL);
1971 assert(conss != NULL || nconss == 0);
1972
1973 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1974
1975 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1976 * would be nice to recognize this and skip reevaluating
1977 */
1979
1983
1984 for( c = 0; c < nconss; ++c )
1985 {
1986 /* skip constraints that are not enabled or deleted or have separation disabled */
1987 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
1988 continue;
1989 assert(SCIPconsIsActive(conss[c]));
1990
1991 consdata = SCIPconsGetData(conss[c]);
1992 assert(consdata != NULL);
1993
1994 ENFOLOG(
1995 {
1996 int i;
1997 SCIPinfoMessage(scip, enfologfile, " constraint ");
1999 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2000 for( i = 0; i < consdata->nvarexprs; ++i )
2001 {
2002 SCIP_VAR* var;
2003 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2004 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2006 }
2007 })
2008
2009 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2010 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2011
2012 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2013 {
2014 SCIP_EXPR_OWNERDATA* ownerdata;
2015
2016 ownerdata = SCIPexprGetOwnerData(expr);
2017 assert(ownerdata != NULL);
2018
2019 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2022 if( ownerdata->auxvar != NULL )
2023 {
2024 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2025 }
2026
2027 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2028 for( e = 0; e < ownerdata->nenfos; ++e )
2029 {
2030 /* call sollinearize callback, if implemented by nlhdlr */
2031 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2032 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2033 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2034 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2035 }
2036 }
2037 }
2038
2040
2041 return SCIP_OKAY;
2042}
2043
2044/** processes the event that a new primal solution has been found */
2045static
2047{
2048 SCIP_CONSHDLR* conshdlr;
2049 SCIP_CONSHDLRDATA* conshdlrdata;
2050 SCIP_SOL* sol;
2051
2052 assert(scip != NULL);
2053 assert(event != NULL);
2054 assert(eventdata != NULL);
2055 assert(eventhdlr != NULL);
2057
2058 conshdlr = (SCIP_CONSHDLR*)eventdata;
2059
2060 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2061 return SCIP_OKAY;
2062
2064 assert(sol != NULL);
2065
2066 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2067 assert(conshdlrdata != NULL);
2068
2069 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2070 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2071 * from the tree, but postprocessed via proposeFeasibleSolution
2072 */
2073 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2074 return SCIP_OKAY;
2075
2076 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2077
2079
2080 return SCIP_OKAY;
2081}
2082
2083/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2084 *
2085 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2086 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2087 *
2088 * Nothing will happen if SCIP is not in presolve or solve.
2089 */
2090static
2092 SCIP* scip, /**< SCIP data structure */
2093 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2094 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2095 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2096 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2097 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2098 )
2099{
2100 SCIP_VAR* var;
2101 SCIP_Bool tightenedlb;
2102 SCIP_Bool tightenedub;
2103 SCIP_Bool force;
2104
2105 assert(scip != NULL);
2106 assert(conshdlr != NULL);
2107 assert(expr != NULL);
2108 assert(cutoff != NULL);
2109
2110 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2112
2113 *cutoff = FALSE;
2114
2116 if( var == NULL )
2117 return SCIP_OKAY;
2118
2119 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2120 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2121
2122 /* try to tighten lower bound of (auxiliary) variable */
2123 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2124 if( tightenedlb )
2125 {
2126 if( ntightenings != NULL )
2127 ++*ntightenings;
2128 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2129 }
2130 if( *cutoff )
2131 {
2132 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2133 return SCIP_OKAY;
2134 }
2135
2136 /* try to tighten upper bound of (auxiliary) variable */
2137 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2138 if( tightenedub )
2139 {
2140 if( ntightenings != NULL )
2141 ++*ntightenings;
2142 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2143 }
2144 if( *cutoff )
2145 {
2146 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2147 return SCIP_OKAY;
2148 }
2149
2150 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2151 * that seems unnecessary and we could easily undo this here, e.g.,
2152 * if( tightenedlb ) expr->activity.inf = bounds.inf
2153 */
2154
2155 return SCIP_OKAY;
2156}
2157
2158/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2159 * and tries to tighten the bounds of the auxiliary variables accordingly
2160 */
2161static
2163 SCIP* scip, /**< SCIP data structure */
2164 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2165 SCIP_EXPR* rootexpr, /**< expression */
2166 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2167 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2168 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2169 )
2170{
2172 SCIP_EXPR* expr;
2173 SCIP_EXPR_OWNERDATA* ownerdata;
2174 SCIP_CONSHDLRDATA* conshdlrdata;
2175
2176 assert(scip != NULL);
2177 assert(rootexpr != NULL);
2178
2179 if( infeasible != NULL )
2180 *infeasible = FALSE;
2181 if( ntightenings != NULL )
2182 *ntightenings = 0;
2183
2184 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2185 assert(conshdlrdata != NULL);
2186
2187 /* if value is valid and empty, then we cannot improve, so do nothing */
2189 {
2190 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2191
2192 if( infeasible != NULL )
2193 *infeasible = TRUE;
2194
2195 /* just update tag to curboundstag */
2196 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2197
2198 return SCIP_OKAY;
2199 }
2200
2201 /* if value is up-to-date, then nothing to do */
2202 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2203 {
2204 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2205
2207
2208 return SCIP_OKAY;
2209 }
2210
2211 ownerdata = SCIPexprGetOwnerData(rootexpr);
2212 assert(ownerdata != NULL);
2213
2214 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2215 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2216 * during detect, we are in some in-between state where we may want to eval activity
2217 * on exprs that we did not notify about their activity usage
2218 */
2219 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2220 {
2221#ifdef DEBUG_PROP
2222 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2223#endif
2224 SCIPABORT();
2225 return SCIP_OKAY;
2226 }
2227
2231
2233 {
2234 switch( SCIPexpriterGetStageDFS(it) )
2235 {
2237 {
2238 /* skip child if it has been evaluated already */
2239 SCIP_EXPR* child;
2240
2242 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2243 {
2245 *infeasible = TRUE;
2246
2247 expr = SCIPexpriterSkipDFS(it);
2248 continue;
2249 }
2250
2251 break;
2252 }
2253
2255 {
2256 SCIP_INTERVAL activity;
2257
2258 /* we should not have entered this expression if its activity was already up to date */
2259 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2260
2261 ownerdata = SCIPexprGetOwnerData(expr);
2262 assert(ownerdata != NULL);
2263
2264 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2265 * so we can assume that the activity is up to date for all these variables
2266 * UNLESS we changed the method used to evaluate activity of variable expressions
2267 * or we currently use global bounds (varevents are catched for local bound changes only)
2268 */
2269 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2270 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2271 {
2272#ifndef NDEBUG
2274
2275 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2278#endif
2279#ifdef DEBUG_PROP
2280 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2281#endif
2282 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2283
2284 break;
2285 }
2286
2287 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2288 {
2289 /* start with entire activity if current one is invalid */
2291 }
2293 {
2294 /* If already empty, then don't try to compute even better activity.
2295 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2296 * so an assert(infeasible == NULL || *infeasible) should work here.
2297 * However, after reporting a cutoff due to expr->activity being empty,
2298 * SCIP may wander to a different node and call propagation again.
2299 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2300 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2301 * we will still have expr->activity being empty, but will have forgotten
2302 * that we found infeasibility here before (!2221#note_134120).
2303 * Therefore we just set *infeasibility=TRUE here and stop.
2304 */
2305 if( infeasible != NULL )
2306 *infeasible = TRUE;
2307 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2308 break;
2309 }
2310 else
2311 {
2312 /* start with current activity, since it is valid */
2313 activity = SCIPexprGetActivity(expr);
2314 }
2315
2316 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2317 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2318 {
2319#ifdef DEBUG_PROP
2320 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2321#endif
2322 break;
2323 }
2324
2325#ifdef DEBUG_PROP
2326 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2327 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2328 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2329#endif
2330
2331 /* run interval eval of nonlinear handlers or expression handler */
2332 if( ownerdata->nenfos > 0 )
2333 {
2334 SCIP_NLHDLR* nlhdlr;
2336 int e;
2337
2338 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2339 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2340 {
2341 /* skip nlhdlr if it does not want to participate in activity computation */
2342 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2343 continue;
2344
2345 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2346 assert(nlhdlr != NULL);
2347
2348 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2349 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2350 continue;
2351
2352 /* let nlhdlr evaluate current expression */
2353 nlhdlrinterval = activity;
2354 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2355 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2356#ifdef DEBUG_PROP
2357 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2358#endif
2359
2360 /* update activity by intersecting with computed activity */
2362#ifdef DEBUG_PROP
2363 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2364#endif
2365 }
2366 }
2367 else
2368 {
2369 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2371 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2372#ifdef DEBUG_PROP
2373 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2374#endif
2375
2376 /* update expr->activity by intersecting with computed activity */
2378#ifdef DEBUG_PROP
2379 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2380#endif
2381 }
2382
2383 /* if expression is integral, then we try to tighten the interval bounds a bit
2384 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2385 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2386 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2387 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2388 * (constants should be ok, too)
2389 */
2390 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2391 {
2392 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2393 activity.inf = SCIPceil(scip, activity.inf);
2394 if( activity.sup < SCIP_INTERVAL_INFINITY )
2395 activity.sup = SCIPfloor(scip, activity.sup);
2396#ifdef DEBUG_PROP
2397 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2398#endif
2399 }
2400
2401 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2402 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2403 */
2404 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2405 {
2406 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2407 SCIPintervalSetEmpty(&activity);
2408 }
2409
2410 /* now finally store activity in expr */
2411 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2412
2414 {
2415 if( infeasible != NULL )
2416 *infeasible = TRUE;
2417 }
2418 else if( tightenauxvars && ownerdata->auxvar != NULL )
2419 {
2420 SCIP_Bool tighteninfeasible;
2421
2422 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2423 if( tighteninfeasible )
2424 {
2425 if( infeasible != NULL )
2426 *infeasible = TRUE;
2427 SCIPintervalSetEmpty(&activity);
2428 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2429 }
2430 }
2431
2432 break;
2433 }
2434
2435 default:
2436 /* you should never be here */
2437 SCIPerrorMessage("unexpected iterator stage\n");
2438 SCIPABORT();
2439 break;
2440 }
2441
2442 expr = SCIPexpriterGetNext(it);
2443 }
2444
2446
2447 return SCIP_OKAY;
2448}
2449
2450/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2451 *
2452 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2453 *
2454 * If `subsetsufficient` is FALSE, then we require
2455 * - a change from an unbounded interval to a bounded one, or
2456 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2457 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2458 */
2459static
2461 SCIP* scip, /**< SCIP data structure */
2462 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2463 SCIP_INTERVAL newinterval, /**< new interval */
2464 SCIP_INTERVAL oldinterval /**< old interval */
2465 )
2466{
2467 assert(scip != NULL);
2470
2471 if( subsetsufficient )
2472 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2474
2475 /* check whether lower bound of interval becomes finite */
2477 return TRUE;
2478
2479 /* check whether upper bound of interval becomes finite */
2481 return TRUE;
2482
2483 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2485 return TRUE;
2486
2487 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2489 return TRUE;
2490
2491 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2493 return TRUE;
2494
2495 return FALSE;
2496}
2497
2498/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2499 *
2500 * The expression will be traversed in breadth first search by using this queue.
2501 *
2502 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2503 * forwardPropExpr() before calling this function.
2504 *
2505 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2506 */
2507static
2509 SCIP* scip, /**< SCIP data structure */
2510 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2511 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2512 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2513 )
2514{
2515 SCIP_CONSHDLRDATA* conshdlrdata;
2516 SCIP_EXPR* expr;
2517 SCIP_EXPR_OWNERDATA* ownerdata;
2518
2519 assert(infeasible != NULL);
2521
2522 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2523 assert(conshdlrdata != NULL);
2524
2525 *ntightenings = 0;
2526
2527 /* main loop that calls reverse propagation for expressions on the queue
2528 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2529 */
2530 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2531 {
2532 SCIP_INTERVAL propbounds;
2533 int e;
2534
2535 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2536 assert(expr != NULL);
2537
2538 ownerdata = SCIPexprGetOwnerData(expr);
2539 assert(ownerdata != NULL);
2540
2541 assert(ownerdata->inpropqueue);
2542 /* mark that the expression is not in the queue anymore */
2543 ownerdata->inpropqueue = FALSE;
2544
2545 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2546 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2547 */
2548 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2549 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2550 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2551
2552 /* this intersects propbounds with activity and auxvar bounds
2553 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2554 * auxvar bounds separately, so disabling this for now
2555 */
2556#ifdef SCIP_DISABLED_CODE
2557 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2559 {
2560 *infeasible = TRUE;
2561 break;
2562 }
2563#else
2564 propbounds = ownerdata->propbounds;
2565#endif
2566
2567 if( ownerdata->nenfos > 0 )
2568 {
2569 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2570 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2571 {
2572 SCIP_NLHDLR* nlhdlr;
2573 int nreds;
2574
2575 /* skip nlhdlr if it does not want to participate in activity computation */
2576 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2577 continue;
2578
2579 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2580 assert(nlhdlr != NULL);
2581
2582 /* call the reverseprop of the nlhdlr */
2583#ifdef SCIP_DEBUG
2584 SCIPdebugMsg(scip, "call reverse propagation for ");
2585 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2586 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2587#endif
2588
2589 nreds = 0;
2590 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2591 assert(nreds >= 0);
2592 *ntightenings += nreds;
2593 }
2594 }
2596 {
2597 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2599 int c;
2600
2601#ifdef SCIP_DEBUG
2602 SCIPdebugMsg(scip, "call reverse propagation for ");
2603 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2604 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2605#endif
2606
2607 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2608 * been initialized in detectNlhdlr yet (nenfos < 0)
2609 */
2610 assert(ownerdata->nenfos < 0);
2611
2613 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2615
2616 /* call the reverseprop of the exprhdlr */
2617 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2618
2619 if( !*infeasible )
2620 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2621 {
2623 }
2624
2626 }
2627 }
2628
2629 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2630 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2631 {
2632 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2633 assert(expr != NULL);
2634
2635 ownerdata = SCIPexprGetOwnerData(expr);
2636 assert(ownerdata != NULL);
2637
2638 /* mark that the expression is not in the queue anymore */
2639 ownerdata->inpropqueue = FALSE;
2640 }
2641
2642 return SCIP_OKAY;
2643}
2644
2645/** calls domain propagation for a given set of constraints
2646 *
2647 * The algorithm alternates calls of forward and reverse propagation.
2648 * Forward propagation ensures that activity of expressions is up to date.
2649 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2650 * [lhs,rhs] interval as starting point.
2651 *
2652 * The propagation algorithm works as follows:
2653 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2654 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2655 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2656 * provide tighter bounds
2657 * 3. apply reverse propagation to all collected expressions; don't explore
2658 * sub-expressions which have not changed since the beginning of the propagation loop
2659 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2660 *
2661 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2662 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2663 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2664 *
2665 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2666 * e.g., try less to propagate on convex constraints?
2667 */
2668static
2670 SCIP* scip, /**< SCIP data structure */
2671 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2672 SCIP_CONS** conss, /**< constraints to propagate */
2673 int nconss, /**< total number of constraints */
2674 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2675 SCIP_RESULT* result, /**< pointer to store the result */
2676 int* nchgbds /**< buffer to add the number of changed bounds */
2677 )
2678{
2679 SCIP_CONSHDLRDATA* conshdlrdata;
2680 SCIP_CONSDATA* consdata;
2681 SCIP_EXPR_OWNERDATA* ownerdata;
2682 SCIP_Bool cutoff = FALSE;
2684 int ntightenings;
2685 int roundnr;
2687 int i;
2688
2689 assert(scip != NULL);
2690 assert(conshdlr != NULL);
2691 assert(conss != NULL);
2692 assert(nconss >= 0);
2693 assert(result != NULL);
2694 assert(nchgbds != NULL);
2695 assert(*nchgbds >= 0);
2696
2697 /* no constraints to propagate */
2698 if( nconss == 0 )
2699 {
2701 return SCIP_OKAY;
2702 }
2703
2704 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2705 assert(conshdlrdata != NULL);
2706#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2707 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2708#endif
2709 assert(!conshdlrdata->globalbounds);
2710
2712 roundnr = 0;
2713
2714 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2715 conshdlrdata->forceboundtightening = force;
2716
2717 /* invalidate all propbounds (probably not needed) */
2718 ++conshdlrdata->curpropboundstag;
2719
2720 /* create iterator that we will use if we need to look at all auxvars */
2721 if( conshdlrdata->propauxvars )
2722 {
2724 }
2725
2726 /* main propagation loop */
2727 do
2728 {
2729 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2730
2731 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2732
2733 /* apply forward propagation (update expression activities)
2734 * and add promising root expressions into queue for reversepropagation
2735 */
2736 for( i = 0; i < nconss; ++i )
2737 {
2738 consdata = SCIPconsGetData(conss[i]);
2739 assert(consdata != NULL);
2740
2741 /* skip deleted, non-active, or propagation-disabled constraints */
2742 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2743 continue;
2744
2745 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2746 * activity didn't change
2747 */
2748 if( consdata->ispropagated )
2749 continue;
2750
2751 /* update activities in expression */
2752 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2753 SCIPdebugPrintCons(scip, conss[i], NULL);
2754
2755 ntightenings = 0;
2756 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2758
2759 if( cutoff )
2760 {
2761 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2763 break;
2764 }
2765
2766 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2767
2768 /* 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 */
2769 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2770 {
2771 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2772 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2773 * so taking auxvar bounds is enough)
2774 */
2775 if( ownerdata->auxvar == NULL )
2776 {
2777 /* relax sides by SCIPepsilon() and handle infinite sides */
2778 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2779 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2780 SCIPintervalSetBounds(&conssides, lhs, rhs);
2781 }
2782 else
2783 {
2784 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2785 }
2787 }
2788 else
2789 {
2790 /* check whether bounds of any auxvar used in constraint provides a tightening
2791 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2792 * but skip exprs that have an auxvar, but do not participate in propagation
2793 */
2794 SCIP_EXPR* expr;
2795
2799 {
2800 ownerdata = SCIPexprGetOwnerData(expr);
2801 assert(ownerdata != NULL);
2802
2803 if( ownerdata->auxvar == NULL )
2804 continue;
2805
2806 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2807 continue;
2808
2809 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2811 }
2812 }
2813
2814 if( cutoff )
2815 {
2816 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2818 break;
2819 }
2820
2821 assert(ntightenings >= 0);
2822 if( ntightenings > 0 )
2823 {
2824 *nchgbds += ntightenings;
2826 }
2827
2828 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2829 consdata->ispropagated = TRUE;
2830 }
2831
2832 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2834 assert(ntightenings >= 0);
2835 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2836
2837 if( cutoff )
2838 {
2839 SCIPdebugMsg(scip, " -> cutoff\n");
2841 break;
2842 }
2843
2844 if( ntightenings > 0 )
2845 {
2846 *nchgbds += ntightenings;
2848 }
2849 }
2850 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2851
2852 if( conshdlrdata->propauxvars )
2853 {
2855 }
2856
2857 conshdlrdata->forceboundtightening = FALSE;
2858
2859 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2860 ++conshdlrdata->curpropboundstag;
2861
2862 return SCIP_OKAY;
2863}
2864
2865/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2866 *
2867 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2868 *
2869 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2870 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2871 */
2872static
2874 SCIP* scip, /**< SCIP data structure */
2875 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2876 SCIP_CONS** conss, /**< constraints to propagate */
2877 int nconss, /**< total number of constraints */
2878 SCIP_RESULT* result, /**< pointer to store the result */
2879 int* nchgbds /**< buffer to add the number of changed bounds */
2880 )
2881{
2882 SCIP_CONSDATA* consdata;
2884 SCIP_EXPR* expr;
2885 SCIP_EXPR_OWNERDATA* ownerdata;
2886 SCIP_Bool cutoff = FALSE;
2887 int ntightenings;
2888 int c;
2889 int e;
2890
2891 assert(scip != NULL);
2892 assert(conshdlr != NULL);
2893 assert(conss != NULL);
2894 assert(nconss >= 0);
2895 assert(result != NULL);
2896 assert(nchgbds != NULL);
2897 assert(*nchgbds >= 0);
2898
2899#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2901#endif
2902 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2903 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2904
2906
2909
2910 for( c = 0; c < nconss && !cutoff; ++c )
2911 {
2912 /* skip deleted, non-active, or propagation-disabled constraints */
2913 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2914 continue;
2915
2916 consdata = SCIPconsGetData(conss[c]);
2917 assert(consdata != NULL);
2918
2919 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2920 {
2921 ownerdata = SCIPexprGetOwnerData(expr);
2922 assert(ownerdata != NULL);
2923
2924 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2925 * this will propagate the current activity
2926 */
2927 for( e = 0; e < ownerdata->nenfos; ++e )
2928 {
2929 SCIP_NLHDLR* nlhdlr;
2930 assert(ownerdata->enfos[e] != NULL);
2931
2932 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2933 assert(nlhdlr != NULL);
2934 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2935 continue;
2936
2937 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2938 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2939 ntightenings = 0;
2940 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2942
2943 if( cutoff )
2944 {
2945 /* stop everything if we detected infeasibility */
2946 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2948 break;
2949 }
2950
2951 assert(ntightenings >= 0);
2952 if( ntightenings > 0 )
2953 {
2954 *nchgbds += ntightenings;
2956 }
2957 }
2958 }
2959 }
2960
2961 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2963 assert(ntightenings >= 0);
2964
2965 if( cutoff )
2966 {
2967 SCIPdebugMsg(scip, " -> cutoff\n");
2969 }
2970 else if( ntightenings > 0 )
2971 {
2972 *nchgbds += ntightenings;
2974 }
2975
2977
2978 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2979 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2980
2981 return SCIP_OKAY;
2982}
2983
2984/** propagates variable locks through expression and adds locks to variables */
2985static
2987 SCIP* scip, /**< SCIP data structure */
2988 SCIP_EXPR* expr, /**< expression */
2989 int nlockspos, /**< number of positive locks */
2990 int nlocksneg /**< number of negative locks */
2991 )
2992{
2993 SCIP_EXPR_OWNERDATA* ownerdata;
2996
2997 assert(expr != NULL);
2998
2999 /* if no locks, then nothing to propagate */
3000 if( nlockspos == 0 && nlocksneg == 0 )
3001 return SCIP_OKAY;
3002
3006 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3007
3008 /* store locks in root node */
3009 ituserdata.intvals[0] = nlockspos;
3010 ituserdata.intvals[1] = nlocksneg;
3012
3013 while( !SCIPexpriterIsEnd(it) )
3014 {
3015 /* collect locks */
3017 nlockspos = ituserdata.intvals[0];
3018 nlocksneg = ituserdata.intvals[1];
3019
3020 ownerdata = SCIPexprGetOwnerData(expr);
3021
3022 switch( SCIPexpriterGetStageDFS(it) )
3023 {
3025 {
3026 if( SCIPisExprVar(scip, expr) )
3027 {
3028 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3029 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3030 }
3031
3032 /* add locks to expression */
3033 ownerdata->nlockspos += nlockspos;
3034 ownerdata->nlocksneg += nlocksneg;
3035
3036 /* add monotonicity information if expression has been locked for the first time */
3037 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3039 {
3040 int i;
3041
3042 assert(ownerdata->monotonicity == NULL);
3043 assert(ownerdata->monotonicitysize == 0);
3044
3045 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3046 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3047
3048 /* store the monotonicity for each child */
3049 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3050 {
3051 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3052 }
3053 }
3054 break;
3055 }
3056
3058 {
3059 /* remove monotonicity information if expression has been unlocked */
3060 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3061 {
3062 assert(ownerdata->monotonicitysize > 0);
3063 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3064 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3065
3066 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3067 ownerdata->monotonicitysize = 0;
3068 }
3069 break;
3070 }
3071
3073 {
3074 SCIP_MONOTONE monotonicity;
3075
3076 /* get monotonicity of child */
3077 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3078 * SCIPcallExprMonotonicity
3079 */
3080 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3081
3082 /* compute resulting locks of the child expression */
3083 switch( monotonicity )
3084 {
3085 case SCIP_MONOTONE_INC:
3086 ituserdata.intvals[0] = nlockspos;
3087 ituserdata.intvals[1] = nlocksneg;
3088 break;
3089 case SCIP_MONOTONE_DEC:
3090 ituserdata.intvals[0] = nlocksneg;
3091 ituserdata.intvals[1] = nlockspos;
3092 break;
3094 ituserdata.intvals[0] = nlockspos + nlocksneg;
3095 ituserdata.intvals[1] = nlockspos + nlocksneg;
3096 break;
3098 ituserdata.intvals[0] = 0;
3099 ituserdata.intvals[1] = 0;
3100 break;
3101 }
3102 /* set locks in child expression */
3104
3105 break;
3106 }
3107
3108 default :
3109 /* you should never be here */
3110 SCIPABORT();
3111 break;
3112 }
3113
3114 expr = SCIPexpriterGetNext(it);
3115 }
3116
3118
3119 return SCIP_OKAY;
3120}
3121
3122/** main function for adding locks to expressions and variables
3123 *
3124 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3125 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3126 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3127 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3128 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3129 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3130 * which implies that updating the monotonicity information during the next locking of this expression does not
3131 * break existing locks.
3132 *
3133 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3134 * locks from an expression and repropagating them after the structural changes have been applied.
3135 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3136 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3137 */
3138static
3140 SCIP* scip, /**< SCIP data structure */
3141 SCIP_CONS* cons, /**< nonlinear constraint */
3142 int nlockspos, /**< number of positive rounding locks */
3143 int nlocksneg /**< number of negative rounding locks */
3144 )
3145{
3146 SCIP_CONSDATA* consdata;
3147
3148 assert(cons != NULL);
3149
3150 if( nlockspos == 0 && nlocksneg == 0 )
3151 return SCIP_OKAY;
3152
3153 consdata = SCIPconsGetData(cons);
3154 assert(consdata != NULL);
3155
3156 /* no constraint sides -> nothing to lock */
3157 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3158 return SCIP_OKAY;
3159
3160 /* remember locks */
3161 consdata->nlockspos += nlockspos;
3162 consdata->nlocksneg += nlocksneg;
3163
3164 assert(consdata->nlockspos >= 0);
3165 assert(consdata->nlocksneg >= 0);
3166
3167 /* compute locks for lock propagation */
3168 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3169 {
3170 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3171 }
3172 else if( !SCIPisInfinity(scip, consdata->rhs) )
3173 {
3174 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3175 }
3176 else
3177 {
3178 assert(!SCIPisInfinity(scip, -consdata->lhs));
3179 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3180 }
3181
3182 return SCIP_OKAY;
3183}
3184
3185/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3186static
3188 SCIP* scip, /**< SCIP data structure */
3189 SCIP_CONS* cons /**< nonlinear constraint */
3190 )
3191{
3192 SCIP_CONSDATA* consdata;
3193
3194 assert(scip != NULL);
3195 assert(cons != NULL);
3196
3197 consdata = SCIPconsGetData(cons);
3198 assert(consdata != NULL);
3199 assert(consdata->expr != NULL);
3200
3201 if( consdata->nlrow != NULL )
3202 {
3203 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3204 }
3205
3206 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3207 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3208 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3209
3210 if( SCIPisExprSum(scip, consdata->expr) )
3211 {
3212 /* if root is a sum, then split into linear and nonlinear terms */
3214 SCIP_EXPR* child;
3215 SCIP_Real* coefs;
3216 int i;
3217
3218 coefs = SCIPgetCoefsExprSum(consdata->expr);
3219
3220 /* constant term of sum */
3221 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3222
3223 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3225
3226 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3227 {
3228 child = SCIPexprGetChildren(consdata->expr)[i];
3229 if( SCIPisExprVar(scip, child) )
3230 {
3231 /* linear term */
3232 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3233 }
3234 else
3235 {
3236 /* nonlinear term */
3237 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3238 }
3239 }
3240
3242 {
3243 /* add expression to nlrow (this will make a copy) */
3244 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3245 }
3247 }
3248 else
3249 {
3250 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3251 }
3252
3253 return SCIP_OKAY;
3254}
3255
3256/** compares enfodata by enforcement priority of nonlinear handler
3257 *
3258 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3259 */
3260static
3283
3284/** install nlhdlrs in one expression */
3285static
3287 SCIP* scip, /**< SCIP data structure */
3288 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3289 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3290 )
3291{
3292 SCIP_EXPR_OWNERDATA* ownerdata;
3293 SCIP_CONSHDLRDATA* conshdlrdata;
3299 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3300 int enfossize; /* allocated length of expr->enfos array */
3301 int h;
3302
3303 assert(expr != NULL);
3304
3305 ownerdata = SCIPexprGetOwnerData(expr);
3306 assert(ownerdata != NULL);
3307
3308 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3309 assert(conshdlrdata != NULL);
3310 assert(conshdlrdata->auxvarid >= 0);
3311 assert(!conshdlrdata->indetect);
3312
3313 /* there should be no enforcer yet and detection should not even have considered expr yet */
3314 assert(ownerdata->nenfos < 0);
3315 assert(ownerdata->enfos == NULL);
3316
3317 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3318 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3319 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3320 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3321 * - if no one uses activity, then do not need activity methods
3322 */
3324 if( ownerdata->nauxvaruses == 0 )
3326 else
3327 {
3328 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3330 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3332 }
3333 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3335
3336 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3338
3339 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3341
3342 ownerdata->nenfos = 0;
3343 enfossize = 2;
3344 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3345 conshdlrdata->indetect = TRUE;
3346
3347 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3348 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3349 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3350 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3351 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3352
3353 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3354 {
3355 SCIP_NLHDLR* nlhdlr;
3356
3357 nlhdlr = conshdlrdata->nlhdlrs[h];
3358 assert(nlhdlr != NULL);
3359
3360 /* skip disabled nlhdlrs */
3361 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3362 continue;
3363
3364 /* call detect routine of nlhdlr */
3365 nlhdlrexprdata = NULL;
3368 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3369 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3370 /* coverity[var_deref_model] */
3371 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3372
3373 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3375
3376 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3378
3379 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3380 * They are also cleaned up here to ensure that only the needed methods are claimed.
3381 */
3383
3384 /* nlhdlr needs to participate for the methods it is enforcing */
3386
3388 {
3389 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3390 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3391
3392 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3393 if( nlhdlrexprdata != NULL )
3394 {
3395 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3396 }
3397 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3399
3400 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3401
3402 continue;
3403 }
3404
3405 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3406 SCIPnlhdlrGetName(nlhdlr),
3407 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3408 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3409 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3410
3411 /* store nlhdlr and its data */
3412 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3413 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3414 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3415 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3416 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3417 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3418 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3419 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3420 ownerdata->nenfos++;
3421
3422 /* update enforcement flags */
3424 }
3425
3426 conshdlrdata->indetect = FALSE;
3427
3428 /* stop if an enforcement method is missing but we are already in solving stage
3429 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3430 */
3432 {
3433 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3434 return SCIP_ERROR;
3435 }
3436
3437 assert(ownerdata->nenfos > 0);
3438
3439 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3440 if( ownerdata->nenfos > 1 )
3441 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3442
3443 /* resize enfos array to be nenfos long */
3444 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3445
3446 return SCIP_OKAY;
3447}
3448
3449/** detect nlhdlrs that can handle the expressions */
3450static
3452 SCIP* scip, /**< SCIP data structure */
3453 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3454 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3455 int nconss /**< total number of constraints */
3456 )
3457{
3458 SCIP_CONSHDLRDATA* conshdlrdata;
3459 SCIP_CONSDATA* consdata;
3460 SCIP_EXPR* expr;
3461 SCIP_EXPR_OWNERDATA* ownerdata;
3463 int i;
3464
3465 assert(conss != NULL || nconss == 0);
3466 assert(nconss >= 0);
3467 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 */
3468
3469 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3470 assert(conshdlrdata != NULL);
3471
3474
3476 {
3477 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3478 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3479 */
3481 conshdlrdata->globalbounds = TRUE;
3482 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3483 }
3484
3485 for( i = 0; i < nconss; ++i )
3486 {
3487 assert(conss != NULL && conss[i] != NULL);
3488
3489 consdata = SCIPconsGetData(conss[i]);
3490 assert(consdata != NULL);
3491 assert(consdata->expr != NULL);
3492
3493 /* if a constraint is separated, we currently need it to be initial, too
3494 * this is because INITLP will create the auxiliary variables that are used for any separation
3495 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3496 */
3497 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3498
3499 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3500 assert(ownerdata != NULL);
3501
3502 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3503 * then we would normally skip to run DETECT again
3504 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3505 * thus, if expr is the root expression, we rerun DETECT
3506 */
3507 if( ownerdata->nenfos > 0 )
3508 {
3509 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3510 assert(ownerdata->nenfos < 0);
3511 }
3512
3513 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3514 * this way we can treat the root expression like any other expression when enforcing via separation
3515 * if constraint will be propagated, then register activity usage of root expression
3516 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3517 */
3518 conshdlrdata->indetect = TRUE;
3521 SCIPconsIsPropagated(conss[i]),
3522 FALSE, FALSE) );
3523 conshdlrdata->indetect = FALSE;
3524
3525 /* compute integrality information for all subexpressions */
3526 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3527
3528 /* run detectNlhdlr on all expr where required */
3529 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3530 {
3531 ownerdata = SCIPexprGetOwnerData(expr);
3532 assert(ownerdata != NULL);
3533
3534 /* skip exprs that we already looked at */
3535 if( ownerdata->nenfos >= 0 )
3536 continue;
3537
3538 /* if there is use of the auxvar, then someone requires that
3539 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3540 * thus, we need to find nlhdlrs that separate or estimate
3541 * if there is use of the activity, then there is someone requiring that
3542 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3543 * thus, we need to find nlhdlrs that do interval-evaluation
3544 */
3545 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3546 {
3547 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3548
3549 assert(ownerdata->nenfos >= 0);
3550 }
3551 else
3552 {
3553 /* remember that we looked at this expression during detectNlhdlrs
3554 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3555 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3556 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3557 */
3558 ownerdata->nenfos = 0;
3559 }
3560 }
3561
3562 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3563 if( SCIPconsIsPropagated(conss[i]) )
3564 consdata->ispropagated = FALSE;
3565 }
3566
3568 {
3569 /* ensure that the local bounds are used again when reevaluating the expressions later;
3570 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3571 */
3573 conshdlrdata->globalbounds = FALSE;
3574 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3575 }
3576 else
3577 {
3578 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3580 }
3581
3583
3584 return SCIP_OKAY;
3585}
3586
3587/** initializes (pre)solving data of constraints
3588 *
3589 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3590 * not be modified.
3591 * In particular, this function
3592 * - runs the detection method of nlhldrs
3593 * - looks for unlocked linear variables
3594 * - checks curvature (if not in presolve)
3595 * - creates and add row to NLP (if not in presolve)
3596 *
3597 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3598 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3599 */
3600static
3602 SCIP* scip, /**< SCIP data structure */
3603 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3604 SCIP_CONS** conss, /**< constraints */
3605 int nconss /**< number of constraints */
3606 )
3607{
3608 int c;
3609
3610 for( c = 0; c < nconss; ++c )
3611 {
3612 /* check for a linear variable that can be increase or decreased without harming feasibility */
3613 findUnlockedLinearVar(scip, conss[c]);
3614
3616 {
3617 SCIP_CONSDATA* consdata;
3618 SCIP_Bool success = FALSE;
3619
3620 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3621 assert(consdata != NULL);
3622 assert(consdata->expr != NULL);
3623
3624 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3625 {
3626 /* call the curvature detection algorithm of the convex nonlinear handler
3627 * Check only for those curvature that may result in a convex inequality, i.e.,
3628 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3629 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3630 */
3631 if( !SCIPisInfinity(scip, -consdata->lhs) )
3632 {
3634 if( success )
3635 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3636 }
3637 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3638 {
3640 if( success )
3641 consdata->curv = SCIP_EXPRCURV_CONVEX;
3642 }
3643 }
3644 else
3645 {
3646 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3647 {
3648 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3649 consdata->curv = SCIP_EXPRCURV_LINEAR;
3650 }
3651 else
3652 {
3653 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3654 }
3655 }
3656 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3657
3658 /* add nlrow representation to NLP, if NLP had been constructed */
3660 {
3661 if( consdata->nlrow == NULL )
3662 {
3663 SCIP_CALL( createNlRow(scip, conss[c]) );
3664 assert(consdata->nlrow != NULL);
3665 }
3666 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3667 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3668 }
3669 }
3670 }
3671
3672 /* register non linear handlers */
3673 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3674
3675 return SCIP_OKAY;
3676}
3677
3678/** deinitializes (pre)solving data of constraints
3679 *
3680 * This removes the initialization data created in initSolve().
3681 *
3682 * This function can be called in presolve and solve.
3683 *
3684 * TODO At the moment, it should not be called for a constraint if there are other constraints
3685 * that use the same expressions but still require their nlhdlr.
3686 * We should probably only decrement the auxvar and activity usage for the root expr and then
3687 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3688 */
3689static
3691 SCIP* scip, /**< SCIP data structure */
3692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3693 SCIP_CONS** conss, /**< constraints */
3694 int nconss /**< number of constraints */
3695 )
3696{
3698 SCIP_EXPR* expr;
3699 SCIP_CONSDATA* consdata;
3700 SCIP_Bool rootactivityvalid;
3701 int c;
3702
3706
3707 /* call deinitialization callbacks of expression and nonlinear handlers
3708 * free nonlinear handlers information from expressions
3709 * remove auxiliary variables and nactivityuses counts from expressions
3710 */
3711 for( c = 0; c < nconss; ++c )
3712 {
3713 assert(conss != NULL);
3714 assert(conss[c] != NULL);
3715
3716 consdata = SCIPconsGetData(conss[c]);
3717 assert(consdata != NULL);
3718 assert(consdata->expr != NULL);
3719
3720 /* check and remember whether activity in root is valid */
3721 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3722
3723 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3724 {
3725 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3726
3727 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3728 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3729
3730 /* remove quadratic info */
3732
3733 if( rootactivityvalid )
3734 {
3735 /* ensure activity is valid if consdata->expr activity is valid
3736 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3737 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3738 * so this childs activity would be invalid, which can generate confusion
3739 */
3741 }
3742 }
3743
3744 if( consdata->nlrow != NULL )
3745 {
3746 /* remove row from NLP, if still in solving
3747 * if we are in exitsolve, the whole NLP will be freed anyway
3748 */
3750 {
3751 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3752 }
3753
3754 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3755 }
3756
3757 /* forget about linear variables that can be increased or decreased without harming feasibility */
3758 consdata->linvardecr = NULL;
3759 consdata->linvarincr = NULL;
3760
3761 /* forget about curvature */
3762 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3763 }
3764
3766
3767 return SCIP_OKAY;
3768}
3769
3770/** helper method to decide whether a given expression is product of at least two binary variables */
3771static
3773 SCIP* scip, /**< SCIP data structure */
3774 SCIP_EXPR* expr /**< expression */
3775 )
3776{
3777 int i;
3778
3779 assert(expr != NULL);
3780
3781 /* check whether the expression is a product */
3782 if( !SCIPisExprProduct(scip, expr) )
3783 return FALSE;
3784
3785 /* don't consider products with a coefficient != 1 and products with a single child
3786 * simplification will take care of this expression later
3787 */
3788 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3789 return FALSE;
3790
3791 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3792 {
3793 SCIP_EXPR* child;
3794 SCIP_VAR* var;
3795 SCIP_Real ub;
3796 SCIP_Real lb;
3797
3798 child = SCIPexprGetChildren(expr)[i];
3799 assert(child != NULL);
3800
3801 if( !SCIPisExprVar(scip, child) )
3802 return FALSE;
3803
3804 var = SCIPgetVarExprVar(child);
3805 lb = SCIPvarGetLbLocal(var);
3806 ub = SCIPvarGetUbLocal(var);
3807
3808 /* check whether variable is integer and has [0,1] as variable bounds */
3809 if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3810 return FALSE;
3811 }
3812
3813 return TRUE;
3814}
3815
3816/** helper method to collect all bilinear binary product terms */
3817static
3819 SCIP* scip, /**< SCIP data structure */
3820 SCIP_EXPR* sumexpr, /**< sum expression */
3821 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3822 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3823 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3824 int* nterms /**< pointer to store the total number of bilinear binary terms */
3825 )
3826{
3827 int i;
3828
3829 assert(sumexpr != NULL);
3831 assert(xs != NULL);
3832 assert(ys != NULL);
3833 assert(childidxs != NULL);
3834 assert(nterms != NULL);
3835
3836 *nterms = 0;
3837
3838 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3839 {
3840 SCIP_EXPR* child;
3841
3842 child = SCIPexprGetChildren(sumexpr)[i];
3843 assert(child != NULL);
3844
3845 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3846 {
3849
3850 assert(x != NULL);
3851 assert(y != NULL);
3852
3853 if( x != y )
3854 {
3855 xs[*nterms] = x;
3856 ys[*nterms] = y;
3857 childidxs[*nterms] = i;
3858 ++(*nterms);
3859 }
3860 }
3861 }
3862
3863 return SCIP_OKAY;
3864}
3865
3866/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3867static
3869 SCIP* scip, /**< SCIP data structure */
3870 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3871 SCIP_CONS* cons, /**< constraint */
3872 SCIP_VAR* facvar, /**< variable that has been factorized */
3873 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3874 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3875 int nvars, /**< total number of variables in sum_j c_ij x_j */
3876 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3877 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3878 )
3879{
3880 SCIP_VAR* auxvar;
3882 SCIP_Real minact = 0.0;
3883 SCIP_Real maxact = 0.0;
3884 SCIP_Bool integral = TRUE;
3885 char name [SCIP_MAXSTRLEN];
3886 int i;
3887
3888 assert(facvar != NULL);
3889 assert(vars != NULL);
3890 assert(nvars > 1);
3891 assert(newexpr != NULL);
3892
3893 /* compute minimum and maximum activity of sum_j c_ij x_j */
3894 /* 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 */
3895 for( i = 0; i < nvars; ++i )
3896 {
3897 minact += MIN(coefs[i], 0.0);
3898 maxact += MAX(coefs[i], 0.0);
3899 integral = integral && SCIPisIntegral(scip, coefs[i]);
3900 }
3901 assert(minact <= maxact);
3902
3903 /* create and add auxiliary variable */
3904 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3906 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3907
3908 /* create and add z - maxact x <= 0 */
3909 if( !SCIPisZero(scip, maxact) )
3910 {
3911 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3915 if( naddconss != NULL )
3916 ++(*naddconss);
3917 }
3918
3919 /* create and add 0 <= z - minact x */
3920 if( !SCIPisZero(scip, minact) )
3921 {
3922 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3926 if( naddconss != NULL )
3927 ++(*naddconss);
3928 }
3929
3930 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3931 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3933 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3934 if( !SCIPisZero(scip, minact) )
3935 {
3937 }
3940 if( naddconss != NULL )
3941 ++(*naddconss);
3942
3943 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
3944 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3946 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3947 if( !SCIPisZero(scip, maxact) )
3948 {
3950 }
3953 if( naddconss != NULL )
3954 ++(*naddconss);
3955
3956 /* create variable expression */
3957 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
3958
3959 /* release auxvar */
3960 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3961
3962 return SCIP_OKAY;
3963}
3964
3965/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3966static
3968 SCIP* scip, /**< SCIP data structure */
3969 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3970 SCIP_CONS* cons, /**< constraint */
3971 SCIP_EXPR* sumexpr, /**< expression */
3972 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
3973 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
3974 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3975 )
3976{
3977 SCIP_EXPR** exprs = NULL;
3978 SCIP_VAR** tmpvars = NULL;
3979 SCIP_VAR** vars = NULL;
3980 SCIP_VAR** xs = NULL;
3981 SCIP_VAR** ys = NULL;
3982 SCIP_Real* exprcoefs = NULL;
3983 SCIP_Real* tmpcoefs = NULL;
3984 SCIP_Real* sumcoefs;
3985 SCIP_Bool* isused = NULL;
3986 int* childidxs = NULL;
3987 int* count = NULL;
3988 int nchildren;
3989 int nexprs = 0;
3990 int nterms;
3991 int nvars;
3992 int ntotalvars;
3993 int i;
3994
3995 assert(sumexpr != NULL);
3996 assert(minterms > 1);
3997 assert(newexpr != NULL);
3998
3999 *newexpr = NULL;
4000
4001 /* check whether sumexpr is indeed a sum */
4002 if( !SCIPisExprSum(scip, sumexpr) )
4003 return SCIP_OKAY;
4004
4005 nchildren = SCIPexprGetNChildren(sumexpr);
4009
4010 /* check whether there are enough terms available */
4011 if( nchildren < minterms )
4012 return SCIP_OKAY;
4013
4014 /* allocate memory */
4015 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4016 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4018
4019 /* collect all bilinear binary product terms */
4021
4022 /* check whether there are enough terms available */
4023 if( nterms < minterms )
4024 goto TERMINATE;
4025
4026 /* store how often each variable appears in a bilinear binary product */
4030
4031 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4035
4036 for( i = 0; i < nterms; ++i )
4037 {
4038 int xidx;
4039 int yidx;
4040
4041 assert(xs[i] != NULL);
4042 assert(ys[i] != NULL);
4043
4044 xidx = SCIPvarGetIndex(xs[i]);
4046 yidx = SCIPvarGetIndex(ys[i]);
4048
4049 ++count[xidx];
4050 ++count[yidx];
4051
4052 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4053 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4054 }
4055
4056 /* sort variables; don't change order of count array because it depends on problem indices */
4057 {
4058 int* tmpcount;
4059
4063 }
4064
4065 for( i = 0; i < nvars; ++i )
4066 {
4067 SCIP_VAR* facvar = vars[i];
4068 int ntmpvars = 0;
4069 int j;
4070
4071 /* skip candidate if there are not enough terms left */
4072 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4073 continue;
4074
4075 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4076
4077 /* collect variables for x_i * sum_j c_ij x_j */
4078 for( j = 0; j < nterms; ++j )
4079 {
4080 int childidx = childidxs[j];
4081 assert(childidx >= 0 && childidx < nchildren);
4082
4083 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4084 {
4085 SCIP_Real coef;
4086 int xidx;
4087 int yidx;
4088
4089 coef = sumcoefs[childidx];
4090 assert(coef != 0.0);
4091
4092 /* collect corresponding variable */
4093 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4094 tmpcoefs[ntmpvars] = coef;
4095 ++ntmpvars;
4096
4097 /* update counters */
4098 xidx = SCIPvarGetIndex(xs[j]);
4100 yidx = SCIPvarGetIndex(ys[j]);
4102 --count[xidx];
4103 --count[yidx];
4104 assert(count[xidx] >= 0);
4105 assert(count[yidx] >= 0);
4106
4107 /* mark term to be used */
4108 isused[childidx] = TRUE;
4109 }
4110 }
4113 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4114
4115 /* create required constraints and store the generated expression */
4116 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4117 exprcoefs[nexprs] = 1.0;
4118 ++nexprs;
4119 }
4120
4121 /* factorization was only successful if at least one expression has been generated */
4122 if( nexprs > 0 )
4123 {
4124 int nexprsold = nexprs;
4125
4126 /* add all children of the sum that have not been used */
4127 for( i = 0; i < nchildren; ++i )
4128 {
4129 if( !isused[i] )
4130 {
4131 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4132 exprcoefs[nexprs] = sumcoefs[i];
4133 ++nexprs;
4134 }
4135 }
4136
4137 /* create a new sum expression */
4139
4140 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4141 for( i = 0; i < nexprsold; ++i )
4142 {
4143 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4144 }
4145 }
4146
4147TERMINATE:
4148 /* free memory */
4150 SCIPfreeBufferArrayNull(scip, &tmpvars);
4159
4160 return SCIP_OKAY;
4161}
4162
4163/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4164static
4166 SCIP* scip, /**< SCIP data structure */
4167 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4168 SCIP_EXPR* prodexpr, /**< product expression */
4169 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4170 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4171 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4172 )
4173{
4174 SCIP_VAR** vars;
4175 SCIP_CONS* cons;
4176 SCIP_Real* coefs;
4177 SCIP_VAR* w;
4178 char* name;
4179 int nchildren;
4180 int i;
4181
4182 assert(conshdlr != NULL);
4183 assert(prodexpr != NULL);
4184 assert(SCIPisExprProduct(scip, prodexpr));
4185 assert(newexpr != NULL);
4186
4187 nchildren = SCIPexprGetNChildren(prodexpr);
4188 assert(nchildren >= 2);
4189
4190 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4191 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4192 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4193 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4194
4195 /* prepare the names of the variable and the constraints */
4196 /* coverity[secure_coding] */
4197 strcpy(name, "binreform");
4198 for( i = 0; i < nchildren; ++i )
4199 {
4201 coefs[i] = 1.0;
4202 assert(vars[i] != NULL);
4203 (void) strcat(name, "_");
4204 (void) strcat(name, SCIPvarGetName(vars[i]));
4205 }
4206
4207 /* create and add variable */
4208 SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4210 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4211
4212 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4213 if( nchildren == 2 && !empathy4and )
4214 {
4215 SCIP_VAR* x = vars[0];
4216 SCIP_VAR* y = vars[1];
4217
4218 assert(x != NULL);
4219 assert(y != NULL);
4220 assert(x != y);
4221
4222 /* create and add x - w >= 0 */
4223 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4224 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4225 SCIP_CALL( SCIPaddCons(scip, cons) );
4226 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4227
4228 /* create and add y - w >= 0 */
4229 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4230 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4231 SCIP_CALL( SCIPaddCons(scip, cons) );
4232 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4233
4234 /* create and add x + y - w <= 1 */
4235 vars[2] = w;
4236 coefs[2] = -1.0;
4237 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4238 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4239 SCIP_CALL( SCIPaddCons(scip, cons) );
4240 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4241
4242 /* update number of added constraints */
4243 if( naddconss != NULL )
4244 *naddconss += 3;
4245 }
4246 else
4247 {
4248 /* create, add, and release AND constraint */
4249 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4250 SCIP_CALL( SCIPaddCons(scip, cons) );
4251 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4252 SCIPdebugMsg(scip, " create AND constraint\n");
4253
4254 /* update number of added constraints */
4255 if( naddconss != NULL )
4256 *naddconss += 1;
4257 }
4258
4259 /* create variable expression */
4260 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4261
4262 /* release created variable */
4264
4265 /* free memory */
4266 SCIPfreeBufferArray(scip, &name);
4267 SCIPfreeBufferArray(scip, &coefs);
4269
4270 return SCIP_OKAY;
4271}
4272
4273/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4274static
4276 SCIP* scip, /**< SCIP data structure */
4277 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4278 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4279 SCIP_EXPR* prodexpr, /**< product expression */
4280 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4281 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4282 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4283 )
4284{
4285 SCIP_CONSHDLRDATA* conshdlrdata;
4286 int nchildren;
4287
4288 assert(prodexpr != NULL);
4289 assert(newexpr != NULL);
4290
4291 *newexpr = NULL;
4292
4293 /* only consider products of binary variables */
4294 if( !isBinaryProduct(scip, prodexpr) )
4295 return SCIP_OKAY;
4296
4297 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4298 assert(conshdlrdata != NULL);
4299 nchildren = SCIPexprGetNChildren(prodexpr);
4300 assert(nchildren >= 2);
4301
4302 /* check whether there is already an expression that represents the product */
4303 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4304 {
4305 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4306 assert(*newexpr != NULL);
4307
4308 /* capture expression */
4310 }
4311 else
4312 {
4313 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4314
4315 if( nchildren == 2 )
4316 {
4318 SCIP_VAR* x;
4319 SCIP_VAR* y;
4320 SCIP_Bool found_clique = FALSE;
4321 int c;
4322
4323 /* get variables from the product expression */
4324 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4325 assert(x != NULL);
4326 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4327 assert(y != NULL);
4328 assert(x != y);
4329
4330 /* first try to find a clique containing both variables */
4332
4333 /* look in cliques containing x */
4334 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4335 {
4336 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4337 {
4338 /* create zero value expression */
4339 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4340
4341 if( nchgcoefs != NULL )
4342 *nchgcoefs += 1;
4343
4345 break;
4346 }
4347
4348 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4349 {
4350 /* create variable expression for x */
4351 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4352
4353 if( nchgcoefs != NULL )
4354 *nchgcoefs += 2;
4355
4357 break;
4358 }
4359 }
4360
4361 if( !found_clique )
4362 {
4364
4365 /* look in cliques containing complement of x */
4366 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4367 {
4368 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4369 {
4370 /* create variable expression for y */
4371 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4372
4373 if( nchgcoefs != NULL )
4374 *nchgcoefs += 1;
4375
4377 break;
4378 }
4379
4380 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4381 {
4382 /* create sum expression */
4384 SCIP_Real sum_coefs[2];
4385 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4386 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4387 sum_coefs[0] = 1.0;
4388 sum_coefs[1] = 1.0;
4390
4393
4394 if( nchgcoefs != NULL )
4395 *nchgcoefs += 3;
4396
4398 break;
4399 }
4400 }
4401 }
4402
4403 /* if the variables are not in a clique, do standard linearization */
4404 if( !found_clique )
4405 {
4406 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4407 }
4408 }
4409 else
4410 {
4411 /* linearize binary product using an AND constraint because nchildren > 2 */
4412 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4413 }
4414
4415 /* hash variable expression */
4416 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4417 }
4418
4419 return SCIP_OKAY;
4420}
4421
4422/** helper function to replace binary products in a given constraint */
4423static
4425 SCIP* scip, /**< SCIP data structure */
4426 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4427 SCIP_CONS* cons, /**< constraint */
4428 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4429 SCIP_EXPRITER* it, /**< expression iterator */
4430 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4431 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4432 )
4433{
4434 SCIP_CONSHDLRDATA* conshdlrdata;
4435 SCIP_CONSDATA* consdata;
4436 SCIP_EXPR* expr;
4437
4438 assert(conshdlr != NULL);
4439 assert(cons != NULL);
4440 assert(exprmap != NULL);
4441 assert(it != NULL);
4442
4443 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4444 assert(conshdlrdata != NULL);
4445
4446 consdata = SCIPconsGetData(cons);
4447 assert(consdata != NULL);
4448 assert(consdata->expr != NULL);
4449
4450 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4451
4452 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4453 {
4456 int childexpridx;
4457
4461 assert(childexpr != NULL);
4462
4463 /* try to factorize variables in a sum expression that contains several products of binary variables */
4464 if( conshdlrdata->reformbinprodsfac > 1 )
4465 {
4466 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4467 }
4468
4469 /* try to create an expression that represents a product of binary variables */
4470 if( newexpr == NULL )
4471 {
4472 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4473 }
4474
4475 if( newexpr != NULL )
4476 {
4477 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4478
4479 /* replace product expression */
4481
4482 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4484
4485 /* mark the constraint to not be simplified anymore */
4486 consdata->issimplified = FALSE;
4487 }
4488 }
4489
4490 return SCIP_OKAY;
4491}
4492
4493/** reformulates products of binary variables during presolving in the following way:
4494 *
4495 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4496 * 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}:
4497 * \f[
4498 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4499 * \f]
4500 *
4501 * 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$.
4502 * These cliques allow for a better reformulation. There are four cases:
4503 *
4504 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4505 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4506 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4507 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4508 *
4509 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4510 *
4511 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4512 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4513 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4514 * Such a lower sum is reformulated with only one extra variable w_i:
4515 * \f{align}{
4516 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4517 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4518 * \text{minact}\, x_i & \leq w_i, \\
4519 * w_i &\leq \text{maxact}\, x_i, \\
4520 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4521 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4522 * \f}
4523 * 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
4524 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4525 * of terms are prioritized.
4526 */
4527static
4529 SCIP* scip, /**< SCIP data structure */
4530 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4531 SCIP_CONS** conss, /**< constraints */
4532 int nconss, /**< total number of constraints */
4533 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4534 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4535 )
4536{
4537 SCIP_CONSHDLRDATA* conshdlrdata;
4538 SCIP_HASHMAP* exprmap;
4540 int c;
4541
4542 assert(conshdlr != NULL);
4543
4544 /* no nonlinear constraints or binary variables -> skip */
4545 if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4546 return SCIP_OKAY;
4547 assert(conss != NULL);
4548
4549 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4550 assert(conshdlrdata != NULL);
4551
4552 /* create expression hash map */
4554
4555 /* create expression iterator */
4559
4560 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4561
4562 for( c = 0; c < nconss; ++c )
4563 {
4564 SCIP_CONSDATA* consdata;
4566
4567 assert(conss[c] != NULL);
4568
4569 consdata = SCIPconsGetData(conss[c]);
4570 assert(consdata != NULL);
4571
4572 /* try to reformulate the root expression */
4573 if( conshdlrdata->reformbinprodsfac > 1 )
4574 {
4575 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4576 }
4577
4578 /* release the root node if another expression has been found */
4579 if( newexpr != NULL )
4580 {
4581 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4582 consdata->expr = newexpr;
4583
4584 /* mark constraint to be not simplified anymore */
4585 consdata->issimplified = FALSE;
4586 }
4587
4588 /* replace each product of binary variables separately */
4589 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4590 }
4591
4592 /* free memory */
4593 SCIPhashmapFree(&exprmap);
4595
4596 return SCIP_OKAY;
4597}
4598
4599/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4600 *
4601 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4602 * Then scale by -1 if
4603 * - \f$n_+ < n_-\f$, or
4604 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4605 */
4606static
4608 SCIP* scip, /**< SCIP data structure */
4609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4610 SCIP_CONS* cons, /**< nonlinear constraint */
4611 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4612 )
4613{
4614 SCIP_CONSDATA* consdata;
4615 int i;
4616
4617 assert(cons != NULL);
4618
4619 consdata = SCIPconsGetData(cons);
4620 assert(consdata != NULL);
4621
4622 if( SCIPisExprSum(scip, consdata->expr) )
4623 {
4624 SCIP_Real* coefs;
4625 SCIP_Real constant;
4626 int nchildren;
4627 int counter = 0;
4628
4629 coefs = SCIPgetCoefsExprSum(consdata->expr);
4630 constant = SCIPgetConstantExprSum(consdata->expr);
4631 nchildren = SCIPexprGetNChildren(consdata->expr);
4632
4633 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4634 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4635 {
4636 SCIP_EXPR* expr;
4637 expr = consdata->expr;
4638
4639 consdata->expr = SCIPexprGetChildren(expr)[0];
4640 assert(!SCIPisExprSum(scip, consdata->expr));
4641
4642 SCIPcaptureExpr(consdata->expr);
4643
4644 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4645 consdata->lhs = -consdata->lhs;
4646 consdata->rhs = -consdata->rhs;
4647
4648 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4649 *changed = TRUE;
4650 return SCIP_OKAY;
4651 }
4652
4653 /* compute n_+ - n_i */
4654 for( i = 0; i < nchildren; ++i )
4655 counter += coefs[i] > 0 ? 1 : -1;
4656
4657 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4658 {
4659 SCIP_EXPR* expr;
4660 SCIP_Real* newcoefs;
4661
4662 /* allocate memory */
4664
4665 for( i = 0; i < nchildren; ++i )
4666 newcoefs[i] = -coefs[i];
4667
4668 /* create a new sum expression */
4669 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4670
4671 /* replace expression in constraint data and scale sides */
4672 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4673 consdata->expr = expr;
4674 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4675 consdata->lhs = -consdata->lhs;
4676 consdata->rhs = -consdata->rhs;
4677
4678 /* free memory */
4680
4681 *changed = TRUE;
4682 }
4683 }
4684
4685 return SCIP_OKAY;
4686}
4687
4688/** forbid multiaggrations of variables that appear nonlinear in constraints */
4689static
4691 SCIP* scip, /**< SCIP data structure */
4692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4693 SCIP_CONS** conss, /**< constraints */
4694 int nconss /**< number of constraints */
4695 )
4696{
4698 SCIP_CONSDATA* consdata;
4699 SCIP_EXPR* expr;
4700 int c;
4701
4702 assert(scip != NULL);
4703 assert(conshdlr != NULL);
4704
4705 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4706 return SCIP_OKAY;
4707
4710
4711 for( c = 0; c < nconss; ++c )
4712 {
4713 consdata = SCIPconsGetData(conss[c]);
4714 assert(consdata != NULL);
4715
4716 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4717 * i.e., skip children of sum that are variables
4718 */
4719 if( SCIPisExprSum(scip, consdata->expr) )
4720 {
4721 int i;
4722 SCIP_EXPR* child;
4723 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4724 {
4725 child = SCIPexprGetChildren(consdata->expr)[i];
4726
4727 /* skip variable expression, as they correspond to a linear term */
4728 if( SCIPisExprVar(scip, child) )
4729 continue;
4730
4731 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4732 if( SCIPisExprVar(scip, expr) )
4733 {
4735 }
4736 }
4737 }
4738 else
4739 {
4740 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4741 if( SCIPisExprVar(scip, expr) )
4742 {
4744 }
4745 }
4746 }
4747
4749
4750 return SCIP_OKAY;
4751}
4752
4753/** simplifies expressions and replaces common subexpressions for a set of constraints
4754 * @todo put the constant to the constraint sides
4755 */
4756static
4758 SCIP* scip, /**< SCIP data structure */
4759 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4760 SCIP_CONS** conss, /**< constraints */
4761 int nconss, /**< total number of constraints */
4762 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4763 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4764 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4765 int* naddconss, /**< counter to add number of added constraints, or NULL */
4766 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4767 )
4768{
4769 SCIP_CONSHDLRDATA* conshdlrdata;
4770 SCIP_CONSDATA* consdata;
4771 int* nlockspos;
4772 int* nlocksneg;
4773 SCIP_Bool havechange;
4774 int i;
4775
4776 assert(scip != NULL);
4777 assert(conshdlr != NULL);
4778 assert(conss != NULL);
4779 assert(nconss > 0);
4780 assert(infeasible != NULL);
4781
4782 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4783 assert(conshdlrdata != NULL);
4784
4785 /* update number of canonicalize calls */
4786 ++(conshdlrdata->ncanonicalizecalls);
4787
4788 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4789
4790 *infeasible = FALSE;
4791
4792 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4793 havechange = conshdlrdata->ncanonicalizecalls == 1;
4794
4795 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4796 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4797
4798 /* allocate memory for storing locks of each constraint */
4799 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4800 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4801
4802 /* unlock all constraints */
4803 for( i = 0; i < nconss; ++i )
4804 {
4805 assert(conss[i] != NULL);
4806
4807 consdata = SCIPconsGetData(conss[i]);
4808 assert(consdata != NULL);
4809
4810 /* remember locks */
4811 nlockspos[i] = consdata->nlockspos;
4812 nlocksneg[i] = consdata->nlocksneg;
4813
4814 /* remove locks */
4815 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4816 assert(consdata->nlockspos == 0);
4817 assert(consdata->nlocksneg == 0);
4818 }
4819
4820#ifndef NDEBUG
4821 /* check whether all locks of each expression have been removed */
4822 for( i = 0; i < nconss; ++i )
4823 {
4824 SCIP_EXPR* expr;
4826
4828
4829 consdata = SCIPconsGetData(conss[i]);
4830 assert(consdata != NULL);
4831
4833 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4834 {
4835 assert(expr != NULL);
4836 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4837 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4838 }
4840 }
4841#endif
4842
4843 /* reformulate products of binary variables */
4844 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4845 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4846 {
4847 int tmpnaddconss = 0;
4848 int tmpnchgcoefs = 0;
4849
4850 /* call this function before simplification because expressions might not be simplified after reformulating
4851 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4852 */
4853 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4854
4855 /* update counters */
4856 if( naddconss != NULL )
4857 *naddconss = tmpnaddconss;
4858 if( nchgcoefs != NULL )
4859 *nchgcoefs = tmpnchgcoefs;
4860
4861 /* check whether at least one expression has changed */
4862 if( tmpnaddconss + tmpnchgcoefs > 0 )
4863 havechange = TRUE;
4864 }
4865
4866 for( i = 0; i < nconss; ++i )
4867 {
4868 consdata = SCIPconsGetData(conss[i]);
4869 assert(consdata != NULL);
4870
4871 /* call simplify for each expression */
4872 if( !consdata->issimplified && consdata->expr != NULL )
4873 {
4875 SCIP_Bool changed;
4876
4877 changed = FALSE;
4878 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4879 consdata->issimplified = TRUE;
4880
4881 if( changed )
4882 havechange = TRUE;
4883
4884 /* 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").
4885 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4886 */
4887 if( simplified != consdata->expr )
4888 {
4889 assert(changed);
4890
4891 /* release old expression */
4892 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4893
4894 /* store simplified expression */
4895 consdata->expr = simplified;
4896 }
4897 else
4898 {
4899 /* The simplify captures simplified in any case, also if nothing has changed.
4900 * Therefore, we have to release it here.
4901 */
4903 }
4904
4905 if( *infeasible )
4906 break;
4907
4908 /* scale constraint sides */
4909 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4910
4911 if( changed )
4912 havechange = TRUE;
4913
4914 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4915 if( SCIPisExprValue(scip, consdata->expr) )
4916 {
4917 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4918 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4919 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4920 {
4921 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4922 SCIPdebugPrintCons(scip, conss[i], NULL);
4923 *infeasible = TRUE;
4924 break;
4925 }
4926 else
4927 {
4928 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
4929 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
4930 if( ndelconss != NULL )
4931 ++*ndelconss;
4932 havechange = TRUE;
4933 }
4934 }
4935 }
4936 }
4937
4938 /* replace common subexpressions */
4939 if( havechange && !*infeasible )
4940 {
4941 SCIP_CONS** consssorted;
4943 SCIP_Bool replacedroot;
4944
4946 for( i = 0; i < nconss; ++i )
4947 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
4948
4950
4951 /* update pointer to root expr in constraints, if any has changed
4952 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
4953 */
4954 if( replacedroot )
4955 for( i = 0; i < nconss; ++i )
4956 SCIPconsGetData(conss[i])->expr = rootexprs[i];
4957
4959
4960 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
4961 * been changed after simplification; now we completely recollect all variable expression and variable events
4962 */
4963
4964 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
4965 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
4966 */
4967 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
4968 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
4969
4970 for( i = nconss-1; i >= 0; --i )
4971 {
4972 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
4973 if( SCIPconsIsDeleted(consssorted[i]) )
4974 continue;
4975
4976 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4977 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
4978 }
4979 for( i = 0; i < nconss; ++i )
4980 {
4981 if( SCIPconsIsDeleted(consssorted[i]) )
4982 continue;
4983
4984 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
4985 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4986 }
4987
4988 SCIPfreeBufferArray(scip, &consssorted);
4989
4990 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
4991 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
4992 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
4993 */
4994 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
4995 }
4996
4997 /* restore locks */
4998 for( i = 0; i < nconss; ++i )
4999 {
5000 if( SCIPconsIsDeleted(conss[i]) )
5001 continue;
5002
5003 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5004 }
5005
5006 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5007 * TODO can we skip this in presoltiming fast?
5008 */
5009 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5010 {
5011 /* reset one of the number of detections counter to count only current presolving round */
5012 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5013 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5014
5015 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5016 }
5017
5018 /* free allocated memory */
5019 SCIPfreeBufferArray(scip, &nlocksneg);
5020 SCIPfreeBufferArray(scip, &nlockspos);
5021
5022 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5023
5024 return SCIP_OKAY;
5025}
5026
5027/** merges constraints that have the same root expression */
5028static
5030 SCIP* scip, /**< SCIP data structure */
5031 SCIP_CONS** conss, /**< constraints to process */
5032 int nconss, /**< number of constraints */
5033 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5034 )
5035{
5037 SCIP_Bool* updatelocks;
5038 int* nlockspos;
5039 int* nlocksneg;
5040 int c;
5041
5042 assert(success != NULL);
5043
5044 *success = FALSE;
5045
5046 /* not enough constraints available */
5047 if( nconss <= 1 )
5048 return SCIP_OKAY;
5049
5051 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5052 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5053 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5054
5055 for( c = 0; c < nconss; ++c )
5056 {
5057 SCIP_CONSDATA* consdata;
5058
5059 /* ignore deleted constraints */
5060 if( SCIPconsIsDeleted(conss[c]) )
5061 continue;
5062
5063 consdata = SCIPconsGetData(conss[c]);
5064 assert(consdata != NULL);
5065
5066 /* add expression to the hash map if not seen so far */
5067 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5068 {
5069 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5070 }
5071 else
5072 {
5074 int idx;
5075
5076 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5077 assert(idx >= 0 && idx < nconss);
5078
5079 imgconsdata = SCIPconsGetData(conss[idx]);
5081 assert(imgconsdata->expr == consdata->expr);
5082
5083 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5084 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5085
5086 /* check whether locks need to be updated */
5087 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5088 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5089 {
5090 nlockspos[idx] = imgconsdata->nlockspos;
5091 nlocksneg[idx] = imgconsdata->nlocksneg;
5092 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5093 updatelocks[idx] = TRUE;
5094 }
5095
5096 /* update constraint sides */
5097 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5098 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5099
5100 /* delete constraint */
5101 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5102 *success = TRUE;
5103 }
5104 }
5105
5106 /* restore locks of updated constraints */
5107 if( *success )
5108 {
5109 for( c = 0; c < nconss; ++c )
5110 {
5111 if( updatelocks[c] )
5112 {
5113 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5114 }
5115 }
5116 }
5117
5118 /* free memory */
5119 SCIPfreeBufferArray(scip, &nlocksneg);
5120 SCIPfreeBufferArray(scip, &nlockspos);
5121 SCIPfreeBufferArray(scip, &updatelocks);
5123
5124 return SCIP_OKAY;
5125}
5126
5127/** interval evaluation of variables as used in redundancy check
5128 *
5129 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5130 */
5131static
5133{ /*lint --e{715}*/
5134 SCIP_CONSHDLRDATA* conshdlrdata;
5136 SCIP_Real lb;
5137 SCIP_Real ub;
5138
5139 assert(scip != NULL);
5140 assert(var != NULL);
5141
5142 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5143 assert(conshdlrdata != NULL);
5144
5145 if( conshdlrdata->globalbounds )
5146 {
5147 lb = SCIPvarGetLbGlobal(var);
5148 ub = SCIPvarGetUbGlobal(var);
5149 }
5150 else
5151 {
5152 lb = SCIPvarGetLbLocal(var);
5153 ub = SCIPvarGetUbLocal(var);
5154 }
5155 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5156
5157 /* relax variable bounds, if there are bounds and variable is not fixed
5158 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5159 */
5160 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5161 {
5162 if( !SCIPisInfinity(scip, -lb) )
5163 lb -= SCIPfeastol(scip);
5164
5165 if( !SCIPisInfinity(scip, ub) )
5166 ub += SCIPfeastol(scip);
5167 }
5168
5169 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5172 assert(lb <= ub);
5173
5175
5176 return interval;
5177}
5178
5179/** removes constraints that are always feasible or very simple
5180 *
5181 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5182 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5183 * might violate variable bounds by up to feastol, too.
5184 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5185 *
5186 * Also removes constraints of the form lhs &le; variable &le; rhs.
5187 *
5188 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5189 *
5190 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5191 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5192 * would appear as if the constraint is redundant.
5193 */
5194static
5196 SCIP* scip, /**< SCIP data structure */
5197 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5198 SCIP_CONS** conss, /**< constraints to propagate */
5199 int nconss, /**< total number of constraints */
5200 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5201 int* ndelconss, /**< buffer to add the number of deleted constraints */
5202 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5203 )
5204{
5205 SCIP_CONSHDLRDATA* conshdlrdata;
5206 SCIP_CONSDATA* consdata;
5207 SCIP_INTERVAL activity;
5209 int i;
5210
5211 assert(scip != NULL);
5212 assert(conshdlr != NULL);
5213 assert(conss != NULL);
5214 assert(nconss >= 0);
5215 assert(cutoff != NULL);
5216 assert(ndelconss != NULL);
5217 assert(nchgbds != NULL);
5218
5219 /* no constraints to check */
5220 if( nconss == 0 )
5221 return SCIP_OKAY;
5222
5223 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5224 assert(conshdlrdata != NULL);
5225
5226 /* increase curboundstag and set lastvaractivitymethodchange
5227 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5228 * for the redundancy check differently than for domain propagation
5229 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5230 */
5231 ++conshdlrdata->curboundstag;
5232 assert(conshdlrdata->curboundstag > 0);
5233 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5234 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5235 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5236
5237 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5238
5239 *cutoff = FALSE;
5240 for( i = 0; i < nconss; ++i )
5241 {
5242 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5243 continue;
5244
5245 consdata = SCIPconsGetData(conss[i]);
5246 assert(consdata != NULL);
5247
5248 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5249 if( SCIPisExprValue(scip, consdata->expr) )
5250 {
5251 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5252
5253 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5254 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5255 {
5256 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5257 *cutoff = TRUE;
5258
5259 goto TERMINATE;
5260 }
5261
5262 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5263
5264 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5265 ++*ndelconss;
5266
5267 continue;
5268 }
5269
5270 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5271 if( SCIPisExprVar(scip, consdata->expr) )
5272 {
5273 SCIP_VAR* var;
5274 SCIP_Bool tightened;
5275
5276 var = SCIPgetVarExprVar(consdata->expr);
5277 assert(var != NULL);
5278
5279 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);
5280
5281 /* ensure that variable bounds are within constraint sides */
5282 if( !SCIPisInfinity(scip, -consdata->lhs) )
5283 {
5284 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5285
5286 if( tightened )
5287 ++*nchgbds;
5288
5289 if( *cutoff )
5290 goto TERMINATE;
5291 }
5292
5293 if( !SCIPisInfinity(scip, consdata->rhs) )
5294 {
5295 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5296
5297 if( tightened )
5298 ++*nchgbds;
5299
5300 if( *cutoff )
5301 goto TERMINATE;
5302 }
5303
5304 /* delete the (now) redundant constraint locally */
5305 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5306 ++*ndelconss;
5307
5308 continue;
5309 }
5310
5311 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5312 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5313 * variable bounds by up to feastol
5314 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5315 */
5316 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5317 SCIPdebugPrintCons(scip, conss[i], NULL);
5318
5319 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5321
5322 /* it is unlikely that we detect infeasibility by doing forward propagation */
5323 if( *cutoff )
5324 {
5325 SCIPdebugMsg(scip, " -> cutoff\n");
5326 goto TERMINATE;
5327 }
5328
5329 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5330 activity = SCIPexprGetActivity(consdata->expr);
5331
5332 /* relax sides by feastol
5333 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5334 */
5336 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5337 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5338
5340 {
5341 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5342
5343 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5344 ++*ndelconss;
5345
5346 continue;
5347 }
5348
5349 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5350 }
5351
5352TERMINATE:
5353 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5354 ++conshdlrdata->curboundstag;
5355 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5356 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5357 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5358
5359 return SCIP_OKAY;
5360}
5361
5362/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5363static
5365 SCIP* scip, /**< SCIP data structure */
5366 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5367 SCIP_CONS* cons, /**< source constraint to try to convert */
5368 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5369 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5370 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5371 )
5372{
5373 SCIP_CONSHDLRDATA* conshdlrdata;
5374 SCIP_CONSDATA* consdata;
5376 int upgdconsssize;
5377 int nupgdconss_;
5378 int i;
5379
5380 assert(scip != NULL);
5381 assert(conshdlr != NULL);
5382 assert(cons != NULL);
5384 assert(upgraded != NULL);
5385 assert(nupgdconss != NULL);
5386 assert(naddconss != NULL);
5387
5388 *upgraded = FALSE;
5389
5390 nupgdconss_ = 0;
5391
5392 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5393 assert(conshdlrdata != NULL);
5394
5395 /* if there are no upgrade methods, we can stop */
5396 if( conshdlrdata->nconsupgrades == 0 )
5397 return SCIP_OKAY;
5398
5399 upgdconsssize = 2;
5401
5402 /* call the upgrading methods */
5403 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5405
5406 consdata = SCIPconsGetData(cons);
5407 assert(consdata != NULL);
5408
5409 /* try all upgrading methods in priority order in case the upgrading step is enable */
5410 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5411 {
5412 if( !conshdlrdata->consupgrades[i]->active )
5413 continue;
5414
5415 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5416
5417 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5418
5419 while( nupgdconss_ < 0 )
5420 {
5421 /* upgrade function requires more memory: resize upgdconss and call again */
5425
5426 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5427
5428 assert(nupgdconss_ != 0);
5429 }
5430
5431 if( nupgdconss_ > 0 )
5432 {
5433 /* got upgrade */
5434 int j;
5435
5436 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5437
5438 /* add the upgraded constraints to the problem and forget them */
5439 for( j = 0; j < nupgdconss_; ++j )
5440 {
5441 SCIPdebugMsgPrint(scip, "\t");
5443
5444 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5445 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5446 }
5447
5448 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5449 *nupgdconss += 1;
5450 *naddconss += nupgdconss_ - 1;
5451 *upgraded = TRUE;
5452
5453 /* delete upgraded constraint */
5454 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5455 SCIP_CALL( SCIPdelCons(scip, cons) );
5456
5457 break;
5458 }
5459 }
5460
5462
5463 return SCIP_OKAY;
5464}
5465
5466/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5467 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5468 * variable bounds, and is not binary
5469 */
5470static
5472 SCIP* scip, /**< SCIP data structure */
5473 SCIP_EXPR* expr /**< variable expression */
5474 )
5475{
5476 SCIP_VAR* var;
5477 SCIP_EXPR_OWNERDATA* ownerdata;
5478
5479 assert(SCIPisExprVar(scip, expr));
5480
5481 var = SCIPgetVarExprVar(expr);
5482 assert(var != NULL);
5483
5484 ownerdata = SCIPexprGetOwnerData(expr);
5485 assert(ownerdata != NULL);
5486
5487 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5488 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5489 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5493}
5494
5495/** removes all variable expressions that are contained in a given expression from a hash map */
5496static
5498 SCIP* scip, /**< SCIP data structure */
5499 SCIP_EXPR* expr, /**< expression */
5500 SCIP_EXPRITER* it, /**< expression iterator */
5501 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5502 )
5503{
5504 SCIP_EXPR* e;
5505
5507 {
5508 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5509 {
5511 }
5512 }
5513
5514 return SCIP_OKAY;
5515}
5516
5517/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5518 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5519 *
5520 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5521 * Otherwise, a bound disjunction constraint is added.
5522 *
5523 * @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
5524 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5525 * 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
5526 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5527 */
5528static
5530 SCIP* scip, /**< SCIP data structure */
5531 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5532 SCIP_CONS* cons, /**< nonlinear constraint */
5533 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5534 int* naddconss, /**< pointer to store the total number of added constraints */
5535 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5536 )
5537{
5538 SCIP_CONSHDLRDATA* conshdlrdata;
5539 SCIP_CONSDATA* consdata;
5542 SCIP_Bool hasbounddisj;
5543 SCIP_Bool haslhs;
5544 SCIP_Bool hasrhs;
5545 int nsinglelocked = 0;
5546 int i;
5547
5548 assert(conshdlr != NULL);
5549 assert(cons != NULL);
5550 assert(nchgvartypes != NULL);
5551 assert(naddconss != NULL);
5552 assert(infeasible != NULL);
5553
5554 *nchgvartypes = 0;
5555 *naddconss = 0;
5556 *infeasible = FALSE;
5557
5558 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5559 assert(conshdlrdata != NULL);
5560 consdata = SCIPconsGetData(cons);
5561 assert(consdata != NULL);
5562
5563 /* only consider constraints with one finite side */
5564 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5565 return SCIP_OKAY;
5566
5567 /* only consider sum expressions */
5568 if( !SCIPisExprSum(scip, consdata->expr) )
5569 return SCIP_OKAY;
5570
5571 /* remember which side is finite */
5572 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5573 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5574
5575 /* allocate memory */
5576 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5577 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5578
5579 /* check all variable expressions for single locked variables */
5580 for( i = 0; i < consdata->nvarexprs; ++i )
5581 {
5582 assert(consdata->varexprs[i] != NULL);
5583
5584 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5585 {
5586 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5587 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5588 }
5589 }
5590 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5591
5592 if( nsinglelocked > 0 )
5593 {
5594 SCIP_EXPR** children;
5596 int nchildren;
5597
5598 children = SCIPexprGetChildren(consdata->expr);
5599 nchildren = SCIPexprGetNChildren(consdata->expr);
5600
5601 /* create iterator */
5605
5606 for( i = 0; i < nchildren; ++i )
5607 {
5608 SCIP_EXPR* child;
5609 SCIP_Real coef;
5610
5611 child = children[i];
5612 assert(child != NULL);
5613 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5614
5615 /* ignore linear terms */
5616 if( SCIPisExprVar(scip, child) )
5617 continue;
5618
5619 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5620 * expression that represents f_j and remove each variable expression from exprcands
5621 */
5622 else if( SCIPisExprProduct(scip, child) )
5623 {
5624 int j;
5625
5626 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5627 {
5629
5631 {
5632 /* mark all variable expressions that are contained in the expression */
5634 }
5635 }
5636 }
5637 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5638 * for an integer k >= 1
5639 */
5640 else if( SCIPisExprPower(scip, child) )
5641 {
5643 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5644 SCIP_Bool valid;
5645
5646 /* check for even integral exponent */
5647 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5648
5649 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5650 {
5651 /* mark all variable expressions that are contained in the expression */
5653 }
5654 }
5655 /* all other cases cannot be handled */
5656 else
5657 {
5658 /* mark all variable expressions that are contained in the expression */
5660 }
5661 }
5662
5663 /* free expression iterator */
5665 }
5666
5667 /* check whether the bound disjunction constraint handler is available */
5668 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5669
5670 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5671 for( i = 0; i < nsinglelocked; ++i )
5672 {
5673 /* only consider expressions that are still contained in the exprcands map */
5675 {
5677 SCIP_VAR* vars[2];
5678 SCIP_BOUNDTYPE boundtypes[2];
5679 SCIP_Real bounds[2];
5680 char name[SCIP_MAXSTRLEN];
5681 SCIP_VAR* var;
5682
5684 assert(var != NULL);
5685 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5687
5688 /* try to change the variable type to binary */
5689 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5690 {
5693 ++(*nchgvartypes);
5694
5695 if( *infeasible )
5696 {
5697 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5698 break;
5699 }
5700 }
5701 /* add bound disjunction constraint if bounds of the variable are finite */
5703 {
5704 vars[0] = var;
5705 vars[1] = var;
5706 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5707 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5708 bounds[0] = SCIPvarGetUbGlobal(var);
5709 bounds[1] = SCIPvarGetLbGlobal(var);
5710
5711 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5712
5713 /* create, add, and release bound disjunction constraint */
5714 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5715 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5719 ++(*naddconss);
5720 }
5721 }
5722 }
5723
5724 /* free memory */
5727
5728 return SCIP_OKAY;
5729}
5730
5731/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5732static
5734 SCIP* scip, /**< SCIP data structure */
5735 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5736 SCIP_CONS** conss, /**< nonlinear constraints */
5737 int nconss, /**< total number of nonlinear constraints */
5738 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5739 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5740 )
5741{
5742 int c;
5743
5744 assert(scip != NULL);
5745 assert(conshdlr != NULL);
5746 assert(conss != NULL || nconss == 0);
5747 assert(nchgvartypes != NULL);
5748 assert(infeasible != NULL);
5749
5750 *infeasible = FALSE;
5751
5752 /* nothing can be done if there are no binary and integer variables available */
5753 if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5754 return SCIP_OKAY;
5755
5756 /* no continuous var can be made implicit-integer if there are no continuous variables */
5757 if( SCIPgetNContVars(scip) == 0 )
5758 return SCIP_OKAY;
5759
5760 for( c = 0; c < nconss; ++c )
5761 {
5762 SCIP_CONSDATA* consdata;
5763 SCIP_EXPR** children;
5764 int nchildren;
5765 SCIP_Real* coefs;
5766 SCIP_EXPR* cand = NULL;
5767 SCIP_Real candcoef = 0.0;
5768 int i;
5769
5770 assert(conss != NULL && conss[c] != NULL);
5771
5772 consdata = SCIPconsGetData(conss[c]);
5773 assert(consdata != NULL);
5774
5775 /* the constraint must be an equality constraint */
5776 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5777 continue;
5778
5779 /* the root expression needs to be a sum expression */
5780 if( !SCIPisExprSum(scip, consdata->expr) )
5781 continue;
5782
5783 children = SCIPexprGetChildren(consdata->expr);
5784 nchildren = SCIPexprGetNChildren(consdata->expr);
5785
5786 /* the sum expression must have at least two children
5787 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5788 */
5789 if( nchildren <= 1 )
5790 continue;
5791
5792 coefs = SCIPgetCoefsExprSum(consdata->expr);
5793
5794 /* find first continuous variable and get value of its coefficient */
5795 for( i = 0; i < nchildren; ++i )
5796 {
5797 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5798 continue;
5799
5800 candcoef = coefs[i];
5801 assert(candcoef != 0.0);
5802
5803 /* lhs/rhs - constant divided by candcoef must be integral
5804 * if not, break with cand == NULL, so give up
5805 */
5806 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5807 cand = children[i];
5808
5809 break;
5810 }
5811
5812 /* no suitable continuous variable found */
5813 if( cand == NULL )
5814 continue;
5815
5816 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5817 for( i = 0; i < nchildren; ++i )
5818 {
5819 if( children[i] == cand )
5820 continue;
5821
5822 /* child i must be integral */
5823 if( !SCIPexprIsIntegral(children[i]) )
5824 {
5825 cand = NULL;
5826 break;
5827 }
5828
5829 /* coefficient of child i must be integral if diving by candcoef */
5830 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5831 {
5832 cand = NULL;
5833 break;
5834 }
5835 }
5836
5837 if( cand == NULL )
5838 continue;
5839
5840 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5842
5843 /* change variable type */
5845
5846 if( *infeasible )
5847 return SCIP_OKAY;
5848
5849 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5851 }
5852
5853 return SCIP_OKAY;
5854}
5855
5856/** creates auxiliary variable for a given expression
5857 *
5858 * @note for a variable expression it does nothing
5859 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5860 */
5861static
5863 SCIP* scip, /**< SCIP data structure */
5864 SCIP_EXPR* expr /**< expression */
5865 )
5866{
5867 SCIP_EXPR_OWNERDATA* ownerdata;
5868 SCIP_CONSHDLRDATA* conshdlrdata;
5869 SCIP_VARTYPE vartype;
5870 SCIP_INTERVAL activity;
5871 char name[SCIP_MAXSTRLEN];
5872
5873 assert(scip != NULL);
5874 assert(expr != NULL);
5875
5876 ownerdata = SCIPexprGetOwnerData(expr);
5877 assert(ownerdata != NULL);
5878 assert(ownerdata->nauxvaruses > 0);
5879
5880 /* if we already have auxvar, then do nothing */
5881 if( ownerdata->auxvar != NULL )
5882 return SCIP_OKAY;
5883
5884 /* if expression is a variable-expression, then do nothing */
5885 if( SCIPisExprVar(scip, expr) )
5886 return SCIP_OKAY;
5887
5889 {
5890 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5891 return SCIP_INVALIDCALL;
5892 }
5893
5894 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5895 assert(conshdlrdata != NULL);
5896 assert(conshdlrdata->auxvarid >= 0);
5897
5898 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5899 * but it usually indicates a missing simplify
5900 * if we find situations where we need to have an auxvar for a constant, then remove this assert
5901 */
5902 assert(!SCIPisExprValue(scip, expr));
5903
5904 /* create and capture auxiliary variable */
5905 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5906 ++conshdlrdata->auxvarid;
5907
5908 /* type of auxiliary variable depends on integrality information of the expression */
5910
5911 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5912 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5913 {
5914 activity = SCIPexprGetActivity(expr);
5915 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5916 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5917 * and abort in debug mode only
5918 */
5920 {
5921 SCIPABORT();
5923 }
5924 }
5925 else
5927
5928 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
5929 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
5930 */
5931 if( SCIPgetDepth(scip) == 0 )
5932 {
5933 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
5934 }
5935 else
5936 {
5937 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
5938 }
5939
5940 /* mark the auxiliary variable to be added for the relaxation only
5941 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
5942 * or to copy the variable to a subscip
5943 */
5944 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
5945
5946 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
5947
5948 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
5949
5950 /* add variable locks in both directions
5951 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
5952 * but then we need to also update the auxvars locks when the expr locks change
5953 */
5954 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
5955
5956#ifdef WITH_DEBUG_SOLUTION
5958 {
5959 /* store debug solution value of auxiliary variable
5960 * assumes that expression has been evaluated in debug solution before
5961 */
5962 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
5963 }
5964#endif
5965
5966 if( SCIPgetDepth(scip) > 0 )
5967 {
5968 /* initialize local bounds to (locally valid) activity */
5969 SCIP_Bool cutoff;
5970 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
5971 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
5972 }
5973
5974 return SCIP_OKAY;
5975}
5976
5977/** initializes separation for constraint
5978 *
5979 * - ensures that activities are up to date in all expressions
5980 * - creates auxiliary variables where required
5981 * - calls propExprDomains() to possibly tighten auxvar bounds
5982 * - calls separation initialization callback of nlhdlrs
5983 */
5984static
5986 SCIP* scip, /**< SCIP data structure */
5987 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5988 SCIP_CONS** conss, /**< constraints */
5989 int nconss, /**< number of constraints */
5990 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
5991 )
5992{
5993 SCIP_CONSDATA* consdata;
5994 SCIP_CONSHDLRDATA* conshdlrdata;
5996 SCIP_EXPR* expr;
5998 SCIP_VAR* auxvar;
5999 int nreductions = 0;
6000 int c, e;
6001
6002 assert(scip != NULL);
6003 assert(conshdlr != NULL);
6004 assert(conss != NULL || nconss == 0);
6005 assert(nconss >= 0);
6006 assert(infeasible != NULL);
6007
6008 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6009 assert(conshdlrdata != NULL);
6010
6011 /* start with new propbounds (just to be sure, should not be needed) */
6012 ++conshdlrdata->curpropboundstag;
6013
6016
6017 /* first ensure activities are up to date and create auxvars */
6018 *infeasible = FALSE;
6019 for( c = 0; c < nconss; ++c )
6020 {
6021 assert(conss != NULL);
6022 assert(conss[c] != NULL);
6023
6024 consdata = SCIPconsGetData(conss[c]);
6025 assert(consdata != NULL);
6026 assert(consdata->expr != NULL);
6027
6028#ifdef WITH_DEBUG_SOLUTION
6030 {
6032
6034
6035 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6036 {
6037 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6038 * in createAuxVar()
6039 */
6040 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6041 }
6042 }
6043#endif
6044
6045 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6046 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6047
6048 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6049 {
6050 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6051 {
6052 SCIP_CALL( createAuxVar(scip, expr) );
6053 }
6054 }
6055
6056 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6057 if( auxvar != NULL )
6058 {
6059 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6060 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6061 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6062 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6063 if( *infeasible )
6064 {
6065 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6066 break;
6067 }
6068
6069 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6070 if( *infeasible )
6071 {
6072 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6073 break;
6074 }
6075 }
6076 }
6077
6078 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6079 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6080 * (e.g., log(x*y), which becomes log(w), w=x*y
6081 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6082 */
6083 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6084 if( result == SCIP_CUTOFF )
6085 *infeasible = TRUE;
6086
6087 /* now call initsepa of nlhdlrs
6088 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6089 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6090 */
6092 for( c = 0; c < nconss && !*infeasible; ++c )
6093 {
6094 assert(conss != NULL);
6095 assert(conss[c] != NULL);
6096
6097 consdata = SCIPconsGetData(conss[c]);
6098 assert(consdata != NULL);
6099 assert(consdata->expr != NULL);
6100
6101 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6102 {
6103 SCIP_EXPR_OWNERDATA* ownerdata;
6104
6105 ownerdata = SCIPexprGetOwnerData(expr);
6106 assert(ownerdata != NULL);
6107
6108 if( ownerdata->nauxvaruses == 0 )
6109 continue;
6110
6111 for( e = 0; e < ownerdata->nenfos; ++e )
6112 {
6113 SCIP_NLHDLR* nlhdlr;
6114 SCIP_Bool underestimate;
6115 SCIP_Bool overestimate;
6116 assert(ownerdata->enfos[e] != NULL);
6117
6118 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6119 * which participated in a previous initSepa() call
6120 */
6121 if( ownerdata->enfos[e]->issepainit )
6122 continue;
6123
6124 /* only call initsepa if it will actually separate */
6125 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6126 continue;
6127
6128 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6129 assert(nlhdlr != NULL);
6130
6131 /* only init sepa if there is an initsepa callback */
6132 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6133 continue;
6134
6135 /* check whether expression needs to be under- or overestimated */
6136 overestimate = ownerdata->nlocksneg > 0;
6137 underestimate = ownerdata->nlockspos > 0;
6138 assert(underestimate || overestimate);
6139
6140 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6141
6142 /* call the separation initialization callback of the nonlinear handler */
6143 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6144 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6145 ownerdata->enfos[e]->issepainit = TRUE;
6146
6147 if( *infeasible )
6148 {
6149 /* stop everything if we detected infeasibility */
6150 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6151 break;
6152 }
6153 }
6154 }
6155 }
6156
6158
6159 return SCIP_OKAY;
6160}
6161
6162/** returns whether we are ok to branch on auxiliary variables
6163 *
6164 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6165 */
6166static
6168 SCIP* scip, /**< SCIP data structure */
6169 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6170 )
6171{
6172 SCIP_CONSHDLRDATA* conshdlrdata;
6173
6174 assert(conshdlr != NULL);
6175
6176 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6177 assert(conshdlrdata != NULL);
6178
6179 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6180}
6181
6182/** gets weight of variable when splitting violation score onto several variables in an expression */
6183static
6185 SCIP* scip, /**< SCIP data structure */
6186 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6187 SCIP_VAR* var, /**< variable */
6188 SCIP_SOL* sol /**< current solution */
6189 )
6190{
6191 SCIP_CONSHDLRDATA* conshdlrdata;
6192
6193 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6194 assert(conshdlrdata != NULL);
6195
6196 switch( conshdlrdata->branchviolsplit )
6197 {
6198 case 'u' : /* uniform: everyone gets the same score */
6199 return 1.0;
6200
6201 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6202 {
6203 SCIP_Real weight;
6205 return MAX(0.05, weight);
6206 }
6207
6208 case 'd' : /* domain width */
6210
6211 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6212 {
6213 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6214 assert(width > 0.0);
6215 if( width > 10.0 )
6216 return 10.0*log10(width);
6217 if( width < 0.1 )
6218 return 0.1/(-log10(width));
6219 return width;
6220 }
6221
6222 default :
6223 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6224 SCIPABORT();
6225 return SCIP_INVALID;
6226 }
6227}
6228
6229/** adds violation-branching score to a set of expressions, thereby distributing the score
6230 *
6231 * Each expression must either be a variable expression or have an aux-variable.
6232 *
6233 * If unbounded variables are present, each unbounded var gets an even score.
6234 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6235 */
6236static
6238 SCIP* scip, /**< SCIP data structure */
6239 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6240 int nexprs, /**< number of expressions */
6241 SCIP_Real violscore, /**< violation-branching score to add to expression */
6242 SCIP_SOL* sol, /**< current solution */
6243 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6244 )
6245{
6246 SCIP_CONSHDLR* conshdlr;
6247 SCIP_VAR* var;
6248 SCIP_Real weight;
6249 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6250 int nunbounded = 0; /* number of candidates with unbounded domain */
6251 int i;
6252
6253 assert(exprs != NULL);
6254 assert(nexprs > 0);
6255 assert(success != NULL);
6256
6257 if( nexprs == 1 )
6258 {
6260 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6262 *success = TRUE;
6263 return;
6264 }
6265
6266 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6267
6268 for( i = 0; i < nexprs; ++i )
6269 {
6271 assert(var != NULL);
6272
6274 ++nunbounded;
6276 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6277 }
6278
6279 *success = FALSE;
6280 for( i = 0; i < nexprs; ++i )
6281 {
6283 assert(var != NULL);
6284
6285 if( nunbounded > 0 )
6286 {
6288 {
6290 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6291 100.0/nunbounded, violscore,
6293 *success = TRUE;
6294 }
6295 }
6297 {
6298 assert(weightsum > 0.0);
6299
6300 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6301 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6302 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6303 100*weight / weightsum, violscore,
6305 *success = TRUE;
6306 }
6307 else
6308 {
6309 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6311 }
6312 }
6313}
6314
6315/** adds violation-branching score to children of expression for given auxiliary variables
6316 *
6317 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6318 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6319 *
6320 * @note This method may modify the given auxvars array by means of sorting.
6321 */
6322static
6324 SCIP* scip, /**< SCIP data structure */
6325 SCIP_EXPR* expr, /**< expression where to start searching */
6326 SCIP_Real violscore, /**< violation score to add to expression */
6327 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6328 int nauxvars, /**< number of auxiliary variables */
6329 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6330 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6331 )
6332{
6334 SCIP_VAR* auxvar;
6335 SCIP_EXPR** exprs;
6336 int nexprs;
6337 int pos;
6338
6339 assert(scip != NULL);
6340 assert(expr != NULL);
6341 assert(auxvars != NULL);
6342 assert(success != NULL);
6343
6344 /* sort variables to make lookup below faster */
6345 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6346
6349
6351 nexprs = 0;
6352
6354 {
6355 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6356 if( auxvar == NULL )
6357 continue;
6358
6359 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6360 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6361 {
6362 assert(auxvars[pos] == auxvar);
6363
6364 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6365 exprs[nexprs++] = expr;
6366
6367 if( nexprs == nauxvars )
6368 break;
6369 }
6370 }
6371
6373
6374 if( nexprs > 0 )
6375 {
6377 }
6378 else
6379 *success = FALSE;
6380
6381 SCIPfreeBufferArray(scip, &exprs);
6382
6383 return SCIP_OKAY;
6384}
6385
6386/** registers all unfixed variables in violated constraints as branching candidates */
6387static
6389 SCIP* scip, /**< SCIP data structure */
6390 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6391 SCIP_CONS** conss, /**< constraints */
6392 int nconss, /**< number of constraints */
6393 int* nnotify /**< counter for number of notifications performed */
6394 )
6395{
6396 SCIP_CONSDATA* consdata;
6397 SCIP_VAR* var;
6398 int c;
6399 int i;
6400
6401 assert(conshdlr != NULL);
6402 assert(conss != NULL || nconss == 0);
6403 assert(nnotify != NULL);
6404
6405 *nnotify = 0;
6406
6407 for( c = 0; c < nconss; ++c )
6408 {
6409 assert(conss != NULL && conss[c] != NULL);
6410
6411 consdata = SCIPconsGetData(conss[c]);
6412 assert(consdata != NULL);
6413
6414 /* consider only violated constraints */
6415 if( !isConsViolated(scip, conss[c]) )
6416 continue;
6417
6418 /* register all variables that have not been fixed yet */
6419 assert(consdata->varexprs != NULL);
6420 for( i = 0; i < consdata->nvarexprs; ++i )
6421 {
6422 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6423 assert(var != NULL);
6424
6426 {
6428 ++(*nnotify);
6429 }
6430 }
6431 }
6432
6433 return SCIP_OKAY;
6434}
6435
6436/** registers all variables in violated constraints with branching scores as external branching candidates */
6437static
6439 SCIP* scip, /**< SCIP data structure */
6440 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6441 SCIP_CONS** conss, /**< constraints */
6442 int nconss, /**< number of constraints */
6443 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6444 )
6445{
6446 SCIP_CONSDATA* consdata;
6448 int c;
6449
6450 assert(conshdlr != NULL);
6451 assert(success != NULL);
6452
6453 *success = FALSE;
6454
6455 if( branchAuxNonlinear(scip, conshdlr) )
6456 {
6459 }
6460
6461 /* register external branching candidates */
6462 for( c = 0; c < nconss; ++c )
6463 {
6464 assert(conss != NULL && conss[c] != NULL);
6465
6466 consdata = SCIPconsGetData(conss[c]);
6467 assert(consdata != NULL);
6468 assert(consdata->varexprs != NULL);
6469
6470 /* consider only violated constraints */
6471 if( !isConsViolated(scip, conss[c]) )
6472 continue;
6473
6474 if( !branchAuxNonlinear(scip, conshdlr) )
6475 {
6476 int i;
6477
6478 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6479 * only, so we can loop over variable expressions
6480 */
6481 for( i = 0; i < consdata->nvarexprs; ++i )
6482 {
6483 SCIP_Real violscore;
6484 SCIP_Real lb;
6485 SCIP_Real ub;
6486 SCIP_VAR* var;
6487
6488 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6489
6490 /* skip variable expressions that do not have a violation score */
6491 if( violscore == 0.0 )
6492 continue;
6493
6494 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6495 assert(var != NULL);
6496
6497 lb = SCIPvarGetLbLocal(var);
6498 ub = SCIPvarGetUbLocal(var);
6499
6500 /* consider variable for branching if it has not been fixed yet */
6501 if( !SCIPisEQ(scip, lb, ub) )
6502 {
6503 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6505 *success = TRUE;
6506 }
6507 else
6508 {
6509 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6510 }
6511
6512 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6513 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6514 */
6515 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6516 }
6517 }
6518 else
6519 {
6520 SCIP_EXPR* expr;
6521 SCIP_VAR* var;
6522 SCIP_Real lb;
6523 SCIP_Real ub;
6524 SCIP_Real violscore;
6525
6526 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6527 {
6529 if( violscore == 0.0 )
6530 continue;
6531
6532 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6533 * variable, so this expression should either be an original variable or have an auxiliary variable
6534 */
6536 assert(var != NULL);
6537
6538 lb = SCIPvarGetLbLocal(var);
6539 ub = SCIPvarGetUbLocal(var);
6540
6541 /* consider variable for branching if it has not been fixed yet */
6542 if( !SCIPisEQ(scip, lb, ub) )
6543 {
6544 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6545
6547 *success = TRUE;
6548 }
6549 else
6550 {
6551 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6552 }
6553 }
6554 }
6555 }
6556
6557 if( it != NULL )
6559
6560 return SCIP_OKAY;
6561}
6562
6563/** collect branching candidates from violated constraints
6564 *
6565 * Fills array with expressions that serve as branching candidates.
6566 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6567 * branching candidate.
6568 *
6569 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6570 * through variable-expressions only.
6571 */
6572static
6574 SCIP* scip, /**< SCIP data structure */
6575 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6576 SCIP_CONS** conss, /**< constraints to process */
6577 int nconss, /**< number of constraints */
6578 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6579 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6580 SCIP_Longint soltag, /**< tag of solution */
6581 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6582 int* ncands /**< number of candidates found */
6583 )
6584{
6585 SCIP_CONSHDLRDATA* conshdlrdata;
6586 SCIP_CONSDATA* consdata;
6588 int c;
6589 int attempt;
6590 SCIP_VAR* var;
6591
6592 assert(scip != NULL);
6593 assert(conshdlr != NULL);
6594 assert(cands != NULL);
6595 assert(ncands != NULL);
6596
6597 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6598 assert(conshdlrdata != NULL);
6599
6600 if( branchAuxNonlinear(scip, conshdlr) )
6601 {
6604 }
6605
6606 *ncands = 0;
6607 for( attempt = 0; attempt < 2; ++attempt )
6608 {
6609 /* collect branching candidates from violated constraints
6610 * in the first attempt, consider only constraints with large violation
6611 * in the second attempt, consider all remaining violated constraints
6612 */
6613 for( c = 0; c < nconss; ++c )
6614 {
6615 SCIP_Real consviol;
6616
6617 assert(conss != NULL && conss[c] != NULL);
6618
6619 /* consider only violated constraints */
6620 if( !isConsViolated(scip, conss[c]) )
6621 continue;
6622
6623 consdata = SCIPconsGetData(conss[c]);
6624 assert(consdata != NULL);
6625 assert(consdata->varexprs != NULL);
6626
6627 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6628
6629 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6630 continue;
6631 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6632 continue;
6633
6634 if( !branchAuxNonlinear(scip, conshdlr) )
6635 {
6636 int i;
6637
6638 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6639 * only, so we can loop over variable expressions
6640 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6641 * variable, therefore we invalidate the score of a variable after processing it.
6642 */
6643 for( i = 0; i < consdata->nvarexprs; ++i )
6644 {
6645 SCIP_Real lb;
6646 SCIP_Real ub;
6647
6648 /* skip variable expressions that do not have a valid violation score */
6649 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6650 continue;
6651
6652 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6653 assert(var != NULL);
6654
6655 lb = SCIPvarGetLbLocal(var);
6656 ub = SCIPvarGetUbLocal(var);
6657
6658 /* skip already fixed variable */
6659 if( SCIPisEQ(scip, lb, ub) )
6660 {
6661 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6662 continue;
6663 }
6664
6665 assert(*ncands + 1 < SCIPgetNVars(scip));
6666 cands[*ncands].expr = consdata->varexprs[i];
6667 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6668 ++(*ncands);
6669
6670 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6671 * several times as external branching candidate */
6672 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6673 }
6674 }
6675 else
6676 {
6677 SCIP_EXPR* expr;
6678 SCIP_Real lb;
6679 SCIP_Real ub;
6680
6681 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6682 {
6683 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6684 continue;
6685
6686 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6687 * variables, so this expression should either be an original variable or have an auxiliary variable
6688 */
6690 assert(var != NULL);
6691
6692 lb = SCIPvarGetLbLocal(var);
6693 ub = SCIPvarGetUbLocal(var);
6694
6695 /* skip already fixed variable */
6696 if( SCIPisEQ(scip, lb, ub) )
6697 {
6698 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6699 continue;
6700 }
6701
6702 assert(*ncands + 1 < SCIPgetNVars(scip));
6703 cands[*ncands].expr = expr;
6704 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6705 ++(*ncands);
6706 }
6707 }
6708 }
6709
6710 /* if we have branching candidates, then we don't need another attempt */
6711 if( *ncands > 0 )
6712 break;
6713 }
6714
6715 if( it != NULL )
6717
6718 return SCIP_OKAY;
6719}
6720
6721/** computes a branching score for a variable that reflects how important branching on this variable would be for
6722 * improving the dual bound from the LP relaxation
6723 *
6724 * Assume the Lagrangian for the current LP is something of the form
6725 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6726 * where x are the original variables, z the auxiliary variables,
6727 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6728 *
6729 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6730 * If we could have used not only an estimator, but the actual function f(x), then this would
6731 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6732 * Using a lot of handwaving, we claim that
6733 * lambda_i * (f(x) - a_i'x + b_i)
6734 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6735 * If an estimator depended on local bounds, then it could be improved by branching.
6736 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6737 *
6738 * 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.
6739 * To scale, we divide by the LP objective value (if >1).
6740 *
6741 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6742 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6743 *
6744 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6745 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6746 * would also be branching candidates
6747 */
6748static
6750 SCIP* scip, /**< SCIP data structure */
6751 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6752 SCIP_VAR* var /**< variable */
6753 )
6754{
6755 SCIP_COL* col;
6756 SCIP_ROW** rows;
6757 int nrows;
6758 int r;
6759 SCIP_Real dualscore;
6760
6761 assert(scip != NULL);
6762 assert(conshdlr != NULL);
6763 assert(var != NULL);
6764
6765 /* if LP not solved, then the dual branching score is not available */
6767 return 0.0;
6768
6769 /* if var is not in the LP, then the dual branching score is not available */
6771 return 0.0;
6772
6773 col = SCIPvarGetCol(var);
6774 assert(col != NULL);
6775
6776 if( !SCIPcolIsInLP(col) )
6777 return 0.0;
6778
6779 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6780 rows = SCIPcolGetRows(col);
6781
6782 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6783
6784 /* aggregate duals from all rows from consexpr with non-zero dual
6785 * TODO: this is a quick-and-dirty implementation, and not used by default
6786 * in the long run, this should be either removed or replaced by a proper implementation
6787 */
6788 dualscore = 0.0;
6789 for( r = 0; r < nrows; ++r )
6790 {
6791 SCIP_Real estimategap;
6792 const char* estimategapstr;
6793
6794 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6795 * these would typically be local, unless they are created at the root node
6796 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6797 if( !SCIProwIsLocal(rows[r]) )
6798 continue;
6799 */
6800 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6801 continue;
6802 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6803 continue;
6804
6805 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6806 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6807 continue;
6809 assert(estimategap >= 0.0);
6812
6813 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6814 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6815
6817 }
6818
6819 /* divide by optimal value of LP for scaling */
6821
6822 return dualscore;
6823}
6824
6825/** computes branching scores (including weighted score) for a set of candidates
6826 *
6827 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6828 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6829 *
6830 * For each score, compute the maximum over all candidates.
6831 *
6832 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6833 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6834 * score of all candidates.
6835 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6836 *
6837 * For example:
6838 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6839 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6840 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6841 * - 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.
6842 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6843 */
6844static
6846 SCIP* scip, /**< SCIP data structure */
6847 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6848 BRANCHCAND* cands, /**< branching candidates */
6849 int ncands, /**< number of candidates */
6850 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6851 )
6852{
6853 SCIP_CONSHDLRDATA* conshdlrdata;
6855 int c;
6856
6857 assert(scip != NULL);
6858 assert(conshdlr != NULL);
6859 assert(cands != NULL);
6860 assert(ncands > 0);
6861
6862 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6863 assert(conshdlrdata != NULL);
6864
6865 /* initialize counts to 0 */
6866 memset(&maxscore, 0, sizeof(BRANCHCAND));
6867
6868 for( c = 0; c < ncands; ++c )
6869 {
6870 if( conshdlrdata->branchviolweight > 0.0 )
6871 {
6872 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6873 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6874 }
6875
6876 if( conshdlrdata->branchdomainweight > 0.0 )
6877 {
6878 SCIP_Real domainwidth;
6879 SCIP_VAR* var;
6880
6881 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6882 assert(var != NULL);
6883
6884 /* get domain width, taking infinity at 1e20 on purpose */
6886
6887 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6888 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6889 * the idea is to penalize very large and very small domains
6890 */
6891 if( domainwidth >= 1.0 )
6892 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6893 else
6895
6896 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6897 }
6898 else
6899 cands[c].domain = 0.0;
6900
6901 if( conshdlrdata->branchdualweight > 0.0 )
6902 {
6903 SCIP_VAR* var;
6904
6905 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6906 assert(var != NULL);
6907
6908 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6909 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6910 }
6911
6912 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6913 {
6914 SCIP_VAR* var;
6915
6916 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6917 assert(var != NULL);
6918
6920 cands[c].pscost = SCIP_INVALID;
6921 else
6922 {
6923 SCIP_Real brpoint;
6924 SCIP_Real pscostdown;
6925 SCIP_Real pscostup;
6926 char strategy;
6927
6928 /* decide how to compute pseudo-cost scores
6929 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
6930 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
6931 */
6933 strategy = conshdlrdata->branchpscostupdatestrategy;
6934 else
6935 strategy = 'l';
6936
6938
6939 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
6940 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
6941 * For here, I use a simple #counts >= branchpscostreliable.
6942 * TODO use SCIPgetVarPseudocostCount() instead?
6943 */
6944 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
6945 {
6946 switch( strategy )
6947 {
6948 case 's' :
6950 break;
6951 case 'd' :
6953 break;
6954 case 'l' :
6959 else
6961 break;
6962 default :
6963 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
6965 }
6966 }
6967 else
6969
6970 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
6971 {
6972 switch( strategy )
6973 {
6974 case 's' :
6976 break;
6977 case 'd' :
6979 break;
6980 case 'l' :
6985 else
6987 break;
6988 default :
6989 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
6991 }
6992 }
6993 else
6995
6996 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
6997 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
6998 */
7000 cands[c].pscost = SCIP_INVALID;
7001 else if( pscostdown == SCIP_INVALID )
7002 cands[c].pscost = pscostup;
7003 else if( pscostup == SCIP_INVALID )
7004 cands[c].pscost = pscostdown;
7005 else
7006 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7007 }
7008
7009 if( cands[c].pscost != SCIP_INVALID )
7010 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7011 }
7012
7013 if( conshdlrdata->branchvartypeweight > 0.0 )
7014 {
7015 SCIP_VAR* var;
7016
7017 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7018 assert(var != NULL);
7019
7020 switch( SCIPvarGetType(var) )
7021 {
7022 case SCIP_VARTYPE_BINARY :
7023 cands[c].vartype = 1.0;
7024 break;
7026 cands[c].vartype = 0.1;
7027 break;
7029 cands[c].vartype = 0.01;
7030 break;
7032 default:
7033 cands[c].vartype = 0.0;
7034 }
7035 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7036 }
7037 }
7038
7039 /* now compute a weighted score for each candidate from the single scores
7040 * the single scores are scaled to be in [0,1] for this
7041 */
7042 for( c = 0; c < ncands; ++c )
7043 {
7044 SCIP_Real weightsum;
7045
7046 ENFOLOG(
7047 SCIP_VAR* var;
7048 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7050 )
7051
7052 cands[c].weighted = 0.0;
7053 weightsum = 0.0;
7054
7055 if( maxscore.auxviol > 0.0 )
7056 {
7057 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7058 weightsum += conshdlrdata->branchviolweight;
7059
7060 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7061 }
7062
7063 if( maxscore.domain > 0.0 )
7064 {
7065 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7066 weightsum += conshdlrdata->branchdomainweight;
7067
7068 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7069 }
7070
7071 if( maxscore.dual > 0.0 )
7072 {
7073 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7074 weightsum += conshdlrdata->branchdualweight;
7075
7076 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7077 }
7078
7079 if( maxscore.pscost > 0.0 )
7080 {
7081 /* use pseudo-costs only if available */
7082 if( cands[c].pscost != SCIP_INVALID )
7083 {
7084 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7085 weightsum += conshdlrdata->branchpscostweight;
7086
7087 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7088 }
7089 else
7090 {
7091 /* do not add pscostscore, if not available, also do not add into weightsum */
7092 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7093 }
7094 }
7095
7096 if( maxscore.vartype > 0.0 )
7097 {
7098 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7099 weightsum += conshdlrdata->branchvartypeweight;
7100
7101 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7102 }
7103 assert(weightsum > 0.0); /* we should have got at least one valid score */
7104 cands[c].weighted /= weightsum;
7105
7106 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7107 }
7108}
7109
7110/** compare two branching candidates by their weighted score
7111 *
7112 * if weighted score is equal, use variable index of (aux)var
7113 */
7114static
7116{
7117 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7118
7119 if( cands[ind1].weighted != cands[ind2].weighted )
7120 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7121 else
7123}
7124
7125/** do branching or register branching candidates */
7126static
7128 SCIP* scip, /**< SCIP data structure */
7129 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7130 SCIP_CONS** conss, /**< constraints to process */
7131 int nconss, /**< number of constraints */
7132 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7133 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7134 SCIP_Longint soltag, /**< tag of solution */
7135 SCIP_RESULT* result /**< pointer to store the result of branching */
7136 )
7137{
7138 SCIP_CONSHDLRDATA* conshdlrdata;
7139 BRANCHCAND* cands;
7140 int ncands;
7141 SCIP_VAR* var;
7145
7146 assert(conshdlr != NULL);
7147 assert(result != NULL);
7148
7150
7151 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7152 assert(conshdlrdata != NULL);
7153
7154 if( conshdlrdata->branchexternal )
7155 {
7156 /* just register branching candidates as external */
7157 SCIP_Bool success;
7158
7159 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7160 if( success )
7162
7163 return SCIP_OKAY;
7164 }
7165
7166 /* collect branching candidates and their auxviol-score */
7168 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7169
7170 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7171 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7172 */
7173 if( ncands == 0 )
7174 goto TERMINATE;
7175
7176 if( ncands > 1 )
7177 {
7178 /* if there are more than one candidate, then compute scores and select */
7179 int* perm;
7180 int c;
7181 int left;
7182 int right;
7183 SCIP_Real threshold;
7184
7185 /* compute additional scores on branching candidates and weighted score */
7186 scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7187
7188 /* sort candidates by weighted score */
7189 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7190 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7191
7192 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7193 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7194 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7195
7196 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7197 left = 0;
7198 right = ncands - 1;
7199 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7200 while( left < right )
7201 {
7202 int mid = (left + right) / 2;
7203 if( cands[perm[mid]].weighted >= threshold )
7204 left = mid + 1;
7205 else
7206 right = mid;
7207 }
7208 assert(left <= ncands);
7209
7210 if( left < ncands )
7211 {
7212 if( cands[perm[left]].weighted >= threshold )
7213 {
7214 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7215 ncands = left + 1;
7216 }
7217 else
7218 {
7219 assert(cands[perm[left]].weighted < threshold);
7220 ncands = left;
7221 }
7222 }
7223 assert(ncands > 0);
7224
7225 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7226 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7227 SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7228
7229 if( ncands > 1 )
7230 {
7231 /* choose at random from candidates 0..ncands-1 */
7232 if( conshdlrdata->branchrandnumgen == NULL )
7233 {
7234 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7235 }
7236 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7237 var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7238 }
7239 else
7240 var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7241
7242 SCIPfreeBufferArray(scip, &perm);
7243 }
7244 else
7245 {
7246 var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7247 }
7248 assert(var != NULL);
7249
7250 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7252
7254 &upchild) );
7255 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7257 else
7258 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7260
7261 TERMINATE:
7262 SCIPfreeBufferArray(scip, &cands);
7263
7264 return SCIP_OKAY;
7265}
7266
7267/** call enforcement or estimate callback of nonlinear handler
7268 *
7269 * Calls the enforcement callback, if available.
7270 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7271 *
7272 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7273 */
7274static
7276 SCIP* scip, /**< SCIP main data structure */
7277 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7278 SCIP_CONS* cons, /**< nonlinear constraint */
7279 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7280 SCIP_EXPR* expr, /**< expression */
7281 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7282 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7283 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7284 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7285 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7286 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7287 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7288 SCIP_RESULT* result /**< pointer to store the result */
7289 )
7290{
7291 assert(result != NULL);
7292
7293 /* call enforcement callback of the nlhdlr */
7294 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7296
7297 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7299 {
7300 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7301 SCIPnlhdlrGetName(nlhdlr), *result); )
7302 return SCIP_OKAY;
7303 }
7304 else
7305 {
7306 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7307 }
7308
7310
7311 /* now call the estimator callback of the nlhdlr */
7312 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7313 {
7314 SCIP_VAR* auxvar;
7315 SCIP_Bool sepasuccess = FALSE;
7316 SCIP_Bool branchscoresuccess = FALSE;
7318 int minidx;
7319 int maxidx;
7320 int r;
7322
7324
7325 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7326 assert(auxvar != NULL);
7327
7328 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7330
7333
7334 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7335
7336 if( !sepasuccess )
7337 {
7338 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7339 SCIPnlhdlrGetName(nlhdlr)); )
7340 }
7341
7342 for( r = minidx; r <= maxidx; ++r )
7343 {
7345
7346 assert(rowprep != NULL);
7348
7349 /* complete estimator to cut */
7350 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7351
7352 /* add the cut and/or branching scores */
7353 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7355
7357 }
7358
7360 }
7361
7362 return SCIP_OKAY;
7363}
7364
7365/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7366 *
7367 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7368 */
7369static
7371 SCIP* scip, /**< SCIP data structure */
7372 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7373 SCIP_CONS* cons, /**< nonlinear constraint */
7374 SCIP_EXPR* expr, /**< expression */
7375 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7376 SCIP_Longint soltag, /**< tag of solution */
7377 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7378 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7379 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7380 )
7381{
7382 SCIP_CONSHDLRDATA* conshdlrdata;
7383 SCIP_EXPR_OWNERDATA* ownerdata;
7384 SCIP_Real origviol;
7385 SCIP_Bool underestimate;
7386 SCIP_Bool overestimate;
7387 SCIP_Real auxviol;
7388 SCIP_Bool auxunderestimate;
7389 SCIP_Bool auxoverestimate;
7391 int e;
7392
7393 assert(scip != NULL);
7394 assert(expr != NULL);
7395 assert(result != NULL);
7396
7397 ownerdata = SCIPexprGetOwnerData(expr);
7398 assert(ownerdata != NULL);
7399 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7400
7402
7403 /* make sure that this expression has been evaluated */
7404 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7405
7406 /* decide whether under- or overestimate is required and get amount of violation */
7407 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7408
7409 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7410 assert(conshdlrdata != NULL);
7411
7412 /* no sufficient violation w.r.t. the original variables -> skip expression */
7413 if( !overestimate && !underestimate )
7414 {
7415 return SCIP_OKAY;
7416 }
7417
7418 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7419 for( e = 0; e < ownerdata->nenfos; ++e )
7420 {
7421 SCIP_NLHDLR* nlhdlr;
7422
7423 /* skip nlhdlr that do not want to participate in any separation */
7424 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7425 continue;
7426
7427 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7428 assert(nlhdlr != NULL);
7429
7430 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7431 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7432 ENFOLOG(
7433 SCIPinfoMessage(scip, enfologfile, " expr ");
7435 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7436 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7437 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7438 )
7439
7440 /* TODO if expr is root of constraint (consdata->expr == expr),
7441 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7442 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7443 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7444 * so we should enforce in these auxiliaries first
7445 * if changing this here, we must also adapt analyzeViolation()
7446 */
7447
7448 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7449 assert(auxviol >= 0.0);
7450
7451 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7452 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7453 {
7454 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7455 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7456 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7457
7458 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7459 continue;
7460 }
7461
7462 /* 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 */
7463 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7464 {
7465 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7466 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7467 underestimate, overestimate); )
7468
7469 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7470 continue;
7471 }
7472
7473 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7474 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7475 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7476
7477 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7478 * wants to be called for separation on this side, then call separation of nlhdlr
7479 */
7480 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7481 {
7482 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7484 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7485 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7486
7487 if( hdlrresult == SCIP_CUTOFF )
7488 {
7489 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7491 ownerdata->lastenforced = conshdlrdata->enforound;
7492 break;
7493 }
7494
7495 if( hdlrresult == SCIP_SEPARATED )
7496 {
7497 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7499 ownerdata->lastenforced = conshdlrdata->enforound;
7500 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7501 break;
7502 }
7503
7505 {
7506 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7508 ownerdata->lastenforced = conshdlrdata->enforound;
7509 /* TODO or should we always just stop here? */
7510 }
7511
7512 if( hdlrresult == SCIP_BRANCHED )
7513 {
7514 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7516
7517 /* separation and domain reduction takes precedence over branching */
7519 if( *result == SCIP_DIDNOTFIND )
7521 ownerdata->lastenforced = conshdlrdata->enforound;
7522 }
7523 }
7524
7525 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7526 * wants to be called for separation on this side, then call separation of nlhdlr
7527 */
7528 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7529 {
7530 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7532 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7533 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7534
7535 if( hdlrresult == SCIP_CUTOFF )
7536 {
7537 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7539 ownerdata->lastenforced = conshdlrdata->enforound;
7540 break;
7541 }
7542
7543 if( hdlrresult == SCIP_SEPARATED )
7544 {
7545 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7547 ownerdata->lastenforced = conshdlrdata->enforound;
7548 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7549 break;
7550 }
7551
7553 {
7554 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7556 ownerdata->lastenforced = conshdlrdata->enforound;
7557 /* TODO or should we always just stop here? */
7558 }
7559
7560 if( hdlrresult == SCIP_BRANCHED )
7561 {
7562 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7564
7565 /* separation takes precedence over branching */
7567 if( *result == SCIP_DIDNOTFIND )
7569 ownerdata->lastenforced = conshdlrdata->enforound;
7570 }
7571 }
7572 }
7573
7574 return SCIP_OKAY;
7575}
7576
7577/** helper function to enforce a single constraint */
7578static
7580 SCIP* scip, /**< SCIP data structure */
7581 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7582 SCIP_CONS* cons, /**< constraint to process */
7583 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7584 SCIP_Longint soltag, /**< tag of solution */
7585 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7586 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7587 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7588 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7589 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7590 )
7591{
7592 SCIP_CONSDATA* consdata;
7593 SCIP_CONSHDLRDATA* conshdlrdata;
7594 SCIP_EXPR* expr;
7595
7596 assert(conshdlr != NULL);
7597 assert(cons != NULL);
7598 assert(it != NULL);
7599 assert(result != NULL);
7600 assert(success != NULL);
7601
7602 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7603 assert(conshdlrdata != NULL);
7604
7605 consdata = SCIPconsGetData(cons);
7606 assert(consdata != NULL);
7607 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7608
7609 *success = FALSE;
7610
7611 if( inenforcement && !consdata->ispropagated )
7612 {
7613 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7614 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7615 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7616 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7617 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7618 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7619 * confuse the stalling check for how long to do separation).
7620 */
7621 SCIP_Bool infeasible;
7622 int ntightenings;
7623
7624 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7625 if( infeasible )
7626 {
7628 return SCIP_OKAY;
7629 }
7630 /* if we tightened an auxvar bound, we better communicate that */
7631 if( ntightenings > 0 )
7633 }
7634
7635 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7636 {
7637 SCIP_EXPR_OWNERDATA* ownerdata;
7639
7640 ownerdata = SCIPexprGetOwnerData(expr);
7641 assert(ownerdata != NULL);
7642
7643 /* we can only enforce if there is an auxvar to compare with */
7644 if( ownerdata->auxvar == NULL )
7645 continue;
7646
7647 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7648 if( ownerdata->lastenforced == conshdlrdata->enforound )
7649 {
7650 ENFOLOG(
7651 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7653 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7654 )
7655 *success = TRUE;
7656 continue;
7657 }
7658
7659 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7660
7661 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7662 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7663 if( ownerdata->lastenforced == conshdlrdata->enforound )
7664 *success = TRUE;
7665
7666 if( resultexpr == SCIP_CUTOFF )
7667 {
7669 break;
7670 }
7671
7672 if( resultexpr == SCIP_SEPARATED )
7674
7677
7680 }
7681
7682 return SCIP_OKAY;
7683}
7684
7685/** try to separate violated constraints and, if in enforcement, register branching scores
7686 *
7687 * Sets result to
7688 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7689 * - SCIP_CUTOFF, if node can be cutoff,
7690 * - SCIP_SEPARATED, if a cut has been added,
7691 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7692 * - SCIP_BRANCHED, if branching has been done,
7693 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7694 * - SCIP_INFEASIBLE, if external branching candidates were registered
7695 */
7696static
7698 SCIP* scip, /**< SCIP data structure */
7699 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7700 SCIP_CONS** conss, /**< constraints to process */
7701 int nconss, /**< number of constraints */
7702 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7703 SCIP_Longint soltag, /**< tag of solution */
7704 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7705 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7706 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7707 )
7708{
7709 SCIP_CONSHDLRDATA* conshdlrdata;
7711 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7712 int c;
7713
7714 assert(conshdlr != NULL);
7715 assert(conss != NULL || nconss == 0);
7716 assert(result != NULL);
7717
7718 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7719 assert(conshdlrdata != NULL);
7720
7721 /* increase tag to tell whether branching scores in expression belong to this sweep
7722 * and which expressions have already been enforced in this sweep
7723 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7724 */
7725 ++(conshdlrdata->enforound);
7726
7728
7731
7732 for( c = 0; c < nconss; ++c )
7733 {
7734 assert(conss != NULL && conss[c] != NULL);
7735
7736 /* skip constraints that are not enabled or deleted */
7737 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7738 continue;
7739 assert(SCIPconsIsActive(conss[c]));
7740
7741 /* skip constraints that have separation disabled if we are only in separation */
7743 continue;
7744
7745 /* skip non-violated constraints */
7746 if( !isConsViolated(scip, conss[c]) )
7747 continue;
7748
7749 ENFOLOG(
7750 {
7751 SCIP_CONSDATA* consdata;
7752 int i;
7753 consdata = SCIPconsGetData(conss[c]);
7754 assert(consdata != NULL);
7755 SCIPinfoMessage(scip, enfologfile, " constraint ");
7757 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7758 for( i = 0; i < consdata->nvarexprs; ++i )
7759 {
7760 SCIP_VAR* var;
7761 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7762 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7764 }
7765 })
7766
7768
7769 if( *result == SCIP_CUTOFF )
7770 break;
7771
7772 if( !consenforced && inenforcement )
7773 {
7774 SCIP_Real viol;
7775
7776 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7777 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7778 {
7779 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7780 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7781
7783
7784 if( consenforced )
7785 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7786
7787 if( *result == SCIP_CUTOFF )
7788 break;
7789 }
7790 }
7791 }
7792
7794
7796
7797 /* if having branching scores, then propagate them from expressions with children to variable expressions */
7798 if( *result == SCIP_BRANCHED )
7799 {
7800 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7801 * branching
7802 */
7803 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7804
7805 /* branching should either have branched: result == SCIP_BRANCHED,
7806 * or fixed a variable: result == SCIP_REDUCEDDOM,
7807 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7808 * or have not done anything: result == SCIP_DIDNOTFIND
7809 */
7811 }
7812
7814
7815 return SCIP_OKAY;
7816}
7817
7818/** collect (and print (if debugging enfo)) information on violation in expressions
7819 *
7820 * assumes that constraint violations have been computed
7821 */
7822static
7824 SCIP* scip, /**< SCIP data structure */
7825 SCIP_CONS** conss, /**< constraints */
7826 int nconss, /**< number of constraints */
7827 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7828 SCIP_Longint soltag, /**< tag of solution */
7829 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7830 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7831 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7832 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7833 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7834 )
7835{
7836 SCIP_CONSDATA* consdata;
7838 SCIP_EXPR* expr;
7839 SCIP_Real v;
7840 int c;
7841
7842 assert(conss != NULL || nconss == 0);
7847
7850
7851 *maxabsconsviol = 0.0;
7852 *maxrelconsviol = 0.0;
7854 *maxauxviol = 0.0;
7855 *maxvarboundviol = 0.0;
7856
7857 for( c = 0; c < nconss; ++c )
7858 {
7859 assert(conss != NULL && conss[c] != NULL);
7860
7861 consdata = SCIPconsGetData(conss[c]);
7862 assert(consdata != NULL);
7863
7864 /* skip constraints that are not enabled, deleted, or have separation disabled */
7865 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7866 continue;
7867 assert(SCIPconsIsActive(conss[c]));
7868
7869 v = getConsAbsViolation(conss[c]);
7871
7872 /* skip non-violated constraints */
7873 if( !isConsViolated(scip, conss[c]) )
7874 continue;
7875
7876 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7878
7879 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7880 {
7881 SCIP_EXPR_OWNERDATA* ownerdata;
7882 SCIP_Real auxvarvalue;
7883 SCIP_Real auxvarlb;
7884 SCIP_Real auxvarub;
7885 SCIP_Bool violunder;
7886 SCIP_Bool violover;
7887 SCIP_Real origviol;
7888 SCIP_Real auxviol;
7889 int e;
7890
7891 ownerdata = SCIPexprGetOwnerData(expr);
7892 assert(ownerdata != NULL);
7893
7894 if( ownerdata->auxvar == NULL )
7895 {
7896 /* check violation of variable bounds of original variable */
7897 if( SCIPisExprVar(scip, expr) )
7898 {
7899 SCIP_VAR* var;
7900 var = SCIPgetVarExprVar(expr);
7904
7905 origviol = 0.0;
7910 if( origviol <= 0.0 )
7911 continue;
7912
7914
7915 ENFOLOG(
7916 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
7918 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
7920 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
7922 )
7923 }
7924
7925 continue;
7926 }
7927
7928 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
7929 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
7930 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
7931
7932 /* check violation of variable bounds of auxiliary variable */
7937
7939
7940 ENFOLOG(
7941 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
7942 {
7943 SCIPinfoMessage(scip, enfologfile, "expr ");
7945 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
7946
7947 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
7948 if( origviol > 0.0 )
7949 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
7951 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
7953 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
7955 }
7956 )
7957
7958 /* no violation w.r.t. the original variables -> skip expression */
7959 if( origviol == 0.0 )
7960 continue;
7961
7962 /* compute aux-violation for each nonlinear handlers */
7963 for( e = 0; e < ownerdata->nenfos; ++e )
7964 {
7965 SCIP_NLHDLR* nlhdlr;
7966
7967 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
7968 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7969 continue;
7970
7971 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7972 assert(nlhdlr != NULL);
7973
7974 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7975 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7976
7977 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
7978
7979 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
7980
7981 if( auxviol > 0.0 )
7982 {
7983 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
7984 *maxauxviol = MAX(*maxauxviol, auxviol);
7985 *minauxviol = MIN(*minauxviol, auxviol);
7986 }
7988 }
7989 }
7990 }
7991
7993
7994 return SCIP_OKAY;
7995} /*lint !e715*/
7996
7997/** enforcement of constraints called by enfolp and enforelax */
7998static
8000 SCIP* scip, /**< SCIP data structure */
8001 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8002 SCIP_CONS** conss, /**< constraints to process */
8003 int nconss, /**< number of constraints */
8004 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8005 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8006 )
8007{
8008 SCIP_CONSHDLRDATA* conshdlrdata;
8009 SCIP_Real maxabsconsviol;
8010 SCIP_Real maxrelconsviol;
8011 SCIP_Real minauxviol;
8012 SCIP_Real maxauxviol;
8013 SCIP_Real maxvarboundviol;
8014 SCIP_Longint soltag;
8015 int nnotify;
8016 int c;
8017
8018 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8019 assert(conshdlr != NULL);
8020
8022
8024 for( c = 0; c < nconss; ++c )
8025 {
8026 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8027
8028 if( isConsViolated(scip, conss[c]) )
8030 }
8031
8032 if( *result == SCIP_FEASIBLE )
8033 {
8034 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8036 return SCIP_OKAY;
8037 }
8038
8041
8042 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8043 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8046
8048
8049 /* try to propagate */
8050 if( conshdlrdata->propinenforce )
8051 {
8053 int nchgbds = 0;
8054
8055 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8056
8058 {
8059 *result = propresult;
8060 return SCIP_OKAY;
8061 }
8062 }
8063
8064 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8065 * all violated expr/auxvar in violated constraints)
8066 */
8067 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8068 sol == NULL )
8069 {
8071 ++conshdlrdata->ntightenlp;
8072
8074
8075 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8076 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8077
8078 return SCIP_OKAY;
8079 }
8080
8081 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8082 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8083 */
8084 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8085 {
8087 ++conshdlrdata->ntightenlp;
8088
8090
8091 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8092
8093 return SCIP_OKAY;
8094 }
8095
8096 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8097
8100 return SCIP_OKAY;
8101
8103
8104 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8105 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8106
8107 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8108 {
8110 ++conshdlrdata->ntightenlp;
8111
8113
8114 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8115 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8116
8117 return SCIP_OKAY;
8118 }
8119
8120 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8121 SCIPgetLPFeastol(scip)) && sol == NULL )
8122 {
8123 /* try whether tighten the LP feasibility tolerance could help
8124 * maybe it is just some cut that hasn't been taken into account sufficiently
8125 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8126 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8127 * until the LP feastol reaches epsilon
8128 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8129 * when maxauxviol is above LP feastol)
8130 */
8132 ++conshdlrdata->ndesperatetightenlp;
8133
8135
8136 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8137
8138 return SCIP_OKAY;
8139 }
8140
8141 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8142 if( !conshdlrdata->propinenforce )
8143 {
8145 int nchgbds = 0;
8146
8147 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8148
8150 {
8151 *result = propresult;
8152 return SCIP_OKAY;
8153 }
8154 }
8155
8156 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8157 * now look if we find any unfixed variable that we could still branch on
8158 */
8159 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8160
8161 if( nnotify > 0 )
8162 {
8163 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8164 ++conshdlrdata->ndesperatebranch;
8165
8166 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8167
8168 return SCIP_OKAY;
8169 }
8170
8171 /* if everything is fixed in violated constraints, then let's cut off the node
8172 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8173 * result may not be conclusive (when constraint violations are small)
8174 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8175 * sufficiently (see st_e40)
8176 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8177 * not "desperate", but a pretty obvious thing to do
8178 */
8179 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8181
8182 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8184 ++conshdlrdata->ndesperatecutoff;
8185
8186 return SCIP_OKAY;
8187}
8188
8189/** separation for all violated constraints to be used by SEPA callbacks */
8190static
8192 SCIP* scip, /**< SCIP data structure */
8193 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8194 SCIP_CONS** conss, /**< constraints to process */
8195 int nconss, /**< number of constraints */
8196 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8197 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8198 )
8199{
8200 SCIP_Longint soltag;
8201 SCIP_Bool haveviol = FALSE;
8202 int c;
8203
8205
8207
8208 /* compute violations */
8209 for( c = 0; c < nconss; ++c )
8210 {
8211 assert(conss[c] != NULL);
8212
8213 /* skip constraints that are not enabled, deleted, or have separation disabled */
8214 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8215 continue;
8216 assert(SCIPconsIsActive(conss[c]));
8217
8218 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8219
8220 if( isConsViolated(scip, conss[c]) )
8221 haveviol = TRUE;
8222 }
8223
8224 /* if none of our constraints are violated, don't attempt separation */
8225 if( !haveviol )
8226 {
8227 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8228 return SCIP_OKAY;
8229 }
8230
8232
8233 /* call separation */
8234 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8235
8236 return SCIP_OKAY;
8237}
8238
8239/** hash key retrieval function for bilinear term entries */
8240static
8242{ /*lint --e{715}*/
8243 SCIP_CONSHDLRDATA* conshdlrdata;
8244 int idx;
8245
8246 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8247 assert(conshdlrdata != NULL);
8248
8249 idx = ((int)(size_t)elem) - 1;
8250 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8251
8252 return (void*)&conshdlrdata->bilinterms[idx];
8253}
8254
8255/** returns TRUE iff the bilinear term entries are equal */
8256static
8258{ /*lint --e{715}*/
8261
8262 /* get corresponding entries */
8265 assert(entry1->x != NULL && entry1->y != NULL);
8266 assert(entry2->x != NULL && entry2->y != NULL);
8267 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8268 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8269
8270 return entry1->x == entry2->x && entry1->y == entry2->y;
8271}
8272
8273/** returns the hash value of the key */
8274static
8285
8286/** compare two auxiliary expressions
8287 *
8288 * Compares auxiliary variables, followed by coefficients, and then constants.
8289 */
8290static
8292{
8295 int compvars;
8296 int i;
8297
8298 /* compare the auxiliary variables */
8299 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8300
8301 if( compvars != 0 )
8302 return compvars;
8303
8304 /* compare the coefficients and constants */
8305 for( i = 0; i < 3; ++i )
8306 {
8307 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8308 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8309 }
8310
8311 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8312}
8313
8314/* add an auxiliary expression to a bilinear term */
8315static
8317 SCIP* scip, /**< SCIP data structure */
8318 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8319 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8320 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8321 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8322 )
8323{
8324 SCIP_Bool found;
8325 int pos;
8326 int i;
8327
8328 *added = FALSE;
8329
8330 /* check if auxexpr has already been added to term */
8331 if( term->nauxexprs == 0 )
8332 {
8333 found = FALSE;
8334 pos = 0;
8335 }
8336 else
8337 {
8338 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8339 }
8340
8341 if( !found )
8342 {
8343 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8344 return SCIP_OKAY;
8345
8346 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8347 assert(term->auxexprssize >= term->nauxexprs + 1);
8348
8349 /* insert expression at the correct position */
8350 for( i = term->nauxexprs; i > pos; --i )
8351 {
8352 term->aux.exprs[i] = term->aux.exprs[i-1];
8353 }
8354 term->aux.exprs[pos] = auxexpr;
8355 ++(term->nauxexprs);
8356 *added = TRUE;
8357 }
8358 else
8359 {
8360 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8361 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8362 }
8363
8364 return SCIP_OKAY;
8365}
8366
8367/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8368static
8370 SCIP* scip, /**< SCIP data structure */
8371 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8372 SCIP_CONS** conss, /**< nonlinear constraints */
8373 int nconss /**< total number of nonlinear constraints */
8374 )
8375{
8376 SCIP_CONSHDLRDATA* conshdlrdata;
8378 int c;
8379
8380 assert(conss != NULL || nconss == 0);
8381
8382 if( nconss == 0 )
8383 return SCIP_OKAY;
8384
8385 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8386 assert(conshdlrdata != NULL);
8387
8388 /* check whether the bilinear terms have been stored already */
8389 if( conshdlrdata->bilinterms != NULL )
8390 return SCIP_OKAY;
8391
8392 /* create and initialize iterator */
8396
8397 /* iterate through all constraints */
8398 for( c = 0; c < nconss; ++c )
8399 {
8400 SCIP_CONSDATA* consdata;
8401 SCIP_EXPR* expr;
8402
8403 assert(conss != NULL && conss[c] != NULL);
8404 consdata = SCIPconsGetData(conss[c]);
8405 assert(consdata != NULL);
8406
8407 /* iterate through all expressions */
8408 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8409 {
8410 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8411 SCIP_VAR* x = NULL;
8412 SCIP_VAR* y = NULL;
8413
8414 /* check whether the expression is of the form f(..)^2 */
8415 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8416 {
8417 x = SCIPgetExprAuxVarNonlinear(children[0]);
8418 y = x;
8419 }
8420 /* check whether the expression is of the form f(..) * g(..) */
8421 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8422 {
8423 x = SCIPgetExprAuxVarNonlinear(children[0]);
8424 y = SCIPgetExprAuxVarNonlinear(children[1]);
8425 }
8426
8427 /* add variables to the hash table */
8428 if( x != NULL && y != NULL )
8429 {
8432 }
8433 }
8434 }
8435
8436 /* release iterator */
8438
8439 return SCIP_OKAY;
8440}
8441
8442/** store x, y and the locks in a new bilinear term */
8443static
8445 SCIP* scip, /**< SCIP data structure */
8446 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8447 SCIP_VAR* x, /**< the first variable */
8448 SCIP_VAR* y, /**< the second variable */
8449 int nlockspos, /**< number of positive locks of the bilinear term */
8450 int nlocksneg, /**< number of negative locks of the bilinear term */
8451 int* idx, /**< pointer to store the position of the term in bilinterms array */
8452 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8453 )
8454{
8455 SCIP_CONSHDLRDATA* conshdlrdata;
8457
8458 assert(conshdlr != NULL);
8459 assert(x != NULL);
8460 assert(y != NULL);
8461 assert(nlockspos >= 0);
8462 assert(nlocksneg >= 0);
8463
8464 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8465 assert(conshdlrdata != NULL);
8466
8467 /* ensure that x.index <= y.index */
8468 if( SCIPvarCompare(x, y) == 1 )
8469 {
8470 SCIPswapPointers((void**)&x, (void**)&y);
8471 }
8472 assert(SCIPvarCompare(x, y) < 1);
8473
8474 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8475
8476 /* update or create the term */
8477 if( *idx >= 0 )
8478 { /* the term has already been added */
8479 assert(conshdlrdata->bilinterms[*idx].x == x);
8480 assert(conshdlrdata->bilinterms[*idx].y == y);
8481
8482 /* get term and add locks */
8483 term = &conshdlrdata->bilinterms[*idx];
8484 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8485 term->nlockspos += nlockspos;
8486 term->nlocksneg += nlocksneg;
8487 }
8488 else
8489 { /* this is the first time we encounter this product */
8490 /* ensure size of bilinterms array */
8491 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8492
8493 *idx = conshdlrdata->nbilinterms;
8494
8495 /* get term and set values in the created bilinear term */
8496 term = &conshdlrdata->bilinterms[*idx];
8497 assert(term != NULL);
8498 term->x = x;
8499 term->y = y;
8500 term->nauxexprs = 0;
8501 term->auxexprssize = 0;
8502 term->nlockspos = nlockspos;
8503 term->nlocksneg = nlocksneg;
8504 term->existing = existing;
8505 if( existing )
8506 term->aux.var = NULL;
8507 else
8508 term->aux.exprs = NULL;
8509
8510 /* increase the total number of bilinear terms */
8511 ++(conshdlrdata->nbilinterms);
8512
8513 /* save to the hashtable */
8514 if( conshdlrdata->bilinhashtable == NULL )
8515 {
8516 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8518 (void*)conshdlrdata) );
8519 }
8520 assert(conshdlrdata->bilinhashtable != NULL);
8521
8522 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8523 * because zero can not be inserted into hash table
8524 */
8525 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8526
8527 /* capture product variables */
8530 }
8531
8532 return SCIP_OKAY;
8533}
8534
8535/** frees array of bilinear terms and hash table */
8536static
8538 SCIP* scip, /**< SCIP data structure */
8539 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8540 )
8541{
8542 int i;
8543 int j;
8544
8545 assert(conshdlrdata != NULL);
8546
8547 /* check whether bilinear terms have been stored */
8548 if( conshdlrdata->bilinterms == NULL )
8549 {
8550 assert(conshdlrdata->bilinterms == NULL);
8551 assert(conshdlrdata->nbilinterms == 0);
8552 assert(conshdlrdata->bilintermssize == 0);
8553
8554 return SCIP_OKAY;
8555 }
8556
8557 /* release variables */
8558 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8559 {
8560 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8561 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8562
8563 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8564 {
8565 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8566 {
8567 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8568 }
8569 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8570 }
8571
8572 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8573 {
8574 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8575 continue;
8576 }
8577
8578 /* the rest is for simple terms with a single auxvar */
8579
8580 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8581 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8582 {
8583 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8584 }
8585 }
8586
8587 /* free hash table */
8588 if( conshdlrdata->bilinhashtable != NULL )
8589 {
8590 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8591 }
8592
8593 /* free bilinterms array; reset counters */
8594 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8595 conshdlrdata->nbilinterms = 0;
8596 conshdlrdata->bilintermssize = 0;
8597
8598 return SCIP_OKAY;
8599}
8600
8601/*
8602 * vertex polyhedral separation
8603 */
8604
8605/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8606static
8608 SCIP* scip, /**< SCIP data structure */
8609 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8610 SCIP_LPI** lp /**< pointer to store created LP */
8611 )
8612{
8613 SCIP_Real* obj;
8614 SCIP_Real* lb;
8615 SCIP_Real* ub;
8616 SCIP_Real* val;
8617 int* beg;
8618 int* ind;
8619 unsigned int nnonz;
8620 unsigned int ncols;
8621 unsigned int nrows;
8622 unsigned int i;
8623 unsigned int k;
8624
8625 assert(scip != NULL);
8626 assert(lp != NULL);
8627 assert(nvars > 0);
8629
8630 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8631
8632 /* create lpi to store the LP */
8634
8635 nrows = (unsigned int)nvars + 1;
8636 ncols = POWEROFTWO((unsigned int)nvars);
8637 nnonz = (ncols * (nrows + 1)) / 2;
8638
8639 /* allocate necessary memory; set obj, lb, and ub to zero */
8642 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8644 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8646
8647 /* calculate nonzero entries in the LP */
8648 for( i = 0, k = 0; i < ncols; ++i )
8649 {
8650 int row;
8651 unsigned int a;
8652
8653 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8654 ub[i] = SCIPlpiInfinity(*lp);
8655
8656 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8657 beg[i] = (int)k;
8658 row = 0;
8659
8660 /* iterate through the bit representation of i */
8661 a = 1;
8662 while( a <= i )
8663 {
8664 if( (a & i) != 0 )
8665 {
8666 val[k] = 1.0;
8667 ind[k] = row;
8668
8669 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8670
8671 ++k;
8672 }
8673
8674 a <<= 1;
8675 ++row;
8676 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8677 assert(POWEROFTWO(row) == a);
8678 }
8679
8680 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8681 val[k] = 1.0;
8682 ind[k] = (int)nrows - 1;
8683 ++k;
8684 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8685 }
8686 assert(k == nnonz);
8687
8688 /* load all data into LP interface
8689 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8690 */
8691 assert(nrows <= ncols);
8693 (int)ncols, obj, lb, ub, NULL,
8694 (int)nrows, lb, lb, NULL,
8695 (int)nnonz, beg, ind, val) );
8696
8697 /* for the last row, we can set the rhs to 1.0 already */
8698 ind[0] = (int)nrows - 1;
8699 val[0] = 1.0;
8700 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8701
8702 /* free allocated memory */
8709
8710 return SCIP_OKAY;
8711}
8712
8713/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8714 * \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
8715 * set of vertices of the domain
8716 */
8717static
8719 SCIP* scip, /**< SCIP data structure */
8720 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8721 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8722 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8723 int nallvars, /**< number of all variables */
8724 int nvars, /**< number of unfixed variables */
8725 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8726 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8727 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8728 )
8729{
8730 SCIP_Real maxerror;
8731 SCIP_Real facetval;
8732 SCIP_Real funval;
8733 SCIP_Real error;
8734 unsigned int i;
8735 unsigned int ncorners;
8736 unsigned int prev;
8737
8738 assert(scip != NULL);
8739 assert(funvals != NULL);
8740 assert(box != NULL);
8743
8745 maxerror = 0.0;
8746
8747 /* check the origin (all variables at lower bound) */
8749 for( i = 0; i < (unsigned int) nallvars; ++i )
8750 facetval += facetcoefs[i] * box[2*i];
8751
8752 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8753 funval = funvals[0];
8754 if( overestimate )
8755 error = funval - facetval;
8756 else
8757 error = facetval - funval;
8758
8759 /* update maximum error */
8761
8762 prev = 0;
8763 for( i = 1; i < ncorners; ++i )
8764 {
8765 unsigned int gray;
8766 unsigned int diff;
8767 unsigned int pos;
8768 int origpos;
8769
8770 gray = i ^ (i >> 1);
8771 diff = gray ^ prev;
8772
8773 /* compute position of unique 1 of diff */
8774 pos = 0;
8775 while( (diff >>= 1) != 0 )
8776 ++pos;
8777 assert(pos < (unsigned int)nvars);
8778
8779 origpos = nonfixedpos[pos];
8780
8781 if( gray > prev )
8782 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8783 else
8784 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8785
8786 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8787 funval = funvals[gray];
8788 if( overestimate )
8789 error = funval - facetval;
8790 else
8791 error = facetval - funval;
8792
8793 /* update maximum error */
8795
8796 prev = gray;
8797 }
8798
8799 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8800
8801 return maxerror;
8802}
8803
8804/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8805static
8807 SCIP* scip, /**< SCIP data structure */
8808 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8809 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8810 SCIP_Real* xstar, /**< point to be separated */
8811 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8812 int nallvars, /**< half of the length of box */
8813 int* nonfixedpos, /**< indices of nonfixed variables */
8814 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8815 int nvars, /**< number of nonfixed variables */
8816 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8817 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8818 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8819 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8820 )
8821{ /*lint --e{715}*/
8822 SCIP_CONSHDLRDATA* conshdlrdata;
8823 SCIP_LPI* lp;
8824 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8825 int* inds;
8826 int ncols;
8827 int nrows;
8828 int i;
8829 SCIP_Real facetvalue;
8830 SCIP_Real mindomwidth;
8832
8833 assert(scip != NULL);
8834 assert(conshdlr != NULL);
8835 assert(xstar != NULL);
8836 assert(box != NULL);
8838 assert(funvals != NULL);
8839 assert(nvars >= 0);
8841 assert(success != NULL);
8844
8845 *success = FALSE;
8846
8847 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8848 assert(conshdlrdata != NULL);
8849
8850 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8851 {
8852 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8853 }
8854
8855 /* construct an LP for this size, if not having one already */
8856 if( conshdlrdata->vp_lp[nvars] == NULL )
8857 {
8858 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8859 }
8860 lp = conshdlrdata->vp_lp[nvars];
8861 assert(lp != NULL);
8862
8863 /* get number of cols and rows of separation lp */
8864 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8865 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8866
8867 /* number of columns should equal the number of corners = 2^nvars */
8868 assert(ncols == (int)POWEROFTWO(nvars));
8869
8870 /* allocate necessary memory */
8871 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8872 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8873
8874 /*
8875 * set up the described LP on the transformed space
8876 */
8877
8878 for( i = 0; i < ncols; ++i )
8879 inds[i] = i;
8880
8881 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8883 for( i = 0; i < nrows-1; ++i )
8884 {
8885 SCIP_Real solval;
8886 SCIP_Real lb;
8887 SCIP_Real ub;
8888 int varpos;
8889
8890 assert(i < nvars);
8891
8892 varpos = nonfixedpos[i];
8893 lb = box[2 * varpos];
8894 ub = box[2 * varpos + 1];
8895 solval = xstar[varpos];
8896
8897 if( ub - lb < mindomwidth )
8898 mindomwidth = ub - lb;
8899
8900 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
8901 if( solval <= lb )
8902 aux[i] = 0.0;
8903 else if( solval >= ub )
8904 aux[i] = 1.0;
8905 else
8906 aux[i] = (solval - lb) / (ub - lb);
8907
8908 /* perturb point to hopefully obtain a facet of the convex envelope */
8909 if( conshdlrdata->vp_maxperturb > 0.0 )
8910 {
8911 assert(conshdlrdata->vp_randnumgen != NULL);
8912
8913 if( aux[i] == 1.0 )
8914 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8915 else if( aux[i] == 0.0 )
8916 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8917 else
8918 {
8919 SCIP_Real perturbation;
8920
8921 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
8922 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
8923 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
8924 }
8925 assert(0.0 < aux[i] && aux[i] < 1.0);
8926 }
8927
8928 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
8929 }
8930
8931 /* update LP */
8932 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
8933 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
8935
8936 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
8937 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
8938 {
8939 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
8940 }
8941 /* set an iteration limit so we do not run forever */
8943 /* 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 */
8945 /* since we work with the dual of the LP, dual feastol determines validity of the facet
8946 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
8947 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
8948 */
8950
8951#ifdef SCIP_DEBUG
8953#endif
8954
8955 /*
8956 * solve the LP and store the resulting facet for the transformed space
8957 */
8958 if( conshdlrdata->vp_dualsimplex )
8959 {
8961 }
8962 else
8963 {
8965 }
8967 {
8968 SCIPdebugMsg(scip, "LP error, aborting.\n");
8969 goto CLEANUP;
8970 }
8972
8973 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
8974 if( !SCIPlpiIsDualFeasible(lp) )
8975 {
8976 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
8977 goto CLEANUP;
8978 }
8979
8980 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
8981 * columns than needed, in particular, \bar \beta is the last dual multiplier
8982 */
8983 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
8984
8985 for( i = 0; i < nvars; ++i )
8986 facetcoefs[nonfixedpos[i]] = aux[i];
8987 /* last dual multiplier is the constant */
8988 *facetconstant = aux[nrows - 1];
8989
8990#ifdef SCIP_DEBUG
8991 SCIPdebugMsg(scip, "facet for the transformed problem: ");
8992 for( i = 0; i < nallvars; ++i )
8993 {
8994 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
8995 }
8996 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
8997#endif
8998
8999 /*
9000 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9001 */
9002
9003 SCIPdebugMsg(scip, "facet in orig. space: ");
9004
9005 facetvalue = 0.0;
9006 for( i = 0; i < nvars; ++i )
9007 {
9008 SCIP_Real lb;
9009 SCIP_Real ub;
9010 int varpos;
9011
9012 varpos = nonfixedpos[i];
9013 lb = box[2 * varpos];
9014 ub = box[2 * varpos + 1];
9015 assert(!SCIPisEQ(scip, lb, ub));
9016
9017 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9018 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9019
9020 /* beta = beta_bar - sum_i alpha_i * lb_i */
9021 *facetconstant -= facetcoefs[varpos] * lb;
9022
9023 /* evaluate */
9024 facetvalue += facetcoefs[varpos] * xstar[varpos];
9025
9026 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9027 }
9029
9030 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9032
9033 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9034
9035 /* if overestimate, then we want facetvalue < targetvalue
9036 * if underestimate, then we want facetvalue > targetvalue
9037 * if none holds, give up
9038 * so maybe here we should check against the minimal violation
9039 */
9040 if( overestimate == (facetvalue > targetvalue) )
9041 {
9042 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9043 goto CLEANUP;
9044 }
9045
9046 /* if we made it until here, then we have a nice facet */
9047 *success = TRUE;
9048
9049CLEANUP:
9050 /* free allocated memory */
9051 SCIPfreeBufferArray(scip, &inds);
9053
9054 return SCIP_OKAY;
9055}
9056
9057/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9058 *
9059 * In other words, compute the line that passes through two given points.
9060 */
9061static
9063 SCIP* scip, /**< SCIP data structure */
9064 SCIP_Real left, /**< left coordinate */
9065 SCIP_Real right, /**< right coordinate */
9066 SCIP_Real funleft, /**< value of function in left coordinate */
9067 SCIP_Real funright, /**< value of function in right coordinate */
9068 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9069 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9070 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9071 )
9072{
9073 assert(scip != NULL);
9074 assert(SCIPisLE(scip, left, right));
9075 assert(!SCIPisInfinity(scip, -left));
9076 assert(!SCIPisInfinity(scip, right));
9079 assert(success != NULL);
9080 assert(facetcoef != NULL);
9082
9083 *facetcoef = (funright - funleft) / (right - left);
9084 *facetconstant = funleft - *facetcoef * left;
9085
9086 *success = TRUE;
9087
9088 return SCIP_OKAY;
9089}
9090
9091/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9092 *
9093 * Three points a, b, and c are given.
9094 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9095 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9096 */
9097static
9099 SCIP* scip, /**< SCIP data structure */
9100 SCIP_Real a1, /**< first coordinate of a */
9101 SCIP_Real a2, /**< second coordinate of a */
9102 SCIP_Real a3, /**< third coordinate of a */
9103 SCIP_Real b1, /**< first coordinate of b */
9104 SCIP_Real b2, /**< second coordinate of b */
9105 SCIP_Real b3, /**< third coordinate of b */
9106 SCIP_Real c1, /**< first coordinate of c */
9107 SCIP_Real c2, /**< second coordinate of c */
9108 SCIP_Real c3, /**< third coordinate of c */
9109 SCIP_Real* alpha, /**< coefficient of first coordinate */
9110 SCIP_Real* beta, /**< coefficient of second coordinate */
9111 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9112 SCIP_Real* delta /**< constant right-hand side */
9113 )
9114{
9115 assert(scip != NULL);
9116 assert(alpha != NULL);
9117 assert(beta != NULL);
9118 assert(gamma_ != NULL);
9119 assert(delta != NULL);
9120
9121 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9122 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9123 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9124 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9125
9126 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9127
9128 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9131 {
9132 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9133 *delta = 0.0;
9134 *alpha = 0.0;
9135 *beta = 0.0;
9136 *gamma_ = 0.0;
9137 return SCIP_OKAY;
9138 }
9139
9140 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9141 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9142 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9143 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9144 {
9145 SCIP_Real m[9];
9146 SCIP_Real rhs[3];
9147 SCIP_Real x[3];
9148 SCIP_Bool success;
9149
9150 /*
9151 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));
9152 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));
9153 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));
9154 */
9155
9156 /* initialize matrix column-wise */
9157 m[0] = a1;
9158 m[1] = b1;
9159 m[2] = c1;
9160 m[3] = a2;
9161 m[4] = b2;
9162 m[5] = c2;
9163 m[6] = a3;
9164 m[7] = b3;
9165 m[8] = c3;
9166
9167 rhs[0] = 1.0;
9168 rhs[1] = 1.0;
9169 rhs[2] = 1.0;
9170
9171 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9172
9173 /* solve the linear problem */
9175
9176 *delta = rhs[0];
9177 *alpha = x[0];
9178 *beta = x[1];
9179 *gamma_ = x[2];
9180
9181 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9182 * not add a cut to SCIP and that all assertions are trivially fulfilled
9183 */
9184 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9185 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9186 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9187 {
9188 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9189 *delta = 0.0;
9190 *alpha = 0.0;
9191 *beta = 0.0;
9192 *gamma_ = 0.0;
9193 }
9194 }
9195
9196 if( *gamma_ < 0.0 )
9197 {
9198 *alpha = -*alpha;
9199 *beta = -*beta;
9200 *gamma_ = -*gamma_;
9201 *delta = -*delta;
9202 }
9203
9204 return SCIP_OKAY;
9205}
9206
9207/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9208static
9210 SCIP* scip, /**< SCIP data structure */
9211 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9212 SCIP_Real p1[2], /**< first vertex of box */
9213 SCIP_Real p2[2], /**< second vertex of box */
9214 SCIP_Real p3[2], /**< third vertex of box */
9215 SCIP_Real p4[2], /**< forth vertex of box */
9216 SCIP_Real p1val, /**< value in p1 */
9217 SCIP_Real p2val, /**< value in p2 */
9218 SCIP_Real p3val, /**< value in p3 */
9219 SCIP_Real p4val, /**< value in p4 */
9220 SCIP_Real xstar[2], /**< point to be separated */
9221 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9222 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9223 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9224 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9225 )
9226{
9227 SCIP_Real alpha, beta, gamma_, delta;
9228 SCIP_Real xstarval, candxstarval = 0.0;
9229 int leaveout;
9230
9231 assert(scip != NULL);
9232 assert(success != NULL);
9239
9240 *success = FALSE;
9241
9242 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9243 if( !overestimate )
9244 {
9245 p1val = -p1val;
9246 p2val = -p2val;
9247 p3val = -p3val;
9248 p4val = -p4val;
9249 targetvalue = -targetvalue;
9250 }
9251
9252 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9253 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9254 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9255 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9256
9257 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9258 * alpha*x + beta*y + gamma*z = delta
9259 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9260 * the fourth corner point lies below this hyperplane.
9261 * 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.,
9262 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9263 * or, equivalently,
9264 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9265 */
9266 for( leaveout = 1; leaveout <= 4; ++leaveout )
9267 {
9268 switch( leaveout)
9269 {
9270 case 1 :
9271 /* get hyperplane through p2, p3, p4 */
9272 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9273 &alpha, &beta, &gamma_, &delta) );
9274 /* if not underestimating in p1, then go to next candidate */
9275 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9276 continue;
9277 break;
9278
9279 case 2 :
9280 /* get hyperplane through p1, p3, p4 */
9281 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9282 &alpha, &beta, &gamma_, &delta) );
9283 /* if not underestimating in p2, then go to next candidate */
9284 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9285 continue;
9286 break;
9287
9288 case 3 :
9289 /* get hyperplane through p1, p2, p4 */
9290 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9291 &alpha, &beta, &gamma_, &delta) );
9292 /* if not underestimating in p3, then go to next candidate */
9293 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9294 continue;
9295 break;
9296
9297 case 4 :
9298 /* get hyperplane through p1, p2, p3 */
9299 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9300 &alpha, &beta, &gamma_, &delta) );
9301 /* if not underestimating in p4, then stop */
9302 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9303 continue;
9304 break;
9305
9306 default: /* only for lint */
9308 beta = SCIP_INVALID;
9310 delta = SCIP_INVALID;
9311 break;
9312 }
9313
9314 /* check if bad luck: should not happen if numerics are fine */
9315 if( SCIPisZero(scip, gamma_) )
9316 continue;
9318
9319 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9321 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9322 continue;
9323
9324 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9325
9326 /* value of hyperplane candidate in xstar */
9327 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9328
9329 /* if reaching target and first or better than previous candidate, then update */
9330 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9331 {
9332 /* flip hyperplane */
9333 if( !overestimate )
9334 gamma_ = -gamma_;
9335
9336 facetcoefs[0] = -alpha/gamma_;
9337 facetcoefs[1] = -beta/gamma_;
9338 *facetconstant = delta/gamma_;
9339
9340 *success = TRUE;
9342 }
9343 }
9344
9345 return SCIP_OKAY;
9346}
9347
9348/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9349 * graph yet) in an array
9350 */
9351static
9353 SCIP* scip, /**< SCIP pointer */
9354 int** openidx, /**< address of openidx array */
9355 int nelems, /**< number of elements that need to be stored */
9356 int* maxnelems /**< pointer to store maximum number that can be stored */
9357 )
9358{
9359 assert(scip != NULL);
9360 assert(openidx != NULL);
9361 assert(maxnelems != NULL);
9362
9363 if( nelems > *maxnelems )
9364 {
9365 int newsize;
9366
9367 newsize = SCIPcalcMemGrowSize(scip, nelems);
9368 assert(newsize >= nelems);
9369
9371
9372 *maxnelems = newsize;
9373 }
9374
9375 return SCIP_OKAY;
9376}
9377
9378/** ensures that we can store information about local variables in an array */
9379static
9381 SCIP* scip, /**< SCIP pointer */
9382 SCIP_VAR*** vars, /**< address of variable array */
9383 SCIP_Real** vals, /**< address of value array */
9384 int nelems, /**< number of elements that need to be stored */
9385 int* maxnelems /**< pointer to store maximum number that can be stored */
9386 )
9387{
9388 assert(scip != NULL);
9389 assert(vars != NULL);
9390 assert(vals != NULL);
9391 assert(maxnelems != NULL);
9392
9393 if( nelems > *maxnelems )
9394 {
9395 int newsize;
9396
9397 newsize = SCIPcalcMemGrowSize(scip, nelems);
9399
9402
9403 *maxnelems = newsize;
9404 }
9405
9406 return SCIP_OKAY;
9407}
9408
9409/** tries to add gadget for finding signed permutations of bilinear products
9410 *
9411 * If a product has exactly two children being variables, negating both simultanteoulsy
9412 * is a signed permutation.
9413 */
9414static
9416 SCIP* scip, /**< SCIP pointer */
9417 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9418 SCIP_CONS* cons, /**< constraint containing product expression */
9419 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9420 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9421 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9422 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9423 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9424 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9425 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9426 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9427 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9428 )
9429{
9431 SCIP_EXPR** children;
9432 SCIP_VAR* var1 = NULL;
9433 SCIP_VAR* var2 = NULL;
9434 SCIP_Real val1 = 0.0;
9435 SCIP_Real val2 = 0.0;
9436 SCIP_Real coef;
9437 SCIP_Real prodval;
9438 SCIP_Real constant;
9439 int nlocvars;
9440 int optype;
9441 int nchildren;
9442 int prodidx;
9443 int coefidx1;
9444 int coefidx2;
9445 int childidx;
9446
9447 assert(scip != NULL);
9448 assert(expr != NULL);
9450 assert(graph != NULL);
9452 assert(consvars != NULL);
9453 assert(consvals != NULL);
9455 assert(*maxnconsvars > 0);
9457 assert(success != NULL);
9458
9459 *success = FALSE;
9460
9461 /* we require exactly two children being variables */
9462 nchildren = SCIPexprGetNChildren(expr);
9463 if( nchildren != 2 )
9464 return SCIP_OKAY;
9465
9466 children = SCIPexprGetChildren(expr);
9467 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9468 return SCIP_OKAY;
9469
9470 /* check whether each child is not multi-aggregated and is not shifted */
9472
9473 for( childidx = 0; childidx < 2; ++childidx )
9474 {
9475 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9476 (*consvals)[0] = 1.0;
9477 nlocvars = 1;
9478 constant = 0.0;
9479
9481 &constant, SCIPconsIsTransformed(cons)) );
9482
9483 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9484 return SCIP_OKAY;
9485
9486 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9487 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9488 return SCIP_OKAY;
9489
9490 /* store information about variables */
9491 if( childidx == 0 )
9492 {
9493 var1 = (*consvars)[0];
9494 val1 = (*consvals)[0];
9495 }
9496 else
9497 {
9498 var2 = (*consvars)[0];
9499 val2 = (*consvals)[0];
9500 }
9501 }
9502 assert(var1 != NULL);
9503 assert(var2 != NULL);
9504
9505 /* store the we handle the children */
9506 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9507 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9508
9510 assert(symdata != NULL);
9512
9514
9516
9517 /* add gadget modeling the product
9518 *
9519 * Since the constants are 0, each variable is centered at the origin, which leads to
9520 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9521 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9522 * negate both variables simulataneously.
9523 */
9527
9528 prodval = coef * val1 * val2;
9529
9530 /* introduce nodes for the product value and its negation; since flipping both variables
9531 * simultaneously is a signed symmetry, assign both nodes the same value
9532 */
9535
9539
9541 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9543 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9548
9549 *success = TRUE;
9550
9551 return SCIP_OKAY;
9552}
9553
9554/** returns whether an operator is even and, if yes, stores data about operator */
9555static
9557 SCIP* scip, /**< SCIP pointer */
9558 SCIP_EXPR* expr, /**< expression corresponding to operator */
9559 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
9560 * needed for symmetry computation */
9561 SCIP_Real* value /**< pointer to store value for symmetry computation */
9562 )
9563{
9565
9566 assert(scip != NULL);
9567 assert(expr != NULL);
9568 assert(hasvalue != NULL);
9569 assert(value != NULL);
9570
9571 /* check for different operators known to be even */
9572 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9573 {
9574 /* get remaining information needed for symmetry detection */
9575 if( SCIPisExprSignpower(scip, expr) )
9576 {
9578 assert(symdata != NULL);
9580
9582 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9583
9585 }
9586 else
9587 {
9588 assert(SCIPisExprCos(scip, expr));
9589 *hasvalue = FALSE;
9590 }
9591
9592 return TRUE;
9593 }
9594 else if( SCIPisExprPower(scip, expr) )
9595 {
9596 SCIP_Real exponent;
9597 int safeexponent;
9598
9599 /* only consider expressions corresponding to an even power */
9601 assert(symdata != NULL);
9603
9604 exponent = SCIPgetSymExprdataConstants(symdata)[0];
9606
9607 /* check whether the exponent is an even integer */
9608 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
9609 return FALSE;
9610
9611 /* deal with numerics */
9612 safeexponent = (int) (exponent + 0.5);
9613 if( safeexponent % 2 != 0 )
9614 return FALSE;
9615
9616 *hasvalue = TRUE;
9617 *value = exponent;
9618
9619 return TRUE;
9620 }
9621 else if( SCIPisExprAbs(scip, expr) )
9622 {
9623 *hasvalue = FALSE;
9624
9625 return TRUE;
9626 }
9627
9628 return FALSE;
9629}
9630
9631/** returns whether a variable is centered at 0 */
9632static
9634 SCIP* scip, /**< SCIP pointer */
9635 SCIP_VAR* var /**< variable to be checked */
9636 )
9637{
9638 assert(scip != NULL);
9639 assert(var != NULL);
9640
9642 return FALSE;
9643
9645 return TRUE;
9646
9648 return TRUE;
9649
9650 return FALSE;
9651}
9652
9653/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
9654static
9656 SCIP* scip, /**< SCIP pointer */
9657 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
9658 SCIP_EXPR* child, /**< child expression of evenopexpr */
9659 SCIP_CONS* cons, /**< constraint containing expression */
9660 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9661 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9662 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9663 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9664 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
9665 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
9666 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9667 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9668 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9669 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9670 )
9671{
9672 SCIP_VAR* var;
9673 SCIP_Real constant;
9674 SCIP_Real edgeweight;
9675 int nlocvars;
9676 int nodeidx;
9677 int optype;
9678 int thisopidx;
9679
9680 assert(scip != NULL);
9682 assert(child != NULL);
9683 assert(SCIPisExprVar(scip, child));
9684 assert(cons != NULL);
9685 assert(graph != NULL);
9686 assert(parentidx >= 0);
9687 assert(consvars != NULL);
9688 assert(consvals != NULL);
9690 assert(success != NULL);
9691
9692 *success = FALSE;
9693
9694 /* check whether child variable is (multi-)aggregated */
9695 var = SCIPgetVarExprVar(child);
9696 (*consvars)[0] = var;
9697 (*consvals)[0] = 1.0;
9698 constant = 0.0;
9699 nlocvars = 1;
9700
9703 SCIPconsIsTransformed(cons)) );
9704
9705 /* skip multi-aggregated variables or variables with domain not centered at 0 */
9706 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9707 return SCIP_OKAY;
9708
9709 if( !varIsCenteredAt0(scip, var) )
9710 return SCIP_OKAY;
9711
9712 /* store partial information for gadget */
9713 var = (*consvars)[0];
9714 edgeweight = (*consvals)[0];
9715
9716 /* add gadget to graph for even univariate expression */
9717 *success = TRUE;
9718
9720
9723
9725 TRUE, edgeweight) );
9727 TRUE, edgeweight) );
9728
9729 if( hassymval )
9730 {
9733 }
9734
9735 return SCIP_OKAY;
9736}
9737
9738/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
9739static
9741 SCIP* scip, /**< SCIP pointer */
9742 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
9743 SCIP_EXPR* child, /**< child expression of evenopexpr */
9744 SCIP_CONS* cons, /**< constraint containing expression */
9745 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9746 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9747 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9748 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9749 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
9750 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
9751 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9752 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9753 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9754 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9755 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9756 )
9757{
9758 SCIP_VAR* var;
9759 SCIP_Real constant;
9760 SCIP_Real weight;
9761 int nlocvars;
9762 int nodeidx;
9763 int optype;
9764 int thisopidx;
9765 int i;
9766
9767 assert(scip != NULL);
9769 assert(child != NULL);
9770 assert(SCIPisExprSum(scip, child));
9771 assert(cons != NULL);
9772 assert(graph != NULL);
9773 assert(parentidx >= 0);
9774 assert(consvars != NULL);
9775 assert(consvals != NULL);
9778 assert(success != NULL);
9779
9780 *success = FALSE;
9781
9782 /* check whether child variable is (multi-)aggregated and whether all children are variables */
9784
9786
9787 for( i = 0; i < nlocvars; ++i)
9788 {
9789 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
9790 {
9791 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
9792 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
9793 }
9794 else
9795 return SCIP_OKAY;
9796 }
9797 constant = SCIPgetConstantExprSum(child);
9798
9800 SCIPconsIsTransformed(cons)) );
9801
9802 /* we can only handle the case without constant and two variables with domain centered at origin */
9803 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
9804 return SCIP_OKAY;
9805 assert(nlocvars > 0);
9806
9807 var = (*consvars)[0];
9808 if( !varIsCenteredAt0(scip, var) )
9809 return SCIP_OKAY;
9810
9811 if( nlocvars == 2 )
9812 {
9813 var = (*consvars)[1];
9814 if( !varIsCenteredAt0(scip, var) )
9815 return SCIP_OKAY;
9816 }
9817
9818 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
9819 *success = TRUE;
9820 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
9821 {
9823 }
9824
9826
9829
9830 if( hassymval )
9831 {
9834 }
9835
9836 if( nlocvars == 1 )
9837 {
9838 var = (*consvars)[0];
9839 weight = (*consvals)[0];
9840
9842 TRUE, weight) );
9844 TRUE, weight) );
9845 }
9846 else
9847 {
9848 int dummyidx1;
9849 int dummyidx2;
9850
9851 /* add dummy nodes for gadget */
9854
9858
9859 /* connect dummy nodes with variables */
9860 for( i = 0; i < 2; ++i)
9861 {
9862 var = (*consvars)[i];
9863 weight = ABS((*consvals)[i]);
9864
9866 TRUE, weight) );
9868 TRUE, weight) );
9869 }
9870 }
9871
9872 return SCIP_OKAY;
9873}
9874
9875/** tries to add gadget for finding signed permutations of even univariate operators
9876 *
9877 * We handle two cases. First, if a univariate operator is even and has a variable
9878 * as child, negating the child is signed permutation. Second, the univariate operator
9879 * is even and has a weighted sum of two variables as child.
9880 */
9881static
9883 SCIP* scip, /**< SCIP pointer */
9884 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
9885 SCIP_CONS* cons, /**< constraint containing expression */
9886 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9887 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9888 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9889 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9890 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9891 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9892 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9893 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9894 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9895 )
9896{
9897 SCIP_EXPR* child;
9898 SCIP_Real val = 0.0;
9899 SCIP_Bool hasval = FALSE;
9900
9901 assert(scip != NULL);
9902 assert(expr != NULL);
9903 assert(graph != NULL);
9905 assert(consvars != NULL);
9906 assert(consvals != NULL);
9908 assert(*maxnconsvars > 0);
9910 assert(success != NULL);
9911
9912 *success = FALSE;
9913
9914 /* ignore variable or value expressions */
9915 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
9916 return SCIP_OKAY;
9917 assert(SCIPexprGetNChildren(expr) > 0);
9918
9919 /* ignore operators with too many children */
9920 if( SCIPexprGetNChildren(expr) > 1 )
9921 return SCIP_OKAY;
9922
9923 /* check whether operator is even */
9924 if( !isEvenOperator(scip, expr, &hasval, &val) )
9925 return SCIP_OKAY;
9926
9927 /* we can only treat the operator if its child is a variable or a sum */
9928 child = SCIPexprGetChildren(expr)[0];
9929 if( SCIPisExprVar(scip, child) )
9930 {
9932 hasval, val, consvars, consvals, maxnconsvars, success) );
9933 }
9934 else if( SCIPisExprSum(scip, child) )
9935 {
9937 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
9938 }
9939
9940 if( *success )
9941 {
9943 }
9944
9945 return SCIP_OKAY;
9946}
9947
9948/** compares two variable pointers */
9949static
9951{ /*lint --e{715}*/
9952 SCIP_VAR** vars;
9953 SCIP_VAR* var1;
9954 SCIP_VAR* var2;
9955
9956 vars = (SCIP_VAR**) dataptr;
9957
9958 var1 = vars[ind1];
9959 var2 = vars[ind2];
9960 assert(var1 != NULL);
9961 assert(var2 != NULL);
9962
9963 /* sort variables by their unique index */
9965 return -1;
9967 return 1;
9968
9969 return 0;
9970}
9971
9972/** gets domain center of a variable which has not semi-infinite domain */
9973static
9975 SCIP* scip, /**< SCIP pointer */
9976 SCIP_VAR* var /**< variable */
9977 )
9978{
9979 SCIP_Real ub;
9980 SCIP_Real lb;
9981
9982 ub = SCIPvarGetUbGlobal(var);
9983 lb = SCIPvarGetLbGlobal(var);
9984
9985 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
9986
9987 if ( SCIPisInfinity(scip, ub) )
9988 return 0.0;
9989
9990 return (ub + lb) / 2;
9991}
9992
9993/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
9994static
9996 SCIP* scip, /**< SCIP pointer */
9997 SCIP_EXPR* sumexpr, /**< sum expression */
9998 SCIP_CONS* cons, /**< constraint containing the sum expression */
9999 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10000 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10001 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10002 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10003 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10004 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10005 )
10006{
10008 SCIP_EXPR** children;
10011 SCIP_EXPR* child;
10012 SCIP_VAR** powvars;
10016 SCIP_VAR* var;
10017 SCIP_VAR* var2;
10018 SCIP_Real* sumcoefs;
10019 SCIP_Real constant;
10020 SCIP_Real constant2;
10021 SCIP_Real val;
10022 SCIP_Real val2;
10023 SCIP_Bool* powexprused = NULL;
10024 int* powperm = NULL;
10025 int* prodperm = NULL;
10026 int nchildren;
10027 int nlocvars;
10028 int nodeidx;
10029 int coefnodeidx1;
10030 int coefnodeidx2;
10031 int cnt;
10032 int i;
10033 int j;
10034 int nterms;
10035 int npowexprs = 0;
10036 int nprodexprs = 0;
10037 int powcoef = 0;
10038
10039 assert(scip != NULL);
10040 assert(sumexpr != NULL);
10041 assert(cons != NULL);
10043 assert(consvars != NULL);
10044 assert(consvals != NULL);
10046 assert(*maxnconsvars > 0);
10048
10049 /* iterate over sum expression and extract all power and product expressions */
10051 children = SCIPexprGetChildren(sumexpr);
10052 nchildren = SCIPexprGetNChildren(sumexpr);
10054 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10055 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10056 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10057
10058 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10059 /** @todo make this work in a more general case */
10060 for( i = 0; i < nchildren; ++i )
10061 {
10062 if( SCIPisExprPower(scip, children[i]) )
10063 {
10064 SCIP_Real exponent;
10065
10066 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10067 if( powcoef == 0 )
10068 {
10069 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10070 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10071 }
10072 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10073 continue;
10074
10075 /* we only store power expressions if their child is a variable */
10076 assert(SCIPexprGetNChildren(children[i]) == 1);
10077 child = SCIPexprGetChildren(children[i])[0];
10078 if( !SCIPisExprVar(scip, child) )
10079 continue;
10080
10081 /* the power is required to be a 2 */
10082 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10083 assert(symdata != NULL);
10085
10086 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10088
10089 if( !SCIPisEQ(scip, exponent, 2.0) )
10090 continue;
10091
10092 /* we only store power expressions if the child is not multi-aggregated */
10093 var = SCIPgetVarExprVar(child);
10095 {
10096 powexprs[npowexprs] = children[i];
10097 powvars[npowexprs++] = var;
10098 }
10099 }
10100 else if( SCIPisExprProduct(scip, children[i]) )
10101 {
10102 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10103 if( powcoef == 0 )
10104 {
10105 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10106 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10107 }
10108 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10109 continue;
10110
10111 /* we only store power expressions if they have exactly two children being variables */
10112 if( SCIPexprGetNChildren(children[i]) != 2 )
10113 continue;
10114 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10115 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10116 continue;
10117
10118 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10120
10121 /* we only store product expressions if the children are not multi-aggregated */
10124 {
10125 prodexprs[nprodexprs] = children[i];
10126 prodvars[nprodexprs++] = var;
10127 prodexprs[nprodexprs] = children[i];
10129 }
10130 }
10131 }
10132
10133 if( npowexprs == 0 || nprodexprs != npowexprs )
10134 goto FREEMEMORY;
10135
10136 /* check whether the power variables and product variables match */
10139
10142
10143 for( i = 0; i < npowexprs; ++i )
10144 {
10146 goto FREEMEMORY;
10147 }
10148
10149 /* if we reach this line, the variables match: we have found a potential norm constraint */
10150 assert(npowexprs % 2 == 0);
10151 nterms = npowexprs / 2;
10153
10154 /* add gadget of each squared difference term */
10155 cnt = 0;
10156 for( i = 0; i < nterms; ++i )
10157 {
10158 SCIP_Bool var1found = FALSE;
10159 SCIP_Bool var2found = FALSE;
10160
10161 (*consvals)[0] = 1.0;
10162 (*consvars)[0] = prodvars[cnt++];
10163 constant = 0.0;
10164 nlocvars = 1;
10165
10167 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10168
10169 if( nlocvars != 1 )
10170 {
10171 ++cnt;
10172 continue;
10173 }
10174 actvar = (*consvars)[0];
10175 val = (*consvals)[0];
10176
10177 (*consvals)[0] = 1.0;
10178 (*consvars)[0] = prodvars[cnt++];
10179 constant2 = 0.0;
10180 nlocvars = 1;
10181
10184
10185 if( nlocvars != 1 )
10186 continue;
10187 actvar2 = (*consvars)[0];
10188 val2 = (*consvals)[0];
10189
10190 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10191 * cannot be centered at the origin or they are not centered around the same point
10192 */
10193 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10198 continue;
10199
10200 /* add gadget */
10204
10205 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10209 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10211 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10216
10217 /* mark product expression as handled */
10219
10220 /* find corresponding unused power expressions and mark them as handled */
10221 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10222 {
10223 if( powexprused[j] )
10224 continue;
10225 assert(cnt >= 2);
10226
10227 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10228 {
10230 powexprused[j] = TRUE;
10231 var1found = TRUE;
10232 }
10233 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10234 {
10236 powexprused[j] = TRUE;
10237 var2found = TRUE;
10238 }
10239 }
10240 }
10241
10242 FREEMEMORY:
10250
10251 return SCIP_OKAY;
10252}
10253
10254/** adds symmetry information of constraint to a symmetry detection graph */
10255static
10257 SCIP* scip, /**< SCIP pointer */
10258 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10259 SCIP_CONS* cons, /**< constraint */
10260 SYM_GRAPH* graph, /**< symmetry detection graph */
10261 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10262 )
10263{ /*lint --e{850}*/
10267 SCIP_EXPR* expr;
10268 SCIP_VAR** consvars;
10269 SCIP_Real* consvals;
10270 SCIP_Real constant;
10271 SCIP_Real parentcoef = 0.0;
10272 int* openidx;
10273 int maxnopenidx;
10274 int parentidx;
10275 int nconsvars;
10276 int maxnconsvars;
10277 int nlocvars;
10278 int nopenidx = 0;
10279 int consnodeidx;
10280 int nodeidx;
10281 int i;
10282 SCIP_Bool iscolored;
10283 SCIP_Bool hasparentcoef;
10284
10285 assert(scip != NULL);
10286 assert(cons != NULL);
10287 assert(graph != NULL);
10288 assert(success != NULL);
10289
10290 /* store lhs/rhs */
10293
10295 assert(rootexpr != NULL);
10296
10297 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10298 expr = SCIPgetExprNonlinear(cons);
10299 assert(expr != NULL);
10300
10304
10305 /* find potential number of nodes in graph */
10306 maxnopenidx = 0;
10308 {
10310 continue;
10311
10312 ++maxnopenidx;
10313 }
10314
10316
10320
10321 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10323
10324 /* iterate over expression tree and store nodes/edges */
10325 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10328
10330 {
10331 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10333 {
10335
10336 baseexpr = expr;
10338 expr = SCIPexpriterGetNext(it);
10339
10340 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10341
10342 /* leave the expression */
10343 continue;
10344 }
10345
10346 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10348 {
10349 --nopenidx;
10350 continue;
10351 }
10353
10354 /* find parentidx */
10355 if( expr == rootexpr )
10357 else
10358 {
10359 assert(nopenidx >= 1);
10360 parentidx = openidx[nopenidx - 1];
10361 }
10362
10363 /* possibly find a coefficient assigned to the expression by the parent */
10365 if ( expr != rootexpr )
10366 {
10368 }
10369
10370 /* deal with different kinds of expressions and store them in the symmetry data structure */
10371 if( SCIPisExprVar(scip, expr) )
10372 {
10373 /* needed to correctly reset value when leaving expression */
10375
10376 openidx[nopenidx++] = -1;
10377
10378 assert(maxnconsvars > 0);
10379 assert(parentidx > 0);
10380
10381 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10382 if( hasparentcoef )
10383 {
10384 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10385
10386 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10388 }
10389
10390 /* connect (aggregation of) variable expression with its parent */
10391 nconsvars = 1;
10392 consvars[0] = SCIPgetVarExprVar(expr);
10393 consvals[0] = 1.0;
10394 constant = 0.0;
10395
10396 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10397 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10398
10399 /* check whether variable is aggregated */
10400 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10401 {
10402 int thisidx;
10403
10404 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10406
10408 }
10410 nconsvars, constant) );
10411 }
10412 else if( SCIPisExprValue(scip, expr) )
10413 {
10414 assert(parentidx > 0);
10415
10417
10419
10420 /* needed to correctly reset value when leaving expression */
10422
10423 openidx[nopenidx++] = -1;
10424 }
10425 else
10426 {
10427 SCIP_Bool usedefaultgadget = TRUE;
10428
10429 assert(expr == rootexpr || parentidx > 0);
10431
10432 if( SCIPisExprSum(scip, expr) )
10433 {
10434 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10435 SCIP_EXPR** children;
10436 int sumidx;
10437 int optype;
10438 int childidx = 0;
10439
10440 /* sums are handled by a special gadget */
10442
10443 /* extract all children being variables and compute the sum of active variables expression */
10444 nlocvars = 0;
10445 children = SCIPexprGetChildren(expr);
10446
10448
10449 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10450 {
10451 if( !SCIPisExprVar(scip, children[childidx]) )
10452 continue;
10453
10454 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10456
10457 /* store that we have already handled this expression */
10459 }
10460
10461 constant = SCIPgetConstantExprSum(expr);
10462
10463 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10464 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10465
10467
10470
10471 /* add the linear part of the sum */
10472 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10473
10475
10476 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10477 if( symtype == SYM_SYMTYPE_SIGNPERM )
10478 {
10480 &consvars, &consvals, &maxnconsvars, handledexprs) );
10481 }
10482
10483 /* store sumidx for children that have not been treated */
10484 openidx[nopenidx++] = sumidx;
10485 }
10486 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10487 {
10488 SCIP_Bool succ;
10489
10491 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10492
10493 if( succ )
10494 {
10497 }
10498 }
10499 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10500 {
10501 SCIP_Bool succ;
10502
10503 /* we can find more signed permutations for even univariate operators */
10505 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10506
10507 if( succ )
10508 {
10511 }
10512 }
10513
10514 if( usedefaultgadget )
10515 {
10516 int opidx;
10517 int optype;
10518
10522
10523 /* possibly add constants of expression */
10525 {
10527
10529 assert(symdata != NULL);
10530
10531 /* if expression has multiple constants, assign colors to edges to distinguish them */
10533 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10534 {
10536 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10537 }
10538
10540 }
10541
10543
10544 openidx[nopenidx++] = opidx;
10545 }
10546 }
10547 }
10548
10551 SCIPfreeBufferArray(scip, &consvars);
10554
10555 return SCIP_OKAY;
10556}
10557
10558/*
10559 * Callback methods of constraint handler
10560 */
10561
10562/** copy method for constraint handler plugins (called when SCIP copies plugins) */
10563static
10565{ /*lint --e{715}*/
10568 int i;
10569
10570 assert(scip != NULL);
10571 assert(conshdlr != NULL);
10572 assert(valid != NULL);
10574
10575 /* create basic data of constraint handler and include it to scip */
10577
10580 assert(targetconshdlr != conshdlr);
10581
10584
10585 /* copy nonlinear handlers */
10586 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10587 {
10589 }
10590
10591 *valid = TRUE;
10592
10593 return SCIP_OKAY;
10594}
10595
10596/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10597static
10599{ /*lint --e{715}*/
10600 SCIP_CONSHDLRDATA* conshdlrdata;
10601 int i;
10602
10603 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10604 assert(conshdlrdata != NULL);
10605
10606 /* free nonlinear handlers */
10607 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10608 {
10609 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
10610 assert(conshdlrdata->nlhdlrs[i] == NULL);
10611 }
10612 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
10613 conshdlrdata->nlhdlrssize = 0;
10614
10615 /* free upgrade functions */
10616 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
10617 {
10618 assert(conshdlrdata->consupgrades[i] != NULL);
10619 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
10620 }
10621 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
10622
10623 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
10624
10625 SCIPqueueFree(&conshdlrdata->reversepropqueue);
10626
10627 if( conshdlrdata->vp_randnumgen != NULL )
10628 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10629
10630 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10631 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10632 {
10633 if( conshdlrdata->vp_lp[i] != NULL )
10634 {
10635 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10636 }
10637 }
10638
10639 assert(conshdlrdata->branchrandnumgen == NULL);
10640
10641 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
10642 SCIPhashmapFree(&conshdlrdata->var2expr);
10643
10644 SCIPfreeBlockMemory(scip, &conshdlrdata);
10645 SCIPconshdlrSetData(conshdlr, NULL);
10646
10647 return SCIP_OKAY;
10648}
10649
10650
10651/** initialization method of constraint handler (called after problem was transformed) */
10652static
10654{ /*lint --e{715}*/
10655 SCIP_CONSHDLRDATA* conshdlrdata;
10656 int i;
10657
10658 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10659 assert(conshdlrdata != NULL);
10660
10661 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
10662 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
10663 /* set to 1 so it is larger than initial value of lastenforound in exprs */
10664 conshdlrdata->enforound = 1;
10665 /* reset numbering for auxiliary variables */
10666 conshdlrdata->auxvarid = 0;
10667
10668 for( i = 0; i < nconss; ++i )
10669 {
10670 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
10671 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
10672 }
10673
10674 /* sort nonlinear handlers by detection priority, in decreasing order */
10675 if( conshdlrdata->nnlhdlrs > 1 )
10676 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
10677
10678 /* get heuristics for later use */
10679 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
10680 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
10681
10682 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
10683 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10684 {
10685 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
10686 }
10687
10688 /* reset statistics in constraint handler */
10689 conshdlrdata->nweaksepa = 0;
10690 conshdlrdata->ntightenlp = 0;
10691 conshdlrdata->ndesperatebranch = 0;
10692 conshdlrdata->ndesperatecutoff = 0;
10693 conshdlrdata->ndesperatetightenlp = 0;
10694 conshdlrdata->nforcelp = 0;
10695 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
10696 conshdlrdata->ncanonicalizecalls = 0;
10697
10698#ifdef ENFOLOGFILE
10700#endif
10701
10702 return SCIP_OKAY;
10703}
10704
10705
10706/** deinitialization method of constraint handler (called before transformed problem is freed) */
10707static
10709{ /*lint --e{715}*/
10710 SCIP_CONSHDLRDATA* conshdlrdata;
10711 SCIP_CONS** consssorted;
10712 int i;
10713
10714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10715 assert(conshdlrdata != NULL);
10716
10717 if( nconss > 0 )
10718 {
10719 /* for better performance of dropVarEvents, we sort by index, descending */
10720 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
10721 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
10722
10723 for( i = 0; i < nconss; ++i )
10724 {
10725 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
10726 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
10727 }
10728
10729 SCIPfreeBufferArray(scip, &consssorted);
10730 }
10731
10732 conshdlrdata->subnlpheur = NULL;
10733 conshdlrdata->trysolheur = NULL;
10734
10735 if( conshdlrdata->vp_randnumgen != NULL )
10736 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10737
10738 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10739 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10740 {
10741 if( conshdlrdata->vp_lp[i] != NULL )
10742 {
10743 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10744 }
10745 }
10746
10747 if( conshdlrdata->branchrandnumgen != NULL )
10748 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
10749
10750 /* deinitialize nonlinear handlers */
10751 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10752 {
10753 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
10754 }
10755
10756 ENFOLOG(
10757 if( enfologfile != NULL )
10758 {
10760 enfologfile = NULL;
10761 })
10762
10763 return SCIP_OKAY;
10764}
10765
10766
10767/** presolving initialization method of constraint handler (called when presolving is about to begin) */
10768#ifdef SCIP_DISABLED_CODE
10769static
10771{ /*lint --e{715}*/
10772 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10773 SCIPABORT(); /*lint --e{527}*/
10774
10775 return SCIP_OKAY;
10776}
10777#else
10778#define consInitpreNonlinear NULL
10779#endif
10780
10781
10782/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
10783static
10785{ /*lint --e{715}*/
10786 SCIP_Bool infeasible;
10787
10788 if( nconss == 0 )
10789 return SCIP_OKAY;
10790
10791 /* skip some extra work if already known to be infeasible */
10793 return SCIP_OKAY;
10794
10795 /* simplify constraints and replace common subexpressions */
10796 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
10797
10798 /* currently SCIP does not offer to communicate this,
10799 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
10800 * or if a constraint expression became constant
10801 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
10802 */
10803 /* assert(!infeasible); */
10804
10805 /* tell SCIP that we have something nonlinear */
10807
10808 return SCIP_OKAY;
10809}
10810
10811
10812/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
10813static
10815{ /*lint --e{715}*/
10816 SCIP_CONSHDLRDATA* conshdlrdata;
10817 int i;
10818
10819 /* skip remaining initializations if we have solved already
10820 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
10821 * assumes nonempty activities in expressions
10822 */
10823 switch( SCIPgetStatus(scip) )
10824 {
10829 return SCIP_OKAY;
10830 default: ;
10831 } /*lint !e788 */
10832
10833 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10834 assert(conshdlrdata != NULL);
10835
10836 /* reset one of the number of detections counter to count only current round */
10837 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10838 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
10839
10840 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
10841
10842 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
10843 if( conshdlrdata->branchpscostweight > 0.0 )
10844 {
10845 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
10846 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
10847 {
10848 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
10849 SCIPABORT();
10850 return SCIP_INVALIDDATA;
10851 }
10852 }
10853
10854 return SCIP_OKAY;
10855}
10856
10857
10858/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
10859static
10861{ /*lint --e{715}*/
10862 SCIP_CONSHDLRDATA* conshdlrdata;
10863
10864 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
10865
10866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10867 assert(conshdlrdata != NULL);
10868
10869 /* free hash table for bilinear terms */
10870 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
10871
10872 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
10873 conshdlrdata->checkedvarlocks = FALSE;
10874
10875 /* drop catching new solution event, if catched before */
10876 if( conshdlrdata->newsoleventfilterpos >= 0 )
10877 {
10878 SCIP_EVENTHDLR* eventhdlr;
10879
10880 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
10881 assert(eventhdlr != NULL);
10882
10883 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
10884 conshdlrdata->newsoleventfilterpos = -1;
10885 }
10886
10887 return SCIP_OKAY;
10888}
10889
10890
10891/** frees specific constraint data */
10892static
10894{ /*lint --e{715}*/
10895 assert(consdata != NULL);
10896 assert(*consdata != NULL);
10897 assert((*consdata)->expr != NULL);
10898
10899 /* constraint locks should have been removed */
10900 assert((*consdata)->nlockspos == 0);
10901 assert((*consdata)->nlocksneg == 0);
10902
10903 /* free variable expressions */
10904 SCIP_CALL( freeVarExprs(scip, *consdata) );
10905
10906 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
10907
10908 /* free nonlinear row representation */
10909 if( (*consdata)->nlrow != NULL )
10910 {
10911 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
10912 }
10913
10914 SCIPfreeBlockMemory(scip, consdata);
10915
10916 return SCIP_OKAY;
10917}
10918
10919
10920/** transforms constraint data into data belonging to the transformed problem */
10921static
10923{ /*lint --e{715}*/
10926
10929
10930 /* get a copy of sourceexpr with transformed vars */
10931 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
10932 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
10933
10934 /* create transformed cons (only captures targetexpr, no need to copy again) */
10941
10942 /* release target expr */
10944
10945 return SCIP_OKAY;
10946}
10947
10948
10949/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
10950static
10952{ /*lint --e{715}*/
10953 SCIP_CONSHDLRDATA* conshdlrdata;
10954
10955 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
10956 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
10957 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
10958 * for now, there is an assert in detectNlhdlrs to require initial if separated
10959 */
10960 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
10961
10962 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10963 assert(conshdlrdata != NULL);
10964
10965 /* catch new solution event */
10966 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
10967 {
10968 SCIP_EVENTHDLR* eventhdlr;
10969
10970 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
10971 assert(eventhdlr != NULL);
10972
10973 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
10974 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
10975 }
10976
10977 /* collect all bilinear terms for which an auxvar is present
10978 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
10979 * addition (and removal?) of constraints during solve
10980 * this is typically the majority of constraints, but the method should be made more flexible
10981 */
10982 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
10983
10984 return SCIP_OKAY;
10985}
10986
10987
10988/** separation method of constraint handler for LP solutions */
10989static
10991{ /*lint --e{715}*/
10992 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
10993
10994 return SCIP_OKAY;
10995}
10996
10997
10998/** separation method of constraint handler for arbitrary primal solutions */
10999static
11001{ /*lint --e{715}*/
11002 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11003
11004 return SCIP_OKAY;
11005}
11006
11007
11008/** constraint enforcing method of constraint handler for LP solutions */
11009static
11011{ /*lint --e{715}*/
11012 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11013
11014 return SCIP_OKAY;
11015}
11016
11017
11018/** constraint enforcing method of constraint handler for relaxation solutions */
11019static
11021{ /*lint --e{715}*/
11022 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11023
11024 return SCIP_OKAY;
11025}
11026
11027
11028/** constraint enforcing method of constraint handler for pseudo solutions */
11029static
11031{ /*lint --e{715}*/
11033 SCIP_Longint soltag;
11034 int nchgbds;
11035 int nnotify;
11036 int c;
11037
11039
11041 for( c = 0; c < nconss; ++c )
11042 {
11044
11045 if( isConsViolated(scip, conss[c]) )
11047 }
11048
11049 if( *result == SCIP_FEASIBLE )
11050 return SCIP_OKAY;
11051
11052 /* try to propagate
11053 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11054 */
11055 nchgbds = 0;
11056 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11057
11059 {
11060 *result = propresult;
11061 return SCIP_OKAY;
11062 }
11063
11064 /* register all unfixed variables in all violated constraints as branching candidates */
11065 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11066 if( nnotify > 0 )
11067 {
11068 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11069
11070 return SCIP_OKAY;
11071 }
11072
11073 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11075 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11076
11077 return SCIP_OKAY;
11078}
11079
11080
11081/** feasibility check method of constraint handler for integral solutions */
11082static
11084{ /*lint --e{715}*/
11085 SCIP_CONSHDLRDATA* conshdlrdata;
11086 SCIP_CONSDATA* consdata;
11087 SCIP_Real maxviol;
11088 SCIP_Bool maypropfeasible;
11089 SCIP_Longint soltag;
11090 int c;
11091
11092 assert(scip != NULL);
11093 assert(conshdlr != NULL);
11094 assert(conss != NULL || nconss == 0);
11095 assert(result != NULL);
11096
11097 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11098 assert(conshdlrdata != NULL);
11099
11102 maxviol = 0.0;
11103 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11105
11108
11109 /* check nonlinear constraints for feasibility */
11110 for( c = 0; c < nconss; ++c )
11111 {
11112 assert(conss != NULL && conss[c] != NULL);
11113 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11114
11115 if( isConsViolated(scip, conss[c]) )
11116 {
11118 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11119
11120 consdata = SCIPconsGetData(conss[c]);
11121 assert(consdata != NULL);
11122
11123 /* print reason for infeasibility */
11124 if( printreason )
11125 {
11126 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11127 SCIPinfoMessage(scip, NULL, ";\n");
11128
11129 if( consdata->lhsviol > SCIPfeastol(scip) )
11130 {
11131 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11132 }
11133 if( consdata->rhsviol > SCIPfeastol(scip) )
11134 {
11135 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11136 }
11137 }
11138 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11139 {
11140 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11141 return SCIP_OKAY;
11142 }
11143
11144 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11147
11148 if( maypropfeasible )
11149 {
11150 if( consdata->lhsviol > SCIPfeastol(scip) )
11151 {
11152 /* check if there is a variable which may help to get the left hand side satisfied
11153 * if there is no such variable, then we cannot get feasible
11154 */
11155 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11156 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11158 }
11159 else
11160 {
11161 assert(consdata->rhsviol > SCIPfeastol(scip));
11162 /* check if there is a variable which may help to get the right hand side satisfied
11163 * if there is no such variable, then we cannot get feasible
11164 */
11165 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11166 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11168 }
11169 }
11170 }
11171 }
11172
11174 {
11175 SCIP_Bool success;
11176
11177 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11178
11179 /* do not pass solution to NLP heuristic if we made it feasible this way */
11180 if( success )
11181 return SCIP_OKAY;
11182 }
11183
11184 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11185 {
11186 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11187 }
11188
11189 return SCIP_OKAY;
11190}
11191
11192
11193/** domain propagation method of constraint handler */
11194static
11196{ /*lint --e{715}*/
11197 int nchgbds = 0;
11198
11199 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11200 assert(nchgbds >= 0);
11201
11202 /* TODO would it make sense to check for redundant constraints? */
11203
11204 return SCIP_OKAY;
11205}
11206
11207
11208/** presolving method of constraint handler */
11209static
11211{ /*lint --e{715}*/
11212 SCIP_CONSHDLRDATA* conshdlrdata;
11213 SCIP_Bool infeasible;
11214 int c;
11215
11217
11218 if( nconss == 0 )
11219 {
11221 return SCIP_OKAY;
11222 }
11223
11224 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11225 assert(conshdlrdata != NULL);
11226
11227 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11228 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11229 if( infeasible )
11230 {
11232 return SCIP_OKAY;
11233 }
11234
11235 /* merge constraints with the same root expression */
11236 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11237 {
11238 SCIP_Bool success;
11239
11240 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11241 if( success )
11243 }
11244
11245 /* propagate constraints */
11246 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11247 if( *result == SCIP_CUTOFF )
11248 return SCIP_OKAY;
11249
11250 /* propagate function domains (TODO integrate with simplify?) */
11251 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11252 {
11254 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11255 if( localresult == SCIP_CUTOFF )
11256 {
11258 return SCIP_OKAY;
11259 }
11262 }
11263
11264 /* check for redundant constraints, remove constraints that are a value expression */
11265 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11266 if( infeasible )
11267 {
11269 return SCIP_OKAY;
11270 }
11271
11272 /* try to upgrade constraints */
11273 for( c = 0; c < nconss; ++c )
11274 {
11275 SCIP_Bool upgraded;
11276
11277 /* skip inactive and deleted constraints */
11278 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11279 continue;
11280
11281 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11282 }
11283
11284 /* try to change continuous variables that appear linearly to be implicit integer */
11285 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11286 {
11287 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11288
11289 if( infeasible )
11290 {
11291 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11293 return SCIP_OKAY;
11294 }
11295 }
11296
11297 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11299 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11300 {
11301 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11302 * constraints multiple times
11303 */
11304 conshdlrdata->checkedvarlocks = TRUE;
11305
11306 for( c = 0; c < nconss; ++c )
11307 {
11308 int tmpnchgvartypes = 0;
11309 int tmpnaddconss = 0;
11310
11311 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11312 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11313 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11314
11315 if( infeasible )
11316 {
11317 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11319 return SCIP_OKAY;
11320 }
11321
11322 (*nchgvartypes) += tmpnchgvartypes;
11323 (*naddconss) += tmpnaddconss;
11324 }
11325 }
11326
11327 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11329 else
11331
11332 return SCIP_OKAY;
11333}
11334
11335
11336/** propagation conflict resolving method of constraint handler */
11337#ifdef SCIP_DISABLED_CODE
11338static
11340{ /*lint --e{715}*/
11341 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11342 SCIPABORT(); /*lint --e{527}*/
11343
11344 return SCIP_OKAY;
11345}
11346#else
11347#define consRespropNonlinear NULL
11348#endif
11349
11350
11351/** variable rounding lock method of constraint handler */
11352static
11354{ /*lint --e{715}*/
11355 SCIP_CONSDATA* consdata;
11356 SCIP_EXPR_OWNERDATA* ownerdata;
11357 SCIP_Bool reinitsolve = FALSE;
11358
11359 assert(conshdlr != NULL);
11360 assert(cons != NULL);
11361
11362 consdata = SCIPconsGetData(cons);
11363 assert(consdata != NULL);
11364 assert(consdata->expr != NULL);
11365
11366 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11367
11368 /* check whether we need to initSolve again because
11369 * - we have enfo initialized (nenfos >= 0)
11370 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11371 */
11372 if( ownerdata->nenfos >= 0 )
11373 {
11374 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11375 reinitsolve = TRUE;
11376 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11377 reinitsolve = TRUE;
11378 }
11379
11380 if( reinitsolve )
11381 {
11382 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11383 }
11384
11385 /* add locks */
11386 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11387
11388 if( reinitsolve )
11389 {
11390 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11391 }
11392
11393 return SCIP_OKAY;
11394}
11395
11396
11397/** constraint activation notification method of constraint handler */
11398static
11400{ /*lint --e{715}*/
11401 SCIP_CONSDATA* consdata;
11402 SCIP_Bool infeasible = FALSE;
11403
11404 consdata = SCIPconsGetData(cons);
11405 assert(consdata != NULL);
11406
11407 /* simplify root expression if the constraint has been added after presolving */
11409 {
11410 SCIP_Bool replacedroot;
11411
11412 if( !consdata->issimplified )
11413 {
11415 SCIP_Bool changed;
11416
11417 /* simplify constraint */
11418 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11419 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11421 consdata->expr = simplified;
11422 consdata->issimplified = TRUE;
11423 }
11424
11425 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11427 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11428
11429 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11430 {
11431 SCIP_CONSHDLRDATA* conshdlrdata;
11433 SCIP_EXPR* expr;
11434
11435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11436 assert(conshdlrdata != NULL);
11437
11439 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11442 {
11443 SCIP_EXPR* child;
11445
11447 if( !SCIPisExprVar(scip, child) )
11448 continue;
11449
11450 /* check which expression is stored in the hashmap for the var of child */
11451 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11452 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11453 if( hashmapexpr != NULL && hashmapexpr != child )
11454 {
11456 }
11457 }
11459 }
11460 }
11461
11462 /* store variable expressions */
11464 {
11465 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11466 }
11467
11468 /* add manually locks to constraints that are not checked for feasibility */
11469 if( !SCIPconsIsChecked(cons) )
11470 {
11471 assert(consdata->nlockspos == 0);
11472 assert(consdata->nlocksneg == 0);
11473
11474 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11475 }
11476
11477 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11478 {
11479 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11480 }
11481
11482 /* TODO deal with infeasibility */
11483 assert(!infeasible);
11484
11485 return SCIP_OKAY;
11486}
11487
11488
11489/** constraint deactivation notification method of constraint handler */
11490static
11492{ /*lint --e{715}*/
11493 SCIP_CONSHDLRDATA* conshdlrdata;
11494
11495 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11496 assert(conshdlrdata != NULL);
11497
11499 {
11500 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11501 }
11502
11504 {
11505 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11507 }
11508
11509 /* remove locks that have been added in consActiveExpr() */
11510 if( !SCIPconsIsChecked(cons) )
11511 {
11512 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11513
11514 assert(SCIPconsGetData(cons)->nlockspos == 0);
11515 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11516 }
11517
11518 return SCIP_OKAY;
11519}
11520
11521
11522/** constraint enabling notification method of constraint handler */
11523static
11525{ /*lint --e{715}*/
11526 SCIP_CONSHDLRDATA* conshdlrdata;
11527
11528 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11529 assert(conshdlrdata != NULL);
11530
11532 {
11533 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11534 }
11535
11536 return SCIP_OKAY;
11537}
11538
11539
11540/** constraint disabling notification method of constraint handler */
11541static
11543{ /*lint --e{715}*/
11544 SCIP_CONSHDLRDATA* conshdlrdata;
11545
11546 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11547 assert(conshdlrdata != NULL);
11548
11550 {
11551 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11552 }
11553
11554 return SCIP_OKAY;
11555}
11556
11557/** variable deletion of constraint handler */
11558#ifdef SCIP_DISABLED_CODE
11559static
11561{ /*lint --e{715}*/
11562 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11563 SCIPABORT(); /*lint --e{527}*/
11564
11565 return SCIP_OKAY;
11566}
11567#else
11568#define consDelvarsNonlinear NULL
11569#endif
11570
11571
11572/** constraint display method of constraint handler */
11573static
11575{ /*lint --e{715}*/
11576 SCIP_CONSDATA* consdata;
11577
11578 consdata = SCIPconsGetData(cons);
11579 assert(consdata != NULL);
11580 assert(consdata->expr != NULL);
11581
11582 /* print left hand side for ranged constraints */
11583 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11584 {
11585 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11586 }
11587
11588 /* print expression */
11589 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11590
11591 /* print right hand side */
11592 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11593 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11594 else if( !SCIPisInfinity(scip, consdata->rhs) )
11595 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11596 else if( !SCIPisInfinity(scip, -consdata->lhs) )
11597 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11598 else
11599 SCIPinfoMessage(scip, file, " [free]");
11600
11601 return SCIP_OKAY;
11602}
11603
11604
11605/** constraint copying method of constraint handler */
11606static
11608{ /*lint --e{715}*/
11612
11613 assert(cons != NULL);
11614
11617
11620
11621 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
11622
11623 if( targetexpr == NULL )
11624 *valid = FALSE;
11625
11626 *cons = NULL;
11627 if( *valid )
11628 {
11629 /* create copy (only capture targetexpr, no need to copy again) */
11632 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11633 }
11634
11635 if( targetexpr != NULL )
11636 {
11637 /* release target expr */
11639 }
11640
11641 return SCIP_OKAY;
11642}
11643
11644
11645/** constraint parsing method of constraint handler */
11646static
11648{ /*lint --e{715}*/
11649 SCIP_Real lhs;
11650 SCIP_Real rhs;
11651 char* endptr;
11653
11654 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
11655
11656 assert(scip != NULL);
11657 assert(success != NULL);
11658 assert(str != NULL);
11659 assert(name != NULL);
11660 assert(cons != NULL);
11661
11662 *success = FALSE;
11663
11664 /* return if string empty */
11665 if( !*str )
11666 return SCIP_OKAY;
11667
11668 endptr = (char*)str;
11669
11670 /* set left and right hand side to their default values */
11671 lhs = -SCIPinfinity(scip);
11672 rhs = SCIPinfinity(scip);
11673
11674 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
11675
11676 /* check for left hand side */
11677 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11678 {
11679 /* there is a number coming, maybe it is a left-hand-side */
11680 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
11681 {
11682 SCIPerrorMessage("error parsing number from <%s>\n", str);
11683 return SCIP_READERROR;
11684 }
11685
11686 /* ignore whitespace */
11688
11689 if( endptr[0] != '<' || endptr[1] != '=' )
11690 {
11691 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
11692 lhs = -SCIPinfinity(scip);
11693 }
11694 else
11695 {
11696 /* it was indeed a left-hand-side, so continue parsing after it */
11697 str = endptr + 2;
11698
11699 /* ignore whitespace */
11700 SCIP_CALL( SCIPskipSpace((char**)&str) );
11701 }
11702 }
11703
11704 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
11705
11706 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
11707 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
11708
11709 /* check for left or right hand side */
11710 SCIP_CALL( SCIPskipSpace((char**)&str) );
11711
11712 /* check for free constraint */
11713 if( strncmp(str, "[free]", 6) == 0 )
11714 {
11715 if( !SCIPisInfinity(scip, -lhs) )
11716 {
11717 SCIPerrorMessage("cannot have left hand side and [free] status \n");
11719 return SCIP_OKAY;
11720 }
11721 *success = TRUE;
11722 }
11723 else
11724 {
11725 switch( *str )
11726 {
11727 case '<':
11728 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
11729 break;
11730 case '=':
11731 if( !SCIPisInfinity(scip, -lhs) )
11732 {
11733 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
11735 return SCIP_OKAY;
11736 }
11737 else
11738 {
11739 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
11740 lhs = rhs;
11741 }
11742 break;
11743 case '>':
11744 if( !SCIPisInfinity(scip, -lhs) )
11745 {
11746 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
11748 return SCIP_OKAY;
11749 }
11750 else
11751 {
11752 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
11753 break;
11754 }
11755 case '\0':
11756 *success = TRUE;
11757 break;
11758 default:
11759 SCIPerrorMessage("unexpected character %c\n", *str);
11761 return SCIP_OKAY;
11762 }
11763 }
11764
11765 /* create constraint */
11766 SCIP_CALL( createCons(scip, conshdlr, cons, name,
11767 consexprtree, lhs, rhs, FALSE,
11768 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11769 assert(*cons != NULL);
11770
11772
11773 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
11774
11775 return SCIP_OKAY;
11776}
11777
11778
11779/** constraint method of constraint handler which returns the variables (if possible) */
11780static
11782{ /*lint --e{715}*/
11783 SCIP_CONSDATA* consdata;
11784 int i;
11785
11786 consdata = SCIPconsGetData(cons);
11787 assert(consdata != NULL);
11788
11789 /* store variable expressions if not done so far */
11790 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11791
11792 /* check whether array is too small in order to store all variables */
11793 if( varssize < consdata->nvarexprs )
11794 {
11795 *success = FALSE;
11796 return SCIP_OKAY;
11797 }
11798
11799 for( i = 0; i < consdata->nvarexprs; ++i )
11800 {
11801 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
11802 assert(vars[i] != NULL);
11803 }
11804
11805 *success = TRUE;
11806
11807 return SCIP_OKAY;
11808}
11809
11810/** constraint method of constraint handler which returns the number of variables (if possible) */
11811static
11813{ /*lint --e{715}*/
11814 SCIP_CONSDATA* consdata;
11815
11816 consdata = SCIPconsGetData(cons);
11817 assert(consdata != NULL);
11818
11819 /* store variable expressions if not done so far */
11820 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11821
11822 *nvars = consdata->nvarexprs;
11823 *success = TRUE;
11824
11825 return SCIP_OKAY;
11826}
11827
11828/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
11829#ifdef SCIP_DISABLED_CODE
11830static
11832{ /*lint --e{715}*/
11833 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11834 SCIPABORT(); /*lint --e{527}*/
11835
11836 return SCIP_OKAY;
11837}
11838#else
11839#define consGetDiveBdChgsNonlinear NULL
11840#endif
11841
11842/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
11843static
11845{ /*lint --e{715}*/
11847
11848 return SCIP_OKAY;
11849}
11850
11851/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
11852static
11859
11860/** output method of statistics table to output file stream 'file' */
11861static
11863{ /*lint --e{715}*/
11864 SCIP_CONSHDLR* conshdlr;
11865 SCIP_CONSHDLRDATA* conshdlrdata;
11866
11867 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11868 assert(conshdlr != NULL);
11869
11870 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11871 assert(conshdlrdata != NULL);
11872
11873 /* print statistics for constraint handler */
11874 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
11875 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
11876 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
11877 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
11878 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
11879 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
11880 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
11881 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
11882 SCIPinfoMessage(scip, file, "\n");
11883 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
11884 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
11885 SCIPinfoMessage(scip, file, "\n");
11886
11887 return SCIP_OKAY;
11888}
11889
11890/** output method of statistics table to output file stream 'file' */
11891static
11893{ /*lint --e{715}*/
11894 SCIP_CONSHDLR* conshdlr;
11895 SCIP_CONSHDLRDATA* conshdlrdata;
11896
11897 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11898 assert(conshdlr != NULL);
11899
11900 /* skip nlhdlr table if there never were active nonlinear constraints */
11901 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
11902 return SCIP_OKAY;
11903
11904 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11905 assert(conshdlrdata != NULL);
11906
11907 /* print statistics for nonlinear handlers */
11908 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
11909
11910 return SCIP_OKAY;
11911}
11912
11913/** execution method of display nlhdlrs dialog */
11914static
11916{ /*lint --e{715}*/
11917 SCIP_CONSHDLR* conshdlr;
11918 SCIP_CONSHDLRDATA* conshdlrdata;
11919 int i;
11920
11921 /* add dialog to history of dialogs that have been executed */
11923
11924 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11925 assert(conshdlr != NULL);
11926
11927 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11928 assert(conshdlrdata != NULL);
11929
11930 /* display list of nonlinear handler */
11931 SCIPdialogMessage(scip, NULL, "\n");
11932 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
11933 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
11934 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11935 {
11936 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
11937 assert(nlhdlr != NULL);
11938
11939 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
11940 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
11943 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
11944 SCIPdialogMessage(scip, NULL, "\n");
11945 }
11946 SCIPdialogMessage(scip, NULL, "\n");
11947
11948 /* next dialog will be root dialog again */
11949 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
11950
11951 return SCIP_OKAY;
11952}
11953
11954/*
11955 * constraint handler specific interface methods
11956 */
11957
11958/** creates the handler for nonlinear constraints and includes it in SCIP */
11960 SCIP* scip /**< SCIP data structure */
11961 )
11962{
11963 SCIP_CONSHDLRDATA* conshdlrdata;
11965
11966 /* create nonlinear constraint handler data */
11967 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
11968 conshdlrdata->intevalvar = intEvalVarBoundTightening;
11969 conshdlrdata->curboundstag = 1;
11970 conshdlrdata->lastboundrelax = 1;
11971 conshdlrdata->curpropboundstag = 1;
11972 conshdlrdata->newsoleventfilterpos = -1;
11973 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
11974 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
11975 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
11976
11977 /* include constraint handler */
11993 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
11994
11995 /* add nonlinear constraint handler parameters */
11996 /* TODO organize into more subcategories */
11997 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
11998 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
11999 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12000
12001 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12002 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12003 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12004
12005 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12006 "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",
12007 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12008
12009 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12010 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12011 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12012
12013 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12014 "by how much to relax constraint sides during bound tightening",
12015 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12016
12017 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12018 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12019 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12020
12021 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12022 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12023 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12024
12025 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12026 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12027 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12028
12029 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12030 "maximal number of auxiliary expressions per bilinear term",
12031 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12032
12033 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12034 "whether to reformulate products of binary variables during presolving",
12035 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12036
12037 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12038 "whether to use the AND constraint handler for reformulating binary products",
12039 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12040
12041 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12042 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12043 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12044
12045 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12046 "whether to forbid multiaggregation of nonlinear variables",
12047 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12048
12049 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12050 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12051 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12052
12053 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12054 "whether to (re)run propagation in enforcement",
12055 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12056
12057 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12058 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12059 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12060
12061 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12062 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12063 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12064
12065 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12066 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12067 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12068
12069 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12070 "whether to force \"strong\" cuts in enforcement",
12071 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12072
12073 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12074 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12075 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12076
12077 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12078 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12079 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12080
12081 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12082 "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",
12083 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12084
12085 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12086 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12087 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12088
12089 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12090 "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)",
12091 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12092
12093 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12094 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12095 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12096
12097 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12098 "whether to use external branching candidates and branching rules for branching",
12099 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12100
12101 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12102 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12103 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12104
12105 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12106 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12107 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12108
12109 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12110 "weight by how much to consider the violation assigned to a variable for its branching score",
12111 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12112
12113 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12114 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12115 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12116
12117 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12118 "weight by how much to consider the pseudo cost of a variable for its branching score",
12119 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12120
12121 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12122 "weight by how much to consider the domain width in branching score",
12123 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12124
12125 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12126 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12127 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12128
12129 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12130 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12131 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12132
12133 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12134 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12135 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12136
12137 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12138 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12139 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12140
12141 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12142 "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)",
12143 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12144
12145 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12146 "whether to assume that any constraint is convex",
12147 &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
12148
12149 /* include handler for bound change events */
12150 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12151 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12152 assert(conshdlrdata->eventhdlr != NULL);
12153
12154 /* include tables for statistics */
12159
12164
12165 /* create, include, and release display nlhdlrs dialog */
12167 {
12169
12172
12178 }
12179
12180 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12182
12183 return SCIP_OKAY;
12184}
12185
12186/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12188 SCIP* scip, /**< SCIP data structure */
12189 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12190 int priority, /**< priority of upgrading method */
12191 SCIP_Bool active, /**< should the upgrading method by active by default? */
12192 const char* conshdlrname /**< name of the constraint handler */
12193 )
12194{
12195 SCIP_CONSHDLR* conshdlr;
12196 SCIP_CONSHDLRDATA* conshdlrdata;
12200 int i;
12201
12204
12205 /* find the nonlinear constraint handler */
12206 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12207 if( conshdlr == NULL )
12208 {
12209 SCIPerrorMessage("nonlinear constraint handler not found\n");
12210 return SCIP_PLUGINNOTFOUND;
12211 }
12212
12213 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12214 assert(conshdlrdata != NULL);
12215
12216 /* check whether upgrade method exists already */
12217 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12218 {
12219 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12220 {
12221#ifdef SCIP_DEBUG
12222 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12223#endif
12224 return SCIP_OKAY;
12225 }
12226 }
12227
12228 /* create a nonlinear constraint upgrade data object */
12230 consupgrade->consupgd = nlconsupgd;
12231 consupgrade->priority = priority;
12232 consupgrade->active = active;
12233
12234 /* insert nonlinear constraint upgrade method into constraint handler data */
12235 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12236 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12237
12238 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12239 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12240 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12241 conshdlrdata->consupgrades[i] = consupgrade;
12242 conshdlrdata->nconsupgrades++;
12243
12244 /* adds parameter to turn on and off the upgrading step */
12245 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12246 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12249 &consupgrade->active, FALSE, active, NULL, NULL) );
12250
12251 return SCIP_OKAY;
12252}
12253
12254/** creates and captures a nonlinear constraint
12255 *
12256 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12257 */
12259 SCIP* scip, /**< SCIP data structure */
12260 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12261 const char* name, /**< name of constraint */
12262 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12263 SCIP_Real lhs, /**< left hand side of constraint */
12264 SCIP_Real rhs, /**< right hand side of constraint */
12265 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12266 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12267 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12268 * Usually set to TRUE. */
12269 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12270 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12271 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12272 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12273 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12274 * Usually set to TRUE. */
12275 SCIP_Bool local, /**< is constraint only valid locally?
12276 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12277 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12278 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12279 * adds coefficients to this constraint. */
12280 SCIP_Bool dynamic, /**< is constraint subject to aging?
12281 * Usually set to FALSE. Set to TRUE for own cuts which
12282 * are separated as constraints. */
12283 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12284 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12285 )
12286{
12287 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12288 SCIP_CONSHDLR* conshdlr;
12289
12290 /* find the nonlinear constraint handler */
12291 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12292 if( conshdlr == NULL )
12293 {
12294 SCIPerrorMessage("nonlinear constraint handler not found\n");
12295 return SCIP_PLUGINNOTFOUND;
12296 }
12297
12298 /* create constraint */
12299 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12300 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12301
12302 return SCIP_OKAY;
12303}
12304
12305/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12306 *
12307 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12308 *
12309 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12310 *
12311 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12312 */
12314 SCIP* scip, /**< SCIP data structure */
12315 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12316 const char* name, /**< name of constraint */
12317 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12318 SCIP_Real lhs, /**< left hand side of constraint */
12319 SCIP_Real rhs /**< right hand side of constraint */
12320 )
12321{
12322 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12324
12325 return SCIP_OKAY;
12326}
12327
12328/** creates and captures a quadratic nonlinear constraint
12329 *
12330 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12331 */
12333 SCIP* scip, /**< SCIP data structure */
12334 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12335 const char* name, /**< name of constraint */
12336 int nlinvars, /**< number of linear terms */
12337 SCIP_VAR** linvars, /**< array with variables in linear part */
12338 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12339 int nquadterms, /**< number of quadratic terms */
12340 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12341 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12342 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12343 SCIP_Real lhs, /**< left hand side of quadratic equation */
12344 SCIP_Real rhs, /**< right hand side of quadratic equation */
12345 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12346 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12347 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12348 * Usually set to TRUE. */
12349 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12350 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12351 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12352 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12353 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12354 * Usually set to TRUE. */
12355 SCIP_Bool local, /**< is constraint only valid locally?
12356 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12357 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12358 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12359 * adds coefficients to this constraint. */
12360 SCIP_Bool dynamic, /**< is constraint subject to aging?
12361 * Usually set to FALSE. Set to TRUE for own cuts which
12362 * are separated as constraints. */
12363 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12364 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12365 )
12366{
12367 SCIP_CONSHDLR* conshdlr;
12368 SCIP_EXPR* expr;
12369
12370 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12371 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12372
12373 /* get nonlinear constraint handler */
12374 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12375 if( conshdlr == NULL )
12376 {
12377 SCIPerrorMessage("nonlinear constraint handler not found\n");
12378 return SCIP_PLUGINNOTFOUND;
12379 }
12380
12381 /* create quadratic expression */
12382 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12383 assert(expr != NULL);
12384
12385 /* create nonlinear constraint */
12386 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12387 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12388
12389 /* release quadratic expression (captured by constraint now) */
12390 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12391
12392 return SCIP_OKAY;
12393}
12394
12395/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12396 *
12397 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12398 *
12399 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12400 *
12401 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12402 */
12404 SCIP* scip, /**< SCIP data structure */
12405 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12406 const char* name, /**< name of constraint */
12407 int nlinvars, /**< number of linear terms */
12408 SCIP_VAR** linvars, /**< array with variables in linear part */
12409 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12410 int nquadterms, /**< number of quadratic terms */
12411 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12412 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12413 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12414 SCIP_Real lhs, /**< left hand side of quadratic equation */
12415 SCIP_Real rhs /**< right hand side of quadratic equation */
12416 )
12417{
12418 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12420
12421 return SCIP_OKAY;
12422}
12423
12424/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12425 *
12426 * \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$
12427 *
12428 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12429 */
12431 SCIP* scip, /**< SCIP data structure */
12432 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12433 const char* name, /**< name of constraint */
12434 int nvars, /**< number of variables on left hand side of constraint (n) */
12435 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12436 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12437 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12438 SCIP_Real constant, /**< constant on left hand side (gamma) */
12439 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12440 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12441 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12442 )
12443{
12444 SCIP_EXPR* expr;
12446 SCIP_EXPR* terms[2];
12447 SCIP_Real termcoefs[2];
12448 int i;
12449
12450 assert(vars != NULL || nvars == 0);
12451
12452 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
12453 for( i = 0; i < nvars; ++i )
12454 {
12457
12458 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
12459 if( offsets != NULL && offsets[i] != 0.0 )
12460 {
12461 SCIP_EXPR* sum;
12462 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
12463 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
12464 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12465 }
12466 else
12467 {
12468 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
12469 }
12470
12471 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
12474 }
12475
12476 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
12478 termcoefs[0] = 1.0;
12479
12480 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
12481 termcoefs[1] = -rhscoeff;
12482
12483 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
12484
12487
12489
12490 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12491
12492 return SCIP_OKAY;
12493}
12494
12495/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12496 *
12497 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12498 *
12499 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12500 */
12502 SCIP* scip, /**< SCIP data structure */
12503 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12504 const char* name, /**< name of constraint */
12505 SCIP_VAR* x, /**< nonlinear variable x in constraint */
12506 SCIP_VAR* z, /**< linear variable z in constraint */
12507 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
12508 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
12509 SCIP_Real zcoef, /**< coefficient of z in constraint */
12510 SCIP_Real lhs, /**< left hand side of constraint */
12511 SCIP_Real rhs /**< right hand side of constraint */
12512 )
12513{
12515 SCIP_EXPR* terms[2];
12516 SCIP_Real coefs[2];
12518
12519 assert(x != NULL);
12520 assert(z != NULL);
12521
12523 if( xoffset != 0.0 )
12524 {
12525 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12526 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12527
12529 }
12530 else
12531 {
12532 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
12533 }
12534 coefs[0] = 1.0;
12535
12537 coefs[1] = zcoef;
12538
12539 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
12540
12541 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12542
12547
12548 return SCIP_OKAY;
12549}
12550
12551/** gets tag indicating current local variable bounds */
12553 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12554 )
12555{
12556 SCIP_CONSHDLRDATA* conshdlrdata;
12557
12558 assert(conshdlr != NULL);
12559 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12560
12561 return conshdlrdata->curboundstag;
12562}
12563
12564/** gets the `curboundstag` from the last time where variable bounds were relaxed */
12566 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12567 )
12568{
12569 SCIP_CONSHDLRDATA* conshdlrdata;
12570
12571 assert(conshdlr != NULL);
12572 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12573
12574 return conshdlrdata->lastboundrelax;
12575}
12576
12577/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12578 *
12579 * @attention This method is not intended for normal use.
12580 * These tags are maintained by the event handler for variable bound change events.
12581 * This method is used by some unittests.
12582 */
12584 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12585 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12586 )
12587{
12588 SCIP_CONSHDLRDATA* conshdlrdata;
12589
12590 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12591 assert(conshdlrdata != NULL);
12592
12593 ++conshdlrdata->curboundstag;
12594 assert(conshdlrdata->curboundstag > 0);
12595
12596 if( boundrelax )
12597 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
12598}
12599
12600/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
12602 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12603 )
12604{
12605 assert(conshdlr != NULL);
12606
12607 return SCIPconshdlrGetData(conshdlr)->var2expr;
12608}
12609
12610/** processes a rowprep for cut addition and maybe report branchscores */
12612 SCIP* scip, /**< SCIP data structure */
12613 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
12614 SCIP_CONS* cons, /**< nonlinear constraint */
12615 SCIP_EXPR* expr, /**< expression */
12616 SCIP_ROWPREP* rowprep, /**< cut to be added */
12617 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
12618 SCIP_VAR* auxvar, /**< auxiliary variable */
12619 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
12620 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
12621 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
12622 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
12623 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
12624 SCIP_RESULT* result /**< pointer to store the result */
12625 )
12626{
12627 SCIP_Real cutviol;
12628 SCIP_CONSHDLRDATA* conshdlrdata;
12629 SCIP_Real auxvarvalue = SCIP_INVALID;
12630 SCIP_Bool sepasuccess;
12631 SCIP_Real estimateval = SCIP_INVALID;
12632 SCIP_Real mincutviolation;
12633
12634 assert(nlhdlr != NULL);
12635 assert(cons != NULL);
12636 assert(expr != NULL);
12637 assert(rowprep != NULL);
12638 assert(auxvar != NULL);
12639 assert(result != NULL);
12640
12641 /* decide on minimal violation of cut */
12642 if( sol == NULL )
12643 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
12644 else
12645 mincutviolation = SCIPfeastol(scip);
12646
12647 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
12648 assert(conshdlrdata != NULL);
12649
12650 sepasuccess = TRUE;
12651
12653 if( cutviol > 0.0 )
12654 {
12655 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
12656
12657 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
12658 if( !allowweakcuts && auxvalue != SCIP_INVALID )
12659 {
12660 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
12661 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
12662 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
12663 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
12664 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
12665 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
12666 *
12667 * if we are overestimating, we have z >= c'x-b >= f(x)
12668 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
12669 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
12670 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
12671 *
12672 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
12673 */
12674 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
12675 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
12676 {
12677 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
12678 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
12680 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
12682 }
12683 }
12684
12685 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
12686 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
12687 }
12688 else
12689 {
12691 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
12692 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
12693 }
12694
12695 /* clean up estimator */
12696 if( sepasuccess )
12697 {
12698 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
12699 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
12700 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
12702
12703 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
12704 * instead, may even scale them down, that is, scale so that max coef is close to 1
12705 */
12706 if( !allowweakcuts )
12707 {
12708 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
12709
12710 if( !sepasuccess )
12711 {
12712 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
12713 }
12714 else
12715 {
12717 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
12718 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
12719 if( sepasuccess )
12720 sepasuccess = cutviol > mincutviolation;
12721 }
12722
12723 if( sepasuccess && auxvalue != SCIP_INVALID )
12724 {
12725 /* check whether cut is weak now
12726 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
12727 * reconstructing estimateval from cutviol (TODO improve or remove?)
12728 */
12729 SCIP_Real auxvarcoef = 0.0;
12730 int i;
12731
12732 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
12733 * it should be...
12734 */
12735 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
12736 {
12737 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
12738 {
12740 break;
12741 }
12742 }
12743
12744 if( auxvarcoef == 0.0 ||
12745 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
12746 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
12747 {
12748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
12749 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
12751 }
12752 }
12753 }
12754 else
12755 {
12756 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
12757
12758 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
12759 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
12760 */
12761 if( !branchscoresuccess )
12763
12764 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
12765
12766 if( !sepasuccess )
12767 {
12768 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
12770 }
12771
12772 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
12773 * changed
12774 */
12776 {
12777 SCIP_Real violscore;
12778
12779#ifdef BRSCORE_ABSVIOL
12780 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
12781#else
12783#endif
12785
12786 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
12787 * - were fixed,
12788 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
12789 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
12790 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
12791 * so I'm disabling the assert for now
12792 */
12793 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
12794 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
12795 }
12796 }
12797 }
12798
12799 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
12800 if( sepasuccess )
12801 {
12802 SCIP_ROW* row;
12803
12804 if( conshdlrdata->branchdualweight > 0.0 )
12805 {
12806 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
12807 * skip if gap is zero
12808 */
12809 if( auxvalue == SCIP_INVALID )
12810 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
12811 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
12812 {
12813 char gap[40];
12814 /* coverity[secure_coding] */
12815 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
12817 }
12818 }
12819
12821
12822 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
12823 {
12824 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
12826 }
12827 else if( !SCIPisCutApplicable(scip, row) )
12828 {
12829 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
12830 }
12831 else
12832 {
12833 SCIP_Bool infeasible;
12834
12835 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
12837
12838 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
12839 * if we haven't found strong cuts before)
12840 */
12841 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
12842
12843 /* mark row as not removable from LP for current node (this can prevent some cycling) */
12844 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
12846
12847 if( infeasible )
12848 {
12851 }
12852 else
12853 {
12856 }
12857 }
12858
12859 SCIP_CALL( SCIPreleaseRow(scip, &row) );
12860 }
12861 else if( branchscoresuccess )
12862 {
12863 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
12864 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
12865
12866 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
12867 * expressions eligible for branching candidate, see enforceConstraints() and branching()
12868 */
12870 }
12871 else
12872 {
12873 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
12874 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
12875 " (!)" : ""); )
12876 }
12877
12878 return SCIP_OKAY;
12879}
12880
12881/** returns whether all nonlinear constraints are assumed to be convex */
12883 SCIP_CONSHDLR* conshdlr
12884 )
12885{
12886 SCIP_CONSHDLRDATA* conshdlrdata;
12887
12888 assert(conshdlr != NULL);
12889
12890 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12891 assert(conshdlrdata != NULL);
12892
12893 return conshdlrdata->assumeconvex;
12894}
12895
12896/** collects all bilinear terms for a given set of constraints
12897 *
12898 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
12899 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
12900 */
12902 SCIP* scip, /**< SCIP data structure */
12903 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12904 SCIP_CONS** conss, /**< nonlinear constraints */
12905 int nconss /**< total number of nonlinear constraints */
12906 )
12907{
12908 assert(conshdlr != NULL);
12909 assert(conss != NULL || nconss == 0);
12910
12911 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
12912
12913 return SCIP_OKAY;
12914}
12915
12916/** returns the total number of bilinear terms that are contained in all nonlinear constraints
12917 *
12918 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12919 */
12921 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12922 )
12923{
12924 SCIP_CONSHDLRDATA* conshdlrdata;
12925
12926 assert(conshdlr != NULL);
12927
12928 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12929 assert(conshdlrdata != NULL);
12930
12931 return conshdlrdata->nbilinterms;
12932}
12933
12934/** returns all bilinear terms that are contained in all nonlinear constraints
12935 *
12936 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12937 * @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.
12938 */
12940 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12941 )
12942{
12943 SCIP_CONSHDLRDATA* conshdlrdata;
12944
12945 assert(conshdlr != NULL);
12946
12947 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12948 assert(conshdlrdata != NULL);
12949
12950 return conshdlrdata->bilinterms;
12951}
12952
12953/** returns the index of the bilinear term representing the product of the two given variables
12954 *
12955 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12956 * @return The method returns -1 if the variables do not appear bilinearly.
12957 */
12959 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12960 SCIP_VAR* x, /**< first variable */
12961 SCIP_VAR* y /**< second variable */
12962 )
12963{
12964 SCIP_CONSHDLRDATA* conshdlrdata;
12966 int idx;
12967
12968 assert(conshdlr != NULL);
12969 assert(x != NULL);
12970 assert(y != NULL);
12971
12972 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12973 assert(conshdlrdata != NULL);
12974
12975 if( conshdlrdata->bilinhashtable == NULL )
12976 {
12977 return -1;
12978 }
12979
12980 /* ensure that x.index <= y.index */
12981 if( SCIPvarCompare(x, y) == 1 )
12982 {
12983 SCIPswapPointers((void**)&x, (void**)&y);
12984 }
12985 assert(SCIPvarCompare(x, y) < 1);
12986
12987 /* use a new entry to find the image in the bilinear hash table */
12988 entry.x = x;
12989 entry.y = y;
12990 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
12991 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
12992 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
12993 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
12994
12995 return idx;
12996}
12997
12998/** returns the bilinear term that represents the product of two given variables
12999 *
13000 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13001 * @return The method returns NULL if the variables do not appear bilinearly.
13002 */
13004 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13005 SCIP_VAR* x, /**< first variable */
13006 SCIP_VAR* y /**< second variable */
13007 )
13008{
13009 SCIP_CONSHDLRDATA* conshdlrdata;
13010 int idx;
13011
13012 assert(conshdlr != NULL);
13013 assert(x != NULL);
13014 assert(y != NULL);
13015
13016 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13017 assert(conshdlrdata != NULL);
13018
13019 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13020 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13021
13022 if( idx >= 0 )
13023 {
13024 return &conshdlrdata->bilinterms[idx];
13025 }
13026
13027 return NULL;
13028}
13029
13030/** evaluates an auxiliary expression for a bilinear term */
13032 SCIP* scip, /**< SCIP data structure */
13033 SCIP_VAR* x, /**< first variable of the bilinear term */
13034 SCIP_VAR* y, /**< second variable of the bilinear term */
13035 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13036 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13037 )
13038{
13039 assert(scip != NULL);
13040 assert(x != NULL);
13041 assert(y != NULL);
13042 assert(auxexpr != NULL);
13043 assert(auxexpr->auxvar != NULL);
13044
13045 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13046 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13047}
13048
13049/** stores the variables of a bilinear term in the data of the constraint handler */
13051 SCIP* scip, /**< SCIP data structure */
13052 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13053 SCIP_VAR* x, /**< first variable */
13054 SCIP_VAR* y, /**< second variable */
13055 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13056 int nlockspos, /**< number of positive expression locks */
13057 int nlocksneg /**< number of negative expression locks */
13058 )
13059{
13060 SCIP_CONSHDLRDATA* conshdlrdata;
13062 int idx;
13063
13064 assert(conshdlr != NULL);
13065
13066 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13067 assert(conshdlrdata != NULL);
13068
13069 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13070
13071 term = &conshdlrdata->bilinterms[idx];
13072 assert(term != NULL);
13073 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13074 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) */
13075
13076 /* store and capture auxiliary variable */
13077 if( auxvar != NULL )
13078 {
13079 term->aux.var = auxvar;
13080 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13081 }
13082
13083 return SCIP_OKAY;
13084}
13085
13086/** stores the variables of a bilinear term in the data of the constraint handler */
13088 SCIP* scip, /**< SCIP data structure */
13089 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13090 SCIP_VAR* x, /**< first variable */
13091 SCIP_VAR* y, /**< second variable */
13092 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13093 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13094 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13095 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13096 SCIP_Real cst, /**< constant of the auxiliary expression */
13097 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13098 )
13099{
13100 SCIP_CONSHDLRDATA* conshdlrdata;
13103 int idx;
13104 int nlockspos;
13105 int nlocksneg;
13106 SCIP_Bool added;
13107
13108 assert(conshdlr != NULL);
13109
13110 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13111 assert(conshdlrdata != NULL);
13112
13113 nlockspos = overestimate ? 1 : 0;
13114 nlocksneg = overestimate ? 0 : 1;
13115
13116 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13117
13118 term = &conshdlrdata->bilinterms[idx];
13119 assert(term != NULL);
13120 assert(SCIPvarCompare(term->x, term->y) < 1);
13121
13122 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13123 {
13125 /* this is the case where we are adding an implicitly defined relation for a product that has already
13126 * been explicitly defined; convert auxvar into an auxexpr */
13127
13128 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13129 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13130 return SCIP_OKAY;
13131
13133 auxvarexpr->cst = 0.0;
13134 auxvarexpr->coefs[0] = 1.0;
13135 auxvarexpr->coefs[1] = 0.0;
13136 auxvarexpr->coefs[2] = 0.0;
13137 auxvarexpr->auxvar = term->aux.var;
13138 auxvarexpr->underestimate = term->nlocksneg > 0;
13139 auxvarexpr->overestimate = term->nlockspos > 0;
13140
13141 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13142 term->aux.exprs = NULL;
13143
13144 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13145
13146 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13147 assert(added);
13148 }
13149
13150 /* create and add auxexpr */
13152 auxexpr->underestimate = !overestimate;
13153 auxexpr->overestimate = overestimate;
13154 auxexpr->auxvar = auxvar;
13155 auxexpr->coefs[0] = coefaux;
13156 if( term->x == x )
13157 {
13158 assert(term->y == y);
13159 auxexpr->coefs[1] = coefx;
13160 auxexpr->coefs[2] = coefy;
13161 }
13162 else
13163 {
13164 assert(term->x == y);
13165 assert(term->y == x);
13166 auxexpr->coefs[1] = coefy;
13167 auxexpr->coefs[2] = coefx;
13168 }
13169 auxexpr->cst = cst;
13170 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13171
13172 if( !added )
13173 {
13175 }
13176 else if( auxvar != NULL )
13177 { /* capture auxiliary variable */
13178 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13179 }
13180
13181 return SCIP_OKAY;
13182}
13183
13184/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13186 SCIP* scip, /**< SCIP data structure */
13187 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13188 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13189 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13190 void* fundata, /**< data for function evaluation (can be NULL) */
13191 SCIP_Real* xstar, /**< point to be separated */
13192 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13193 int nallvars, /**< half of the length of box */
13194 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13195 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13196 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13197 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13198 )
13199{
13200 SCIP_Real* corner;
13201 SCIP_Real* funvals;
13202 int* nonfixedpos;
13203 SCIP_Real maxfaceterror;
13204 int nvars; /* number of nonfixed variables */
13205 unsigned int ncorners;
13206 unsigned int i;
13207 int j;
13208
13209 assert(scip != NULL);
13210 assert(conshdlr != NULL);
13211 assert(function != NULL);
13212 assert(xstar != NULL);
13213 assert(box != NULL);
13214 assert(success != NULL);
13217
13218 *success = FALSE;
13219
13220 /* identify fixed variables */
13222 nvars = 0;
13223 for( j = 0; j < nallvars; ++j )
13224 {
13225 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13226 continue;
13227 nonfixedpos[nvars] = j;
13228 nvars++;
13229 }
13230
13231 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13232 * if too many variables are not fixed, then we do nothing currently
13233 */
13234 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13235 {
13236 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13238 return SCIP_OKAY;
13239 }
13240
13241 /* compute f(v^i) for each corner v^i of [l,u] */
13244 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13245 for( j = 0; j < nallvars; ++j )
13246 {
13247 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13248 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13249 }
13250 for( i = 0; i < ncorners; ++i )
13251 {
13252 SCIPdebugMsg(scip, "corner %u: ", i);
13253 for( j = 0; j < nvars; ++j )
13254 {
13255 int varpos = nonfixedpos[j];
13256 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13257 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13258 */
13259 if( (i >> j) & 0x1 )
13260 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13261 else
13262 corner[varpos] = box[2 * varpos ]; /* lb of var */
13263 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13265 }
13266
13267 funvals[i] = function(corner, nallvars, fundata);
13268
13269 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13270
13272 {
13273 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13274 goto CLEANUP;
13275 }
13276 }
13277
13278 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13280
13281 if( nvars == 1 )
13282 {
13284
13285 /* check whether target has been missed */
13286 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13287 {
13288 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13289 *success = FALSE;
13290 }
13291 }
13292 else if( nvars == 2 && SCIPlapackIsAvailable() )
13293 {
13294 int idx1 = nonfixedpos[0];
13295 int idx2 = nonfixedpos[1];
13296 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13297 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13298 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13299 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13300 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13301 SCIP_Real coefs[2] = { 0.0, 0.0 };
13302
13303 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13304
13305 facetcoefs[idx1] = coefs[0];
13306 facetcoefs[idx2] = coefs[1];
13307 }
13308 else
13309 {
13310 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13311 }
13312 if( !*success )
13313 {
13314 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13315 goto CLEANUP;
13316 }
13317
13318 /*
13319 * check and adjust facet with the algorithm of Rikun et al.
13320 */
13321
13323
13324 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13325 if( maxfaceterror > 0.0 )
13326 {
13327 SCIP_CONSHDLRDATA* conshdlrdata;
13328 SCIP_Real midval;
13329 SCIP_Real feastol;
13330
13332
13333 /* evaluate function in middle point to get some idea for a scaling */
13334 for( j = 0; j < nvars; ++j )
13335 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13336 midval = function(corner, nallvars, fundata);
13337 if( midval == SCIP_INVALID )
13338 midval = 1.0;
13339
13340 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13341 assert(conshdlrdata != NULL);
13342
13343 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13344 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13345 {
13346 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13347 *success = FALSE;
13348 goto CLEANUP;
13349 }
13350
13351 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13352
13353 if( overestimate )
13355 else
13357 }
13358
13359 /* if we made it until here, then we have a nice facet */
13360 assert(*success);
13361
13362CLEANUP:
13363 /* free allocated memory */
13367
13368 return SCIP_OKAY;
13369}
13370
13371/*
13372 * constraint specific interface methods
13373 */
13374
13375/** returns the expression of the given nonlinear constraint */
13377 SCIP_CONS* cons /**< constraint data */
13378 )
13379{
13380 SCIP_CONSDATA* consdata;
13381
13382 assert(cons != NULL);
13384
13385 consdata = SCIPconsGetData(cons);
13386 assert(consdata != NULL);
13387
13388 return consdata->expr;
13389}
13390
13391/** gets the left hand side of a nonlinear constraint */
13393 SCIP_CONS* cons /**< constraint data */
13394 )
13395{
13396 SCIP_CONSDATA* consdata;
13397
13398 assert(cons != NULL);
13400
13401 consdata = SCIPconsGetData(cons);
13402 assert(consdata != NULL);
13403
13404 return consdata->lhs;
13405}
13406
13407/** gets the right hand side of a nonlinear constraint */
13409 SCIP_CONS* cons /**< constraint data */
13410 )
13411{
13412 SCIP_CONSDATA* consdata;
13413
13414 assert(cons != NULL);
13416
13417 consdata = SCIPconsGetData(cons);
13418 assert(consdata != NULL);
13419
13420 return consdata->rhs;
13421}
13422
13423/** gets the nonlinear constraint as a nonlinear row representation. */
13425 SCIP* scip, /**< SCIP data structure */
13426 SCIP_CONS* cons, /**< constraint */
13427 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13428 )
13429{
13430 SCIP_CONSDATA* consdata;
13431
13432 assert(cons != NULL);
13433 assert(nlrow != NULL);
13435
13436 consdata = SCIPconsGetData(cons);
13437 assert(consdata != NULL);
13438
13439 if( consdata->nlrow == NULL )
13440 {
13441 SCIP_CALL( createNlRow(scip, cons) );
13442 }
13443 assert(consdata->nlrow != NULL);
13444 *nlrow = consdata->nlrow;
13445
13446 return SCIP_OKAY;
13447}
13448
13449/** returns the curvature of the expression of a given nonlinear constraint
13450 *
13451 * @note The curvature information is computed during CONSINITSOL.
13452 */
13454 SCIP_CONS* cons /**< constraint data */
13455 )
13456{
13457 SCIP_CONSDATA* consdata;
13458
13459 assert(cons != NULL);
13461
13462 consdata = SCIPconsGetData(cons);
13463 assert(consdata != NULL);
13464
13465 return consdata->curv;
13466}
13467
13468/** checks whether expression of constraint can be represented as quadratic form
13469 *
13470 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13471 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13472 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13473 */
13475 SCIP* scip, /**< SCIP data structure */
13476 SCIP_CONS* cons, /**< constraint data */
13477 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
13478 )
13479{
13480 SCIP_CONSDATA* consdata;
13481
13482 assert(scip != NULL);
13483 assert(cons != NULL);
13486
13487 consdata = SCIPconsGetData(cons);
13488 assert(consdata != NULL);
13489 assert(consdata->expr != NULL);
13490
13491 /* check whether constraint expression is quadratic in extended formulation */
13492 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13493
13494 /* if not quadratic in non-extended formulation, then do indicate quadratic */
13495 if( *isquadratic )
13497
13498 return SCIP_OKAY;
13499}
13500
13501/** changes left-hand-side of a nonlinear constraint
13502 *
13503 * @attention This method can only be called in the problem stage.
13504 */
13506 SCIP* scip, /**< SCIP data structure */
13507 SCIP_CONS* cons, /**< constraint data */
13508 SCIP_Real lhs /**< new left-hand-side */
13509 )
13510{
13511 SCIP_CONSDATA* consdata;
13512
13513 assert(scip != NULL);
13514 assert(cons != NULL);
13516
13518 {
13519 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13520 return SCIP_INVALIDCALL;
13521 }
13522
13523 /* we should have an original constraint */
13525
13526 consdata = SCIPconsGetData(cons);
13527 assert(consdata != NULL);
13528
13529 if( consdata->lhs == lhs )
13530 return SCIP_OKAY;
13531
13532 consdata->lhs = lhs;
13533
13534 /* not sure we care about any of these flags for original constraints */
13535 consdata->ispropagated = FALSE;
13536
13537 return SCIP_OKAY;
13538}
13539
13540/** changes right-hand-side of a nonlinear constraint
13541 *
13542 * @attention This method can only be called in the problem stage.
13543 */
13545 SCIP* scip, /**< SCIP data structure */
13546 SCIP_CONS* cons, /**< constraint data */
13547 SCIP_Real rhs /**< new right-hand-side */
13548 )
13549{
13550 SCIP_CONSDATA* consdata;
13551
13552 assert(scip != NULL);
13553 assert(cons != NULL);
13555
13557 {
13558 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13559 return SCIP_INVALIDCALL;
13560 }
13561
13562 /* we should have an original constraint */
13564
13565 consdata = SCIPconsGetData(cons);
13566 assert(consdata != NULL);
13567
13568 if( consdata->rhs == rhs )
13569 return SCIP_OKAY;
13570
13571 consdata->rhs = rhs;
13572
13573 /* not sure we care about any of these flags for original constraints */
13574 consdata->ispropagated = FALSE;
13575
13576 return SCIP_OKAY;
13577}
13578
13579/** changes expression of a nonlinear constraint
13580 *
13581 * @attention This method can only be called in the problem stage.
13582 */
13584 SCIP* scip, /**< SCIP data structure */
13585 SCIP_CONS* cons, /**< constraint data */
13586 SCIP_EXPR* expr /**< new expression */
13587 )
13588{
13589 SCIP_CONSHDLR* conshdlr;
13590 SCIP_CONSDATA* consdata;
13591
13592 assert(scip != NULL);
13593 assert(cons != NULL);
13594 assert(expr != NULL);
13595
13597 {
13598 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
13599 return SCIP_INVALIDCALL;
13600 }
13601
13602 /* we should have an original constraint */
13604
13605 conshdlr = SCIPconsGetHdlr(cons);
13606 assert(conshdlr != NULL);
13608
13609 consdata = SCIPconsGetData(cons);
13610 assert(consdata != NULL);
13611 assert(consdata->expr != NULL);
13612
13613 /* we should not have collected additional data for the expr
13614 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13615 */
13616 assert(consdata->nvarexprs == 0);
13617 assert(consdata->varexprs == NULL);
13618 assert(!consdata->catchedevents);
13619
13620 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
13621
13622 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13623 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13624
13625 /* not sure we care about any of these flags for original constraints */
13626 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
13627 consdata->issimplified = FALSE;
13628 consdata->ispropagated = FALSE;
13629
13630 return SCIP_OKAY;
13631}
13632
13633/** adds coef * var to nonlinear constraint
13634 *
13635 * @attention This method can only be called in the problem stage.
13636 */
13638 SCIP* scip, /**< SCIP data structure */
13639 SCIP_CONS* cons, /**< constraint data */
13640 SCIP_VAR* var, /**< variable */
13641 SCIP_Real coef /**< coefficient */
13642 )
13643{
13644 SCIP_CONSHDLR* conshdlr;
13645 SCIP_CONSDATA* consdata;
13647
13648 assert(scip != NULL);
13649 assert(cons != NULL);
13650
13652 {
13653 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13654 return SCIP_INVALIDCALL;
13655 }
13656
13657 /* we should have an original constraint */
13659
13660 if( coef == 0.0 )
13661 return SCIP_OKAY;
13662
13663 conshdlr = SCIPconsGetHdlr(cons);
13664 assert(conshdlr != NULL);
13666
13667 consdata = SCIPconsGetData(cons);
13668 assert(consdata != NULL);
13669 assert(consdata->expr != NULL);
13670
13671 /* we should not have collected additional data for it
13672 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13673 */
13674 assert(consdata->nvarexprs == 0);
13675 assert(consdata->varexprs == NULL);
13676 assert(!consdata->catchedevents);
13677
13678 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
13679
13680 /* append to sum, if consdata->expr is sum and not used anywhere else */
13681 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
13682 {
13683 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
13684 }
13685 else
13686 {
13687 /* create new expression = 1 * consdata->expr + coef * var */
13688 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
13689 SCIP_Real coefs[2] = { 1.0, coef };
13690
13691 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
13692
13693 /* release old root expr */
13694 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
13695 }
13696
13698
13699 /* not sure we care about any of these flags for original constraints */
13700 consdata->issimplified = FALSE;
13701 consdata->ispropagated = FALSE;
13702
13703 return SCIP_OKAY;
13704}
13705
13706/** adds coef * expr to nonlinear constraint
13707 *
13708 * @attention This method can only be called in the problem stage.
13709 */
13711 SCIP* scip, /**< SCIP data structure */
13712 SCIP_CONS* cons, /**< nonlinear constraint */
13713 SCIP_EXPR* expr, /**< expression */
13714 SCIP_Real coef /**< coefficient */
13715 )
13716{
13717 SCIP_CONSHDLR* conshdlr;
13718 SCIP_CONSDATA* consdata;
13720
13721 assert(scip != NULL);
13722 assert(cons != NULL);
13723
13725 {
13726 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13727 return SCIP_INVALIDCALL;
13728 }
13729
13730 /* we should have an original constraint */
13732
13733 if( coef == 0.0 )
13734 return SCIP_OKAY;
13735
13736 conshdlr = SCIPconsGetHdlr(cons);
13737 assert(conshdlr != NULL);
13739
13740 consdata = SCIPconsGetData(cons);
13741 assert(consdata != NULL);
13742 assert(consdata->expr != NULL);
13743
13744 /* we should not have collected additional data for it
13745 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13746 */
13747 assert(consdata->nvarexprs == 0);
13748 assert(consdata->varexprs == NULL);
13749 assert(!consdata->catchedevents);
13750
13751 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13752 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13753
13754 /* append to sum, if consdata->expr is sum and not used anywhere else */
13755 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
13756 {
13757 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
13758 }
13759 else
13760 {
13761 /* create new expression = 1 * consdata->expr + coef * var */
13762 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
13763 SCIP_Real coefs[2] = { 1.0, coef };
13764
13765 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
13766
13767 /* release old root expr */
13768 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
13769 }
13770
13772
13773 /* not sure we care about any of these flags for original constraints */
13774 consdata->issimplified = FALSE;
13775 consdata->ispropagated = FALSE;
13776
13777 return SCIP_OKAY;
13778}
13779
13780/** gets absolute violation of nonlinear constraint
13781 *
13782 * This function evaluates the constraints in the given solution.
13783 *
13784 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
13785 */
13787 SCIP* scip, /**< SCIP data structure */
13788 SCIP_CONS* cons, /**< constraint */
13789 SCIP_SOL* sol, /**< solution to check */
13790 SCIP_Real* viol /**< buffer to store computed violation */
13791 )
13792{
13793 assert(cons != NULL);
13794 assert(viol != NULL);
13795
13796 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
13797 *viol = getConsAbsViolation(cons);
13798
13799 return SCIP_OKAY;
13800}
13801
13802/** gets scaled violation of nonlinear constraint
13803 *
13804 * This function evaluates the constraints in the given solution.
13805 *
13806 * The scaling that is applied to the absolute violation of the constraint
13807 * depends on the setting of parameter constraints/nonlinear/violscale.
13808 */
13810 SCIP* scip, /**< SCIP data structure */
13811 SCIP_CONS* cons, /**< constraint */
13812 SCIP_SOL* sol, /**< solution to check */
13813 SCIP_Real* viol /**< buffer to store computed violation */
13814 )
13815{
13816 assert(cons != NULL);
13817 assert(viol != NULL);
13818
13819 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
13820 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
13821
13822 return SCIP_OKAY;
13823}
13824
13825/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
13827 SCIP* scip, /**< SCIP data structure */
13828 SCIP_CONS* cons, /**< nonlinear constraint */
13829 SCIP_VAR** var, /**< pointer to store the variable */
13830 SCIP_Real* coef /**< pointer to store the coefficient */
13831 )
13832{
13833 SCIP_CONSDATA* consdata;
13834
13835 assert(cons != NULL);
13836 assert(var != NULL);
13837 assert(coef != NULL);
13838
13839 /* check for a linear variable that can be increased or decreased without harming feasibility */
13841
13842 consdata = SCIPconsGetData(cons);
13843 assert(consdata != NULL);
13844
13845 *var = consdata->linvardecr;
13846 *coef = consdata->linvardecrcoef;
13847}
13848
13849/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
13851 SCIP* scip, /**< SCIP data structure */
13852 SCIP_CONS* cons, /**< nonlinear constraint */
13853 SCIP_VAR** var, /**< pointer to store the variable */
13854 SCIP_Real* coef /**< pointer to store the coefficient */
13855 )
13856{
13857 SCIP_CONSDATA* consdata;
13858
13859 assert(cons != NULL);
13860 assert(var != NULL);
13861 assert(coef != NULL);
13862
13863 /* check for a linear variable that can be increased or decreased without harming feasibility */
13865
13866 consdata = SCIPconsGetData(cons);
13867 assert(consdata != NULL);
13868
13869 *var = consdata->linvarincr;
13870 *coef = consdata->linvarincrcoef;
13871}
13872
13873
13874/*
13875 * Methods for Expressions in Nonlinear Constraints
13876 */
13877
13878/** returns the number of positive rounding locks of an expression */
13880 SCIP_EXPR* expr /**< expression */
13881 )
13882{
13883 assert(expr != NULL);
13885
13886 return SCIPexprGetOwnerData(expr)->nlockspos;
13887}
13888
13889/** returns the number of negative rounding locks of an expression */
13891 SCIP_EXPR* expr /**< expression */
13892 )
13893{
13894 assert(expr != NULL);
13896
13897 return SCIPexprGetOwnerData(expr)->nlocksneg;
13898}
13899
13900/** returns the variable used for linearizing a given expression (return value might be NULL)
13901 *
13902 * @note for variable expression it returns the corresponding variable
13903 */
13905 SCIP_EXPR* expr /**< expression */
13906 )
13907{
13908 SCIP_EXPR_OWNERDATA* ownerdata;
13909
13910 assert(expr != NULL);
13911
13912 ownerdata = SCIPexprGetOwnerData(expr);
13913 assert(ownerdata != NULL);
13914
13915 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
13916}
13917
13918/** returns the number of enforcements for an expression */
13920 SCIP_EXPR* expr /**< expression */
13921 )
13922{
13923 assert(expr != NULL);
13925
13926 return SCIPexprGetOwnerData(expr)->nenfos;
13927}
13928
13929/** returns the data for one of the enforcements of an expression */
13931 SCIP_EXPR* expr, /**< expression */
13932 int idx, /**< position of enforcement in enfos array */
13933 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
13934 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
13935 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
13936 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
13937 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
13938 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
13939 )
13940{
13941 SCIP_EXPR_OWNERDATA* ownerdata;
13942
13943 assert(expr != NULL);
13944
13945 ownerdata = SCIPexprGetOwnerData(expr);
13946 assert(ownerdata != NULL);
13947 assert(idx >= 0);
13949 assert(ownerdata->enfos[idx] != NULL);
13950 assert(nlhdlr != NULL);
13951
13952 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
13953
13954 if( nlhdlrexprdata != NULL )
13955 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
13956
13957 if( nlhdlrparticipation != NULL )
13958 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
13959
13960 if( sepabelowusesactivity != NULL )
13961 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
13962
13963 if( sepaaboveusesactivity != NULL )
13964 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
13965
13966 if( auxvalue != NULL )
13967 *auxvalue = ownerdata->enfos[idx]->auxvalue;
13968}
13969
13970/** sets the auxiliary value of expression for one of the enforcements of an expression */
13972 SCIP_EXPR* expr, /**< expression */
13973 int idx, /**< position of enforcement in enfos array */
13974 SCIP_Real auxvalue /**< the new value of auxval */
13975 )
13976{
13977 SCIP_EXPR_OWNERDATA* ownerdata;
13978
13979 assert(expr != NULL);
13980
13981 ownerdata = SCIPexprGetOwnerData(expr);
13982 assert(ownerdata != NULL);
13983
13984 assert(idx >= 0);
13986 assert(ownerdata->enfos[idx] != NULL);
13987
13988 ownerdata->enfos[idx]->auxvalue = auxvalue;
13989}
13990
13991/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
13992 *
13993 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
13994 */
13996 SCIP_EXPR* expr /**< expression */
13997 )
13998{
13999 assert(expr != NULL);
14001
14002 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14003}
14004
14005/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14006 *
14007 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14008 */
14010 SCIP_EXPR* expr /**< expression */
14011 )
14012{
14013 assert(expr != NULL);
14015
14016 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14017}
14018
14019/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14020 *
14021 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14022 */
14024 SCIP_EXPR* expr /**< expression */
14025 )
14026{
14027 assert(expr != NULL);
14029
14030 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14031}
14032
14033/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14034 *
14035 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14036 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14037 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14038 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14039 * and also increments this count for all variables in the expression.
14040 *
14041 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14042 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14043 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14044 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14045 */
14047 SCIP* scip, /**< SCIP data structure */
14048 SCIP_EXPR* expr, /**< expression */
14049 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14050 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14051 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14052 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14053 )
14054{
14055 SCIP_EXPR_OWNERDATA* ownerdata;
14056
14057 assert(expr != NULL);
14058
14059 ownerdata = SCIPexprGetOwnerData(expr);
14060 assert(ownerdata != NULL);
14061
14062 /* do not store auxvar request for variable expressions */
14063 if( useauxvar && SCIPisExprVar(scip, expr) )
14064 useauxvar = FALSE;
14065
14066 if( ownerdata->nenfos >= 0 &&
14067 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14068 (ownerdata->nauxvaruses == 0 && useauxvar)
14069 ) )
14070 {
14071 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14072 * we require additional enforcement methods, that is,
14073 * - activity of expr was not used before but will be used now, or
14074 * - auxiliary variable of expr was not required before but will be used now
14075 */
14076 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14077 }
14078
14079 if( useauxvar )
14080 ++ownerdata->nauxvaruses;
14081
14082 if( useactivityforprop )
14083 ++ownerdata->nactivityusesprop;
14084
14086 ++ownerdata->nactivityusessepa;
14087
14088 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14089 * information is used in detectNlhdlr()
14090 */
14092 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14094 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14095
14096 if( useactivityforprop )
14097 {
14098 /* if activity will be used for propagation, then make sure there is a valid activity
14099 * this way, we can do a reversepropcall after detectNlhdlr
14100 */
14102 }
14103
14104 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14106 {
14108
14109 /* create and initialize iterator */
14112
14113 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14114 if( SCIPisExprVar(scip, expr) )
14115 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14116
14117 /* free iterator */
14119 }
14120
14121 return SCIP_OKAY;
14122}
14123
14124/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14125 *
14126 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14127 * Assume that f(x) is associated with auxiliary variable z.
14128 *
14129 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14130 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14131 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14132 *
14133 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14134 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14135 */
14137 SCIP* scip, /**< SCIP data structure */
14138 SCIP_EXPR* expr, /**< expression */
14139 SCIP_SOL* sol, /**< solution */
14140 SCIP_Longint soltag, /**< tag of solution */
14141 SCIP_Real* viol, /**< buffer to store computed violation */
14142 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14143 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14144 )
14145{
14146 assert(scip != NULL);
14147 assert(expr != NULL);
14148 assert(viol != NULL);
14149
14150 /* make sure expression has been evaluated */
14151 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14152
14153 /* get violation from internal method */
14155
14156 return SCIP_OKAY;
14157}
14158
14159/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14160 *
14161 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14162 * Assume that f(w) is associated with auxiliary variable z.
14163 *
14164 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14165 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14166 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14167 *
14168 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14169 * both `violover` and `violunder` are set to TRUE.
14170 */
14172 SCIP* scip, /**< SCIP data structure */
14173 SCIP_EXPR* expr, /**< expression */
14174 SCIP_Real auxvalue, /**< the value of f(w) */
14175 SCIP_SOL* sol, /**< solution that has been evaluated */
14176 SCIP_Real* viol, /**< buffer to store computed violation */
14177 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14178 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14179 )
14180{
14181 assert(scip != NULL);
14182 assert(expr != NULL);
14183 assert(viol != NULL);
14184
14185 /* get violation from internal method */
14186 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14187
14188 return SCIP_OKAY;
14189}
14190
14191
14192/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14193 *
14194 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14195 * Assume that f(w) is associated with auxiliary variable z.
14196 *
14197 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14198 * the absolute violation divided by max(1,|f(w)|).
14199 *
14200 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14201 * both `violover` and `violunder` are set to TRUE.
14202 */
14204 SCIP* scip, /**< SCIP data structure */
14205 SCIP_EXPR* expr, /**< expression */
14206 SCIP_Real auxvalue, /**< the value of f(w) */
14207 SCIP_SOL* sol, /**< solution that has been evaluated */
14208 SCIP_Real* viol, /**< buffer to store computed violation */
14209 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14210 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14211 )
14212{
14213 assert(scip != NULL);
14214 assert(expr != NULL);
14215 assert(viol != NULL);
14216
14217 /* get violation from internal method */
14218 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14219
14220 if( !SCIPisInfinity(scip, *viol) )
14221 {
14222 assert(auxvalue != SCIP_INVALID);
14223 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14224 *viol /= MAX(1.0, REALABS(auxvalue));
14225 }
14226
14227 return SCIP_OKAY;
14228}
14229
14230/** returns bounds on the expression
14231 *
14232 * This gives an intersection of bounds from
14233 * - activity calculation (SCIPexprGetActivity()), if valid,
14234 * - auxiliary variable, if present,
14235 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14236 *
14237 * @note The returned interval can be empty!
14238 */
14240 SCIP* scip, /**< SCIP data structure */
14241 SCIP_EXPR* expr /**< expression */
14242 )
14243{
14244 SCIP_EXPR_OWNERDATA* ownerdata;
14245 SCIP_CONSHDLRDATA* conshdlrdata;
14246 SCIP_INTERVAL bounds;
14247
14248 assert(scip != NULL);
14249 assert(expr != NULL);
14250
14251 ownerdata = SCIPexprGetOwnerData(expr);
14252 assert(ownerdata != NULL);
14253
14254 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14255 assert(conshdlrdata != NULL);
14256
14257 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14258
14259 /* start with propbounds if they belong to current propagation */
14260 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14261 {
14262 bounds = ownerdata->propbounds;
14263 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14264 }
14265 else
14267
14268 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14269 {
14270 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14271 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14273 }
14274
14275 if( ownerdata->auxvar != NULL )
14276 {
14277 /* apply auxiliary variable bounds to bounds */
14279
14280 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14281 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14283 }
14284
14285 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14286
14287 return bounds;
14288}
14289
14290/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14291 * corresponding (auxiliary) variable (if any)
14292 *
14293 * @attention this function should only be called during domain propagation in cons_nonlinear
14294 */
14296 SCIP* scip, /**< SCIP data structure */
14297 SCIP_EXPR* expr, /**< expression to be tightened */
14298 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14299 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14300 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14301 )
14302{
14303 SCIP_EXPR_OWNERDATA* ownerdata;
14304 SCIP_CONSHDLRDATA* conshdlrdata;
14305
14306 assert(scip != NULL);
14307 assert(expr != NULL);
14308 assert(cutoff != NULL);
14309
14310 ownerdata = SCIPexprGetOwnerData(expr);
14311 assert(ownerdata != NULL);
14312 assert(ownerdata->conshdlr != NULL);
14313
14314 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14315 assert(conshdlrdata != NULL);
14316
14317 /* the code below assumes that current activity is valid
14318 * if it turns out that we cannot ensure that, then we should change code
14319 */
14320 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14322
14323 *cutoff = FALSE;
14324
14325#ifdef DEBUG_PROP
14326 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14327 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14328 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14329#endif
14330
14331 if( SCIPexprIsIntegral(expr) )
14332 {
14333 /* apply integrality to new bounds
14334 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14335 */
14337 newbounds.inf = SCIPceil(scip, newbounds.inf);
14339 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14340#ifdef DEBUG_PROP
14341 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14342#endif
14343 }
14344
14346 {
14347 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14348
14349 *cutoff = TRUE;
14350 return SCIP_OKAY;
14351 }
14352
14353 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14355 {
14356 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14357
14358 *cutoff = TRUE;
14359 return SCIP_OKAY;
14360 }
14361
14362 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14363 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14364 {
14365 /* if already having propbounds in expr, then tighten newbounds by propbounds */
14366 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14367 }
14368 else
14369 {
14370 /* first time we have propbounds for expr in this propagation rounds:
14371 * intersect with activity (though don't let it become empty if very close intervals)
14372 */
14374 }
14375#ifdef DEBUG_PROP
14376 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14377#endif
14378
14379 /* check if the new bounds lead to an empty interval */
14381 {
14382 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14383
14384 *cutoff = TRUE;
14385 return SCIP_OKAY;
14386 }
14387
14388 /* if expr is not constant or variable, then store newbounds in expr->propbounds
14389 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14390 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14391 */
14392 if( SCIPexprGetNChildren(expr) > 0 )
14393 {
14394 ownerdata->propbounds = newbounds;
14395 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14396 }
14397
14398 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14399 * propagation or update of auxvar bounds
14400 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14401 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14402 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14403 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14404 * one or should we not even update propbounds to newbounds if the update is small?
14405 */
14406 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14407 {
14408#ifdef DEBUG_PROP
14409 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);
14410#endif
14411 return SCIP_OKAY;
14412 }
14413
14414 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14415 {
14416 /* add expression to propagation queue if not there yet and not var or constant and
14417 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14418 */
14419#ifdef DEBUG_PROP
14420 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14421#endif
14422 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14423 ownerdata->inpropqueue = TRUE;
14424 }
14425
14426 /* update bounds on variable or auxiliary variable */
14427 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14428
14429 return SCIP_OKAY;
14430}
14431
14432/** mark constraints that include this expression to be propagated again
14433 *
14434 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14435 * a change of variable bounds, e.g., because new information on the expression is available
14436 * that could potentially lead to tighter expression activity values.
14437 *
14438 * Note, that this call marks also constraints for propagation which only share some variable
14439 * with this expression.
14440 */
14442 SCIP* scip, /**< SCIP data structure */
14443 SCIP_EXPR* expr /**< expression to propagate again */
14444 )
14445{
14447 SCIP_CONSDATA* consdata;
14448 SCIP_EXPR_OWNERDATA* ownerdata;
14449 int c;
14450
14451 assert(scip != NULL);
14452 assert(expr != NULL);
14453
14454 ownerdata = SCIPexprGetOwnerData(expr);
14455 assert(ownerdata != NULL);
14456
14457 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14458
14461
14462 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14463 {
14464 if( !SCIPisExprVar(scip, expr) )
14465 continue;
14466
14467 ownerdata = SCIPexprGetOwnerData(expr);
14468 assert(ownerdata != NULL);
14469
14470 for( c = 0; c < ownerdata->nconss; ++c )
14471 {
14472 consdata = SCIPconsGetData(ownerdata->conss[c]);
14473 assert(consdata != NULL);
14474 consdata->ispropagated = FALSE;
14475 }
14476 }
14477
14479
14480 return SCIP_OKAY;
14481}
14482
14483/** adds violation-branching score to an expression
14484 *
14485 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14486 * The expression must either be a variable expression or have an aux-variable.
14487 * In the latter case, branching on auxiliary variables must have been enabled.
14488 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14489 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14490 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14491 *
14492 * @see SCIPaddExprsViolScoreNonlinear()
14493 */
14495 SCIP* scip, /**< SCIP data structure */
14496 SCIP_EXPR* expr, /**< expression where to add branching score */
14497 SCIP_Real violscore /**< violation score to add to expression */
14498 )
14499{
14500 SCIP_EXPR_OWNERDATA* ownerdata;
14501 SCIP_CONSHDLRDATA* conshdlrdata;
14502
14503 assert(scip != NULL);
14504 assert(expr != NULL);
14505 assert(violscore >= 0.0);
14506
14507 ownerdata = SCIPexprGetOwnerData(expr);
14508 assert(ownerdata != NULL);
14509
14510 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14511 assert(conshdlrdata != NULL);
14512
14513 /* if not allowing to branch on auxvars, then expr must be a var-expr */
14514 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14515 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14516 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14517
14518 /* reset branching score if we are in a different enfo round */
14519 if( ownerdata->violscoretag != conshdlrdata->enforound )
14520 {
14521 ownerdata->violscoresum = violscore;
14522 ownerdata->violscoremax = violscore;
14523 ownerdata->nviolscores = 1;
14524 ownerdata->violscoretag = conshdlrdata->enforound;
14525 return;
14526 }
14527
14528 ownerdata->violscoresum += violscore;
14529 if( violscore > ownerdata->violscoremax )
14530 ownerdata->violscoremax = violscore;
14531 ++ownerdata->nviolscores;
14532}
14533
14534/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14535 *
14536 * Each expression must either be a variable expression or have an aux-variable.
14537 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14538 * variables present in `exprs`.
14539 */
14541 SCIP* scip, /**< SCIP data structure */
14542 SCIP_EXPR** exprs, /**< expressions where to add branching score */
14543 int nexprs, /**< number of expressions */
14544 SCIP_Real violscore, /**< violation score to add to expression */
14545 SCIP_SOL* sol, /**< current solution */
14546 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
14547 )
14548{
14550 SCIP_EXPR** varexprs;
14551 SCIP_EXPR* e;
14552 int nvars;
14553 int varssize;
14554 int i;
14555
14556 assert(exprs != NULL || nexprs == 0);
14557 assert(success != NULL);
14558
14559 if( nexprs == 0 )
14560 {
14561 *success = FALSE;
14562 return SCIP_OKAY;
14563 }
14564
14565 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
14566 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
14567 {
14568 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
14569 return SCIP_OKAY;
14570 }
14571
14572 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
14573 nvars = 0;
14574 varssize = 5;
14575 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
14576
14579
14580 for( i = 0; i < nexprs; ++i )
14581 {
14583 {
14584 assert(e != NULL);
14585
14586 if( SCIPisExprVar(scip, e) )
14587 {
14588 /* add variable expression to vars array */
14589 if( varssize == nvars )
14590 {
14591 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
14592 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
14593 }
14594 assert(varssize > nvars);
14595
14596 varexprs[nvars++] = e;
14597 }
14598 }
14599 }
14600
14602
14604
14605 SCIPfreeBufferArray(scip, &varexprs);
14606
14607 return SCIP_OKAY;
14608}
14609
14610/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
14612 SCIP_EXPR* expr /**< expression */
14613 )
14614{
14615 SCIP_EXPR_OWNERDATA* ownerdata;
14616 SCIP_CONSHDLRDATA* conshdlrdata;
14617
14618 assert(expr != NULL);
14619
14620 ownerdata = SCIPexprGetOwnerData(expr);
14621 assert(ownerdata != NULL);
14622
14623 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14624 assert(conshdlrdata != NULL);
14625
14626 if( conshdlrdata->enforound != ownerdata->violscoretag )
14627 return 0.0;
14628
14629 if( ownerdata->nviolscores == 0 )
14630 return 0.0;
14631
14632 switch( conshdlrdata->branchscoreagg )
14633 {
14634 case 'a' :
14635 /* average */
14636 return ownerdata->violscoresum / ownerdata->nviolscores;
14637
14638 case 'm' :
14639 /* maximum */
14640 return ownerdata->violscoremax;
14641
14642 case 's' :
14643 /* sum */
14644 return ownerdata->violscoresum;
14645
14646 default:
14647 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
14648 SCIPABORT();
14649 return SCIP_INVALID;
14650 }
14651}
14652
14653/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
14654 *
14655 * @see SCIPexprGetDerivative()
14656 */
14658 SCIP* scip, /**< SCIP data structure */
14659 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
14660 SCIP_VAR* var /**< variable (needs to be in the expression) */
14661 )
14662{
14663 SCIP_EXPR_OWNERDATA* ownerdata;
14664 SCIP_CONSHDLRDATA* conshdlrdata;
14666
14667 assert(scip != NULL);
14668 assert(expr != NULL);
14669 assert(var != NULL);
14670
14671 /* return 0.0 for value expression */
14672 if( SCIPisExprValue(scip, expr) )
14673 {
14674 assert(SCIPexprGetDerivative(expr) == 0.0);
14675 return 0.0;
14676 }
14677
14678 /* check if an error occurred during the last SCIPevalExprGradient() call */
14679 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
14680 return SCIP_INVALID;
14681
14682 ownerdata = SCIPexprGetOwnerData(expr);
14683 assert(ownerdata != NULL);
14684
14685 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14686 assert(conshdlrdata != NULL);
14687
14688 /* use variable to expressions mapping which is stored in the constraint handler data */
14689 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
14690
14691 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
14692 assert(varexpr != NULL);
14694
14695 /* use difftag to decide whether the variable belongs to the expression */
14697}
14698
14699/** 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)
14700 *
14701 * @see SCIPexprGetBardot()
14702 */
14704 SCIP* scip, /**< SCIP data structure */
14705 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
14706 SCIP_VAR* var /**< variable (needs to be in the expression) */
14707 )
14708{
14709 SCIP_EXPR_OWNERDATA* ownerdata;
14710 SCIP_CONSHDLRDATA* conshdlrdata;
14712
14713 assert(scip != NULL);
14714 assert(expr != NULL);
14715 assert(var != NULL);
14716
14717 /* return 0.0 for value expression */
14718 if( SCIPisExprValue(scip, expr) )
14719 return 0.0;
14720
14721 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
14722 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
14723 return SCIP_INVALID;
14724
14725 ownerdata = SCIPexprGetOwnerData(expr);
14726 assert(ownerdata != NULL);
14727
14728 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14729 assert(conshdlrdata != NULL);
14730
14731 /* use variable to expressions mapping which is stored in the constraint handler data;
14732 * if this fails it means that we are asking for the var's component of H*u for a var
14733 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
14734 */
14735 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
14736
14737 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
14738 assert(varexpr != NULL);
14740
14741 /* use difftag to decide whether the variable belongs to the expression */
14743}
14744
14745/** evaluates quadratic term in a solution w.r.t. auxiliary variables
14746 *
14747 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
14748 */
14750 SCIP* scip, /**< SCIP data structure */
14751 SCIP_EXPR* expr, /**< quadratic expression */
14752 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
14753 )
14754{
14755 SCIP_Real auxvalue;
14756 int nlinexprs;
14757 SCIP_Real* lincoefs;
14758 SCIP_EXPR** linexprs;
14759 int nquadexprs;
14760 int nbilinexprs;
14761 int i;
14762
14763 assert(scip != NULL);
14764 assert(expr != NULL);
14765
14766 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
14767
14768 /* linear terms */
14769 for( i = 0; i < nlinexprs; ++i )
14770 {
14771 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
14772 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
14773 }
14774
14775 /* quadratic terms */
14776 for( i = 0; i < nquadexprs; ++i )
14777 {
14779 SCIP_Real lincoef;
14780 SCIP_Real sqrcoef;
14781 SCIP_Real solval;
14782
14783 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
14784
14786
14788 auxvalue += (lincoef + sqrcoef * solval) * solval;
14789 }
14790
14791 /* bilinear terms */
14792 for( i = 0; i < nbilinexprs; ++i )
14793 {
14794 SCIP_EXPR* expr1;
14795 SCIP_EXPR* expr2;
14796 SCIP_Real coef;
14797
14798 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
14799
14803 }
14804
14805 return auxvalue;
14806}
14807
14808/**@addtogroup PublicNlhdlrInterfaceMethods
14809 * @{
14810 */
14811
14812/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
14814 SCIP* scip, /**< SCIP data structure */
14815 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
14816 const char* name, /**< name of nonlinear handler (must not be NULL) */
14817 const char* desc, /**< description of nonlinear handler (can be NULL) */
14818 int detectpriority, /**< detection priority of nonlinear handler */
14819 int enfopriority, /**< enforcement priority of nonlinear handler */
14820 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
14821 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
14822 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
14823 )
14824{
14825 SCIP_CONSHDLR* conshdlr;
14826 SCIP_CONSHDLRDATA* conshdlrdata;
14827
14828 assert(scip != NULL);
14829 assert(nlhdlr != NULL);
14830 assert(detect != NULL);
14831
14832 /* find myself */
14833 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14834 if( conshdlr == NULL )
14835 {
14836 SCIPerrorMessage("nonlinear constraint handler not found");
14837 return SCIP_PLUGINNOTFOUND;
14838 }
14839
14840 /* create nlhdlr */
14841 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
14842
14843 /* include into constraint handler */
14844 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14845 assert(conshdlrdata != NULL);
14846
14847 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
14848
14849 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
14850 ++conshdlrdata->nnlhdlrs;
14851
14852 /* sort nonlinear handlers by detection priority, in decreasing order
14853 * will happen in INIT, so only do when called late
14854 */
14855 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
14856 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
14857
14858 return SCIP_OKAY;
14859}
14860
14861/** get number of nonlinear handler */
14863 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
14864 )
14865{
14866 SCIP_CONSHDLRDATA* conshdlrdata;
14867
14868 assert(conshdlr != NULL);
14869
14870 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14871 assert(conshdlrdata != NULL);
14872
14873 return conshdlrdata->nnlhdlrs;
14874}
14875
14876/** get nonlinear handlers */
14878 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
14879 )
14880{
14881 SCIP_CONSHDLRDATA* conshdlrdata;
14882
14883 assert(conshdlr != NULL);
14884
14885 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14886 assert(conshdlrdata != NULL);
14887
14888 return conshdlrdata->nlhdlrs;
14889}
14890
14891/** returns a nonlinear handler of a given name (or NULL if not found) */
14893 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
14894 const char* name /**< name of nonlinear handler */
14895 )
14896{
14897 SCIP_CONSHDLRDATA* conshdlrdata;
14898 int h;
14899
14900 assert(conshdlr != NULL);
14901 assert(name != NULL);
14902
14903 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14904 assert(conshdlrdata != NULL);
14905
14906 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
14907 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
14908 return conshdlrdata->nlhdlrs[h];
14909
14910 return NULL;
14911}
14912
14913/** gives expression data that a given nonlinear handler stored in an expression
14914 *
14915 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
14916 */
14918 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
14919 SCIP_EXPR* expr /**< expression */
14920 )
14921{
14922 SCIP_EXPR_OWNERDATA* ownerdata;
14923 int e;
14924
14925 assert(nlhdlr != NULL);
14926 assert(expr != NULL);
14927
14928 ownerdata = SCIPexprGetOwnerData(expr);
14929 assert(ownerdata != NULL);
14930
14931 for( e = 0; e < ownerdata->nenfos; ++e )
14932 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
14933 return ownerdata->enfos[e]->nlhdlrexprdata;
14934
14935 return NULL;
14936}
14937
14938/** @} */
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)
static SCIP_Bool isEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *hasvalue, SCIP_Real *value)
#define ENFOLOG(x)
#define DIALOG_DESC
static SCIP_RETCODE tryAddGadgetEvenOperatorVariable(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_Bool *success)
#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 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)
static SCIP_RETCODE tryAddGadgetEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
#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 tryAddGadgetSquaredDifference(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_CONS *cons, SYM_GRAPH *graph, int sumnodeidx, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs)
static SCIP_RETCODE tryAddGadgetBilinearProductSignedPerm(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
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_RETCODE tryAddGadgetEvenOperatorSum(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
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 ensureLocVarsArraySize(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **vals, int nelems, int *maxnelems)
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 presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
#define VERTEXPOLY_USEDUALSIMPLEX
#define CONSHDLR_PROPFREQ
static SCIP_Bool varIsCenteredAt0(SCIP *scip, SCIP_VAR *var)
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_RETCODE notifyNlhdlrNewsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solisbest)
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)
static SCIP_Real getDomainCenter(SCIP *scip, SCIP_VAR *var)
#define TABLE_POSITION_NLHDLR
static SCIP_RETCODE ensureOpenArraySizeSymdetect(SCIP *scip, int **openidx, int nelems, int *maxnelems)
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 NULL
Definition def.h:267
#define SCIP_MAXSTRLEN
Definition def.h:288
#define EPSROUND(x, eps)
Definition def.h:208
#define EPSISINT(x, eps)
Definition def.h:210
#define SCIP_REAL_MAX
Definition def.h:174
#define SCIP_INVALID
Definition def.h:193
#define SCIP_INTERVAL_INFINITY
Definition def.h:195
#define MIN(x, y)
Definition def.h:243
#define MAX3(x, y, z)
Definition def.h:247
#define ABS(x)
Definition def.h:235
#define EPSFRAC(x, eps)
Definition def.h:209
#define TRUE
Definition def.h:93
#define FALSE
Definition def.h:94
#define MAX(x, y)
Definition def.h:239
#define SCIP_CALL_ABORT(x)
Definition def.h:353
#define SCIP_LONGINT_FORMAT
Definition def.h:165
#define SCIPABORT()
Definition def.h:346
#define REALABS(x)
Definition def.h:197
#define SCIP_CALL(x)
Definition def.h:374
default user interface dialog
absolute expression handler
power and signed power expression handlers
sum expression handler
handler for sin expressions
constant value expression handler
variable expression handler
handler for variable index expressions
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:5186
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_Bool SCIPisExprVaridx(SCIP *scip, SCIP_EXPR *expr)
SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
Definition expr_abs.c:546
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition expr_sum.c:1151
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:3217
SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
Definition expr_pow.c:3242
SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
Definition expr_trig.c:1480
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:1114
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:3193
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:3108
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3281
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3261
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3156
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition misc.c:3533
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3074
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3423
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3192
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3439
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition misc.c:3790
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition misc.c:3817
SCIP_Bool SCIPhashsetIsEmpty(SCIP_HASHSET *hashset)
Definition misc.c:3984
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition misc.c:3800
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition misc.c:3759
SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
Definition misc.c:3858
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2346
#define SCIPhashTwo(a, b)
Definition pub_misc.h:551
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:2296
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2608
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2547
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)
#define SCIPisFinite(x)
Definition pub_misc.h:1933
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:10396
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition misc.c:10383
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:4227
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4970
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4636
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4197
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:941
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4217
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_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)), SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:83
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4593
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8234
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition cons.c:8332
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8383
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2537
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition cons.c:8513
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8343
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8523
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8403
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8275
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:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8453
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition cons.c:8311
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8214
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition cons.c:8321
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8463
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1174
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8483
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)
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_VARTYPE SCIPeventGetNewtype(SCIP_EVENT *event)
Definition event.c:1283
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:545
SCIP_Bool SCIPexprhdlrHasGetSymData(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:685
SCIP_Bool SCIPexprhdlrHasMonotonicity(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:665
SCIP_Bool SCIPexprhdlrHasReverseProp(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:675
void SCIPexprSetActivity(SCIP_EXPR *expr, SCIP_INTERVAL activity, SCIP_Longint activitytag)
Definition expr.c:4036
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:1033
SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
Definition scip_expr.c:1792
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1635
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3854
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition expr.c:4198
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:2015
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition expr_pow.c:3456
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1464
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1667
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition expriter.c:969
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition scip_expr.c:1651
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:930
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition expr.c:3915
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition expr.c:3954
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1453
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition scip_expr.c:2058
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition expr.c:3941
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition expr.c:4073
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition expr.c:4234
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:4113
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition scip_expr.c:1248
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1552
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition expriter.c:756
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1442
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:2395
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1417
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition expriter.c:683
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition expriter.c:664
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1431
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:1380
SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition expriter.c:630
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition scip_expr.c:2337
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition expr.c:4083
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition scip_expr.c:1486
SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:740
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition expr_value.c:294
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition expriter.c:806
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1475
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition expr.c:3928
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition expr.c:4026
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition scip_expr.c:1820
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition expriter.c:858
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition scip_expr.c:2377
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition expr.c:3982
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3864
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1567
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:1318
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition expr_var.c:416
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition expriter.c:838
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition expr.c:4010
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:4158
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:707
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition scip_expr.c:2351
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:696
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:1281
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition scip_expr.c:1409
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition expriter.c:501
int SCIPexprGetNUses(SCIP_EXPR *expr)
Definition expr.c:3844
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition scip_expr.c:2096
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition expr.c:3997
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:1773
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1717
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition expr.c:3877
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:721
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition scip_heur.c:258
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition heur.c:1453
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
BMS_BUFMEM * SCIPbuffer(SCIP *scip)
Definition scip_mem.c:72
#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:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:396
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:1248
SCIP_RETCODE SCIPaddLinearCoefToNlRow(SCIP *scip, SCIP_NLROW *nlrow, SCIP_VAR *var, SCIP_Real val)
Definition scip_nlp.c:1161
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1058
SCIP_RETCODE SCIPchgNlRowConstant(SCIP *scip, SCIP_NLROW *nlrow, SCIP_Real constant)
Definition scip_nlp.c:1126
void SCIPsetNlRowCurvature(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:1140
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:954
const char * SCIPnlhdlrGetDesc(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:176
SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:226
int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:186
SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:206
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:166
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:276
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:246
int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:196
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:2711
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:474
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition sol.c:2804
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:226
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1046
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition scip_sol.c:1174
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1077
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1217
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1347
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
int SCIPgetSymExprdataNConstants(SYM_EXPRDATA *symdata)
int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_RETCODE SCIPfreeSymDataExpr(SCIP *scip, SYM_EXPRDATA **symdata)
int SCIPgetSymgraphNNodes(SYM_GRAPH *graph)
SCIP_Real * SCIPgetSymExprdataConstants(SYM_EXPRDATA *symdata)
SCIP_RETCODE SCIPgetCoefSymData(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *parentexpr, SCIP_Real *coef, SCIP_Bool *success)
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_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_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
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:5205
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition scip_var.c:4319
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition var.c:17789
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition scip_var.c:8952
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:17538
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:18144
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:17926
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition var.c:17724
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:5322
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:17584
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:18088
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:17758
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:17419
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1250
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition scip_var.c:4647
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition scip_var.c:8816
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition scip_var.c:4615
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:17610
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition scip_var.c:8178
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18430
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:18134
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:18441
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:18078
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:8717
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:11942
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:1441
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1216
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition misc.c:1017
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition misc.c:993
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition misc.c:1079
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition misc.c:1234
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition misc.c:1130
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10130
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition misc.c:10108
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
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_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:6077
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)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition misc.c:5538
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10877
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10866
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
SCIP_Bool SCIPlapackIsAvailable(void)
SCIP_RETCODE SCIPlapackSolveLinearEquations(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
interface methods for lapack functions
static const char * paramname[]
Definition lpi_msk.c:5096
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition nlhdlr.c:401
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:353
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition nlhdlr.c:750
private functions of nonlinear handlers of nonlinear constraints
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition nlhdlr.h:131
#define SCIPnlhdlrResetNDetectionslast(nlhdlr)
Definition nlhdlr.h:129
#define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
Definition nlhdlr.h:130
nonlinear handlers for convex and concave expressions, respectively
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
SCIP_RETCODE SCIPgetSymOpNodeType(SCIP *scip, const char *opnodename, int *nodetype)
propagator for symmetry handling
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebugPrintCons(x, y, z)
methods for sorting joint arrays of various types
public functions to work with algebraic expressions
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
structs for symmetry computations
methods for dealing with symmetry detection graphs
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:955
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:937
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:136
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:866
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:768
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSDISABLE(x)
Definition type_cons.h:735
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition type_cons.h:919
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:505
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:884
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:611
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:690
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:844
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:705
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:560
#define SCIP_DECL_CONSENABLE(x)
Definition type_cons.h:720
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:675
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:809
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:126
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:752
#define SCIP_DECL_DIALOGEXEC(x)
Definition type_dialog.h:96
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition type_event.h:125
#define SCIP_EVENTTYPE_TYPECHANGED
Definition type_event.h:86
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:143
SCIP_EXPRCURV
Definition type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition type_expr.h:63
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
@ SCIP_EXPRCURV_UNKNOWN
Definition type_expr.h:62
@ SCIP_EXPRCURV_CONCAVE
Definition type_expr.h:64
#define SCIP_EXPRITER_VISITINGCHILD
Definition type_expr.h:693
#define SCIP_DECL_EXPR_OWNERPRINT(x)
Definition type_expr.h:109
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition type_expr.h:80
SCIP_MONOTONE
Definition type_expr.h:70
@ SCIP_MONOTONE_CONST
Definition type_expr.h:74
@ SCIP_MONOTONE_UNKNOWN
Definition type_expr.h:71
@ SCIP_MONOTONE_INC
Definition type_expr.h:72
@ SCIP_MONOTONE_DEC
Definition type_expr.h:73
#define SCIP_DECL_EXPR_INTEVALVAR(x)
Definition type_expr.h:163
@ SCIP_EXPRITER_BFS
Definition type_expr.h:715
@ SCIP_EXPRITER_DFS
Definition type_expr.h:716
@ SCIP_EXPRITER_RTOPOLOGIC
Definition type_expr.h:714
#define SCIP_DECL_EXPR_MAPEXPR(x)
Definition type_expr.h:182
#define SCIP_DECL_EXPR_OWNERFREE(x)
Definition type_expr.h:95
#define SCIP_EXPRITER_LEAVEEXPR
Definition type_expr.h:695
#define SCIP_DECL_EXPR_OWNEREVALACTIVITY(x)
Definition type_expr.h:125
#define SCIP_EXPRITER_ENTEREXPR
Definition type_expr.h:692
@ 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
enum SYM_Symtype SYM_SYMTYPE
@ SYM_CONSOPTYPE_SUM
@ SYM_CONSOPTYPE_COEF
@ SYM_CONSOPTYPE_SQDIFF
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#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_VARSTATUS_MULTAGGR
Definition type_var.h:54
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:97
enum SCIP_Vartype SCIP_VARTYPE
Definition type_var.h:73