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 50 /**< 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 }
139FILE* enfologfile = NULL;
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 branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
313 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
314 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
315 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
316 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
317 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
318 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
319 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
320 SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
321 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) */
322 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
323
324 /* statistics */
325 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
326 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
327 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 */
328 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
329 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
330 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
331 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
332 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
333
334 /* facets of envelops of vertex-polyhedral functions */
335 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
336 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
337
338 /* hashing of bilinear terms */
339 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
340 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
341 int nbilinterms; /**< total number of bilinear terms */
342 int bilintermssize; /**< size of bilinterms array */
343 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
344
345 /* branching */
346 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
347 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
348
349 /* misc */
350 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
351 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
352 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
353};
354
355/** branching candidate with various scores */
356typedef struct
357{
358 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
359 SCIP_VAR* var; /**< variable that is branching candidate */
360 SCIP_Real auxviol; /**< aux-violation score of candidate */
361 SCIP_Real domain; /**< domain score of candidate */
362 SCIP_Real dual; /**< dual score of candidate */
363 SCIP_Real pscost; /**< pseudo-cost score of candidate */
364 SCIP_Real vartype; /**< variable type score of candidate */
365 SCIP_Real fractionality; /**< fractionality score of candidate */
366 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
367} BRANCHCAND;
368
369/*
370 * Local methods
371 */
372
373/* forward declaration */
374static
376 SCIP* scip, /**< SCIP data structure */
377 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
378 SCIP_EXPR* rootexpr, /**< expression */
379 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
380 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
381 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
382 );
383
384/** frees auxiliary variables of expression, if any */
385static
387 SCIP* scip, /**< SCIP data structure */
388 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
389 )
390{
391 SCIP_EXPR_OWNERDATA* mydata;
392
393 assert(scip != NULL);
394 assert(expr != NULL);
395
396 mydata = SCIPexprGetOwnerData(expr);
397 assert(mydata != NULL);
398
399 if( mydata->auxvar == NULL )
400 return SCIP_OKAY;
401
402 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
403
404 /* remove variable locks
405 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
406 */
407 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
408
409 /* release auxiliary variable */
410 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
411 assert(mydata->auxvar == NULL);
412
413 return SCIP_OKAY;
414}
415
416/** frees data used for enforcement of expression, that is, nonlinear handlers
417 *
418 * can also clear indicators whether expr needs enforcement methods, that is,
419 * free an associated auxiliary variable and reset the nactivityuses counts
420 */
421static
423 SCIP* scip, /**< SCIP data structure */
424 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
425 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
426 )
427{
428 SCIP_EXPR_OWNERDATA* mydata;
429 int e;
430
431 mydata = SCIPexprGetOwnerData(expr);
432 assert(mydata != NULL);
433
434 if( freeauxvar )
435 {
436 /* free auxiliary variable */
437 SCIP_CALL( freeAuxVar(scip, expr) );
438 assert(mydata->auxvar == NULL);
439
440 /* reset count on activity and auxvar usage */
441 mydata->nactivityusesprop = 0;
442 mydata->nactivityusessepa = 0;
443 mydata->nauxvaruses = 0;
444 }
445
446 /* free data stored by nonlinear handlers */
447 for( e = 0; e < mydata->nenfos; ++e )
448 {
449 SCIP_NLHDLR* nlhdlr;
450
451 assert(mydata->enfos[e] != NULL);
452
453 nlhdlr = mydata->enfos[e]->nlhdlr;
454 assert(nlhdlr != NULL);
455
456 if( mydata->enfos[e]->issepainit )
457 {
458 /* call the separation deinitialization callback of the nonlinear handler */
459 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
460 mydata->enfos[e]->issepainit = FALSE;
461 }
462
463 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
464 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
465 {
466 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
467 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
468 }
469
470 /* free enfo data */
471 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
472 }
473
474 /* free array with enfo data */
475 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
476
477 /* we need to look at this expression in detect again */
478 mydata->nenfos = -1;
479
480 return SCIP_OKAY;
481}
482
483/** callback that frees data that this conshdlr stored in an expression */
484static
486{
487 assert(scip != NULL);
488 assert(expr != NULL);
489 assert(ownerdata != NULL);
490 assert(*ownerdata != NULL);
491
492 /* expression should not be locked anymore */
493 assert((*ownerdata)->nlockspos == 0);
494 assert((*ownerdata)->nlocksneg == 0);
495
496 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
497
498 /* expression should not be enforced anymore */
499 assert((*ownerdata)->nenfos <= 0);
500 assert((*ownerdata)->auxvar == NULL);
501
502 if( SCIPisExprVar(scip, expr) )
503 {
504 SCIP_CONSHDLRDATA* conshdlrdata;
505 SCIP_VAR* var;
506
507 /* there should be no constraints left that still use this variable */
508 assert((*ownerdata)->nconss == 0);
509 /* thus, there should also be no variable event catched (via this exprhdlr) */
510 assert((*ownerdata)->filterpos == -1);
511
512 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
513
514 /* update var2expr hashmap in conshdlrdata */
515 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
516 assert(conshdlrdata != NULL);
517
518 var = SCIPgetVarExprVar(expr);
519 assert(var != NULL);
520
521 /* remove var -> expr map from hashmap if present
522 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
523 * if variable-expression stored for var is different, then also do nothing)
524 */
525 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
526 {
527 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
528 }
529 }
530
531 SCIPfreeBlockMemory(scip, ownerdata);
532
533 return SCIP_OKAY;
534}
535
536static
538{ /*lint --e{715}*/
539 assert(ownerdata != NULL);
540
541 /* print nl handlers associated to expr */
542 if( ownerdata->nenfos > 0 )
543 {
544 int i;
545 SCIPinfoMessage(scip, file, " {");
546
547 for( i = 0; i < ownerdata->nenfos; ++i )
548 {
549 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
550 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
551 SCIPinfoMessage(scip, file, "a");
552 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
553 SCIPinfoMessage(scip, file, "u");
554 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
555 SCIPinfoMessage(scip, file, "o");
556 if( i < ownerdata->nenfos-1 )
557 SCIPinfoMessage(scip, file, ", ");
558 }
559
560 SCIPinfoMessage(scip, file, "}");
561 }
562
563 /* print aux var associated to expr */
564 if( ownerdata->auxvar != NULL )
565 {
566 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
567 }
568 SCIPinfoMessage(scip, file, "\n");
569
570 return SCIP_OKAY;
571}
572
573/** possibly reevaluates and then returns the activity of the expression
574 *
575 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
576 */
577static
579{
580 SCIP_CONSHDLRDATA* conshdlrdata;
581
582 assert(scip != NULL);
583 assert(expr != NULL);
584 assert(ownerdata != NULL);
585
586 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
587 assert(conshdlrdata != NULL);
588
589 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
590 {
591 /* update activity of expression */
592 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
593
594 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
595 }
596
597 return SCIP_OKAY;
598}
599
600/** callback that creates data that this conshdlr wants to store in an expression */
601static
603{
604 assert(scip != NULL);
605 assert(expr != NULL);
606 assert(ownerdata != NULL);
607
609 (*ownerdata)->nenfos = -1;
610 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
611
612 if( SCIPisExprVar(scip, expr) )
613 {
614 SCIP_CONSHDLRDATA* conshdlrdata;
615 SCIP_VAR* var;
616
617 (*ownerdata)->filterpos = -1;
618
619 /* add to var2expr hashmap if not having expr for var yet */
620
621 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
622 assert(conshdlrdata != NULL);
623
624 var = SCIPgetVarExprVar(expr);
625
626 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
627 {
628 /* store the variable expression in the hashmap */
629 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
630 }
631 else
632 {
633 /* if expr was just created, then it shouldn't already be stored as image of var */
634 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
635 }
636 }
637 else
638 {
639 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
640 (*ownerdata)->filterpos = -2;
641 }
642
643 *ownerfree = exprownerFree;
644 *ownerprint = exprownerPrint;
645 *ownerevalactivity = exprownerEvalactivity;
646
647 return SCIP_OKAY;
648}
649
650/** creates a variable expression or retrieves from hashmap in conshdlr data */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
655 SCIP_EXPR** expr, /**< pointer where to store expression */
656 SCIP_VAR* var /**< variable to be stored */
657 )
658{
659 assert(conshdlr != NULL);
660 assert(expr != NULL);
661 assert(var != NULL);
662
663 /* get variable expression representing the given variable if there is one already */
664 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
665
666 if( *expr == NULL )
667 {
668 /* create a new variable expression; this also captures the expression */
669 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
670 assert(*expr != NULL);
671 /* exprownerCreate should have added var->expr to var2expr */
672 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
673 }
674 else
675 {
676 /* only capture already existing expr to get a consistent uses-count */
677 SCIPcaptureExpr(*expr);
678 }
679
680 return SCIP_OKAY;
681}
682
683/* map var exprs to var-expr from var2expr hashmap */
684static
686{ /*lint --e{715}*/
687 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
688
689 assert(sourcescip != NULL);
690 assert(targetscip != NULL);
691 assert(sourceexpr != NULL);
692 assert(targetexpr != NULL);
693 assert(*targetexpr == NULL);
694 assert(mapexprdata != NULL);
695
696 /* do not provide map if not variable */
697 if( !SCIPisExprVar(sourcescip, sourceexpr) )
698 return SCIP_OKAY;
699
700 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
701
702 return SCIP_OKAY;
703}
704
705/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
706static
708{ /*lint --e{715}*/
709 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
710 SCIP_VAR* var;
711
712 assert(sourcescip != NULL);
713 assert(targetscip != NULL);
714 assert(sourceexpr != NULL);
715 assert(targetexpr != NULL);
716 assert(*targetexpr == NULL);
717 assert(mapexprdata != NULL);
718
719 /* do not provide map if not variable */
720 if( !SCIPisExprVar(sourcescip, sourceexpr) )
721 return SCIP_OKAY;
722
723 var = SCIPgetVarExprVar(sourceexpr);
724 assert(var != NULL);
725
726 /* transform variable */
727 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
728 assert(var != NULL);
729
730 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
731
732 return SCIP_OKAY;
733}
734
735/** stores all variable expressions into a given constraint */
736static
738 SCIP* scip, /**< SCIP data structure */
739 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
740 SCIP_CONSDATA* consdata /**< constraint data */
741 )
742{
743 SCIP_CONSHDLRDATA* conshdlrdata;
744 int varexprssize;
745 int i;
746
747 assert(consdata != NULL);
748
749 /* skip if we have stored the variable expressions already */
750 if( consdata->varexprs != NULL )
751 return SCIP_OKAY;
752
753 assert(consdata->varexprs == NULL);
754 assert(consdata->nvarexprs == 0);
755
756 /* get an upper bound on number of variable expressions */
757 if( consdata->issimplified )
758 {
759 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
760 * so we cannot have more variable expression than the number of active variables
761 */
762 varexprssize = SCIPgetNVars(scip);
763 }
764 else
765 {
766 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
767 }
768
769 /* create array to store all variable expressions */
770 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
771
772 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
773 assert(varexprssize >= consdata->nvarexprs);
774
775 /* shrink array if there are less variables in the expression than in the problem */
776 if( varexprssize > consdata->nvarexprs )
777 {
778 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
779 }
780
781 conshdlrdata = SCIPconshdlrGetData(conshdlr);
782 assert(conshdlrdata != NULL);
783 assert(conshdlrdata->var2expr != NULL);
784
785 /* ensure that for every variable an entry exists in the var2expr hashmap
786 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
787 */
788 for( i = 0; i < consdata->nvarexprs; ++i )
789 {
790 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
791 {
792 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
793 }
794 }
795
796 return SCIP_OKAY;
797}
798
799/** frees all variable expression stored in storeVarExprs() */
800static
802 SCIP* scip, /**< SCIP data structure */
803 SCIP_CONSDATA* consdata /**< constraint data */
804 )
805{
806 int i;
807
808 assert(consdata != NULL);
809
810 /* skip if we have stored the variable expressions already*/
811 if( consdata->varexprs == NULL )
812 return SCIP_OKAY;
813
814 assert(consdata->varexprs != NULL);
815 assert(consdata->nvarexprs >= 0);
816
817 /* release variable expressions */
818 for( i = 0; i < consdata->nvarexprs; ++i )
819 {
820 assert(consdata->varexprs[i] != NULL);
821 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
822 assert(consdata->varexprs[i] == NULL);
823 }
824
825 /* free variable expressions */
826 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
827 consdata->varexprs = NULL;
828 consdata->nvarexprs = 0;
829
830 return SCIP_OKAY;
831}
832
833/** interval evaluation of variables as used in bound tightening
834 *
835 * Returns slightly relaxed local variable bounds of a variable as interval.
836 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
837 */
838static
839SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
840{
841 SCIP_INTERVAL interval;
842 SCIP_CONSHDLRDATA* conshdlrdata;
843 SCIP_Real lb;
844 SCIP_Real ub;
845
846 assert(scip != NULL);
847 assert(var != NULL);
848
849 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
850 assert(conshdlrdata != NULL);
851
852 if( conshdlrdata->globalbounds )
853 {
856 }
857 else
858 {
861 }
862 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
863
864 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
866 {
867 lb = EPSROUND(lb, 0.0); /*lint !e835*/
868 ub = EPSROUND(ub, 0.0); /*lint !e835*/
869 }
870
871 /* integer variables should always have integral bounds in SCIP */
872 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
873 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
874
875 switch( conshdlrdata->varboundrelax )
876 {
877 case 'n' : /* no relaxation */
878 break;
879
880 case 'a' : /* relax by absolute value */
881 {
882 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
884 break;
885
886 if( !SCIPisInfinity(scip, -lb) )
887 {
888 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
889 SCIP_Real bnd = floor(lb);
890 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
891 }
892
893 if( !SCIPisInfinity(scip, ub) )
894 {
895 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
896 SCIP_Real bnd = ceil(ub);
897 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
898 }
899
900 break;
901 }
902
903 case 'b' : /* relax always by absolute value */
904 {
905 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
907 break;
908
909 if( !SCIPisInfinity(scip, -lb) )
910 lb -= conshdlrdata->varboundrelaxamount;
911
912 if( !SCIPisInfinity(scip, ub) )
913 ub += conshdlrdata->varboundrelaxamount;
914
915 break;
916 }
917
918 case 'r' : /* relax by relative value */
919 {
920 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
922 break;
923
924 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
925 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
926 * further, do not relax beyond next integer value
927 */
928 if( !SCIPisInfinity(scip, -lb) )
929 {
930 SCIP_Real bnd = floor(lb);
931 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
932 }
933
934 if( !SCIPisInfinity(scip, ub) )
935 {
936 SCIP_Real bnd = ceil(ub);
937 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
938 }
939
940 break;
941 }
942
943 default :
944 {
945 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
946 SCIPABORT();
947 break;
948 }
949 }
950
951 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
954 assert(lb <= ub);
955
956 SCIPintervalSetBounds(&interval, lb, ub);
957
958 return interval;
959}
960
961/** compares two nonlinear constraints by its index
962 *
963 * Usable as compare operator in array sort functions.
964 */
965static
966SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
967{
968 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
969 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
970
971 assert(consdata1 != NULL);
972 assert(consdata2 != NULL);
973
974 return consdata1->consindex - consdata2->consindex;
975}
976
977/** processes variable fixing or bound change event */
978static
979SCIP_DECL_EVENTEXEC(processVarEvent)
980{ /*lint --e{715}*/
981 SCIP_EVENTTYPE eventtype;
982 SCIP_EXPR* expr;
983 SCIP_EXPR_OWNERDATA* ownerdata;
984 SCIP_Bool boundtightened = FALSE;
985
986 eventtype = SCIPeventGetType(event);
988
989 assert(eventdata != NULL);
990 expr = (SCIP_EXPR*) eventdata;
991 assert(SCIPisExprVar(scip, expr));
992
993 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
997
998 ownerdata = SCIPexprGetOwnerData(expr);
999 assert(ownerdata != NULL);
1000 /* we only catch varevents for variables in constraints, so there should be constraints */
1001 assert(ownerdata->nconss > 0);
1002 assert(ownerdata->conss != NULL);
1003
1004 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1005 boundtightened = TRUE;
1006
1007 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1008 * however, if the boundchange is smaller than epsilon, such an event will be omitted
1009 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1010 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1011 * as a boundtightening (and usually it is, I would think)
1012 */
1013 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1014 boundtightened = TRUE;
1015
1016 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1017 * because we will round the bounds and no longer consider relaxing them
1018 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1019 * (mainly to avoid a failing assert, see github issue #70)
1020 * 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
1021 */
1022 if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1023 (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1024 boundtightened = TRUE;
1025
1026 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1027 * - propagation can only find something new if a bound was tightened
1028 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1029 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1030 */
1031 if( boundtightened )
1032 {
1033 SCIP_CONSDATA* consdata;
1034 int c;
1035
1036 for( c = 0; c < ownerdata->nconss; ++c )
1037 {
1038 assert(ownerdata->conss[c] != NULL);
1039 consdata = SCIPconsGetData(ownerdata->conss[c]);
1040
1041 /* if bound tightening, then mark constraints to be propagated again
1042 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1043 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1044 * the locks don't help since they are not available separately for each constraint
1045 */
1046 consdata->ispropagated = FALSE;
1047 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1048
1049 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1051 {
1052 consdata->issimplified = FALSE;
1053 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1054 }
1055 }
1056 }
1057
1058 /* update curboundstag, lastboundrelax, and expr activity */
1059 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1060 {
1061 SCIP_CONSHDLRDATA* conshdlrdata;
1062 SCIP_INTERVAL activity;
1063
1064 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1065 assert(conshdlrdata != NULL);
1066
1067 /* increase tag on bounds */
1068 ++conshdlrdata->curboundstag;
1069 assert(conshdlrdata->curboundstag > 0);
1070
1071 /* remember also if we relaxed bounds now */
1072 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1073 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1074
1075 /* update the activity of the var-expr here immediately
1076 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1077 */
1078 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1079 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1080#ifdef DEBUG_PROP
1081 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1082#endif
1083 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1084 }
1085
1086 return SCIP_OKAY;
1087}
1088
1089/** registers event handler to catch variable events on variable
1090 *
1091 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1092 * When an event occurs, all stored constraints are notified.
1093 */
1094static
1096 SCIP* scip, /**< SCIP data structure */
1097 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1098 SCIP_EXPR* expr, /**< variable expression */
1099 SCIP_CONS* cons /**< nonlinear constraint */
1100 )
1101{
1102 SCIP_EXPR_OWNERDATA* ownerdata;
1103
1104 assert(eventhdlr != NULL);
1105 assert(expr != NULL);
1106 assert(SCIPisExprVar(scip, expr));
1107 assert(cons != NULL);
1108
1109 ownerdata = SCIPexprGetOwnerData(expr);
1110 assert(ownerdata != NULL);
1111
1112#ifndef NDEBUG
1113 /* assert that constraint does not double-catch variable */
1114 {
1115 int i;
1116 for( i = 0; i < ownerdata->nconss; ++i )
1117 assert(ownerdata->conss[i] != cons);
1118 }
1119#endif
1120
1121 /* append cons to ownerdata->conss */
1122 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1123 ownerdata->conss[ownerdata->nconss++] = cons;
1124 /* we're not capturing the constraint here to avoid circular references */
1125
1126 /* updated sorted flag */
1127 if( ownerdata->nconss <= 1 )
1128 ownerdata->consssorted = TRUE;
1129 else if( ownerdata->consssorted )
1130 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1131
1132 /* catch variable events, if not done so yet (first constraint) */
1133 if( ownerdata->filterpos < 0 )
1134 {
1135 SCIP_EVENTTYPE eventtype;
1136
1137 assert(ownerdata->nconss == 1);
1138
1140
1141 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1142 assert(ownerdata->filterpos >= 0);
1143 }
1144
1145 return SCIP_OKAY;
1146}
1147
1148/** catch variable events */
1149static
1151 SCIP* scip, /**< SCIP data structure */
1152 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1153 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1154 )
1155{
1156 SCIP_CONSHDLRDATA* conshdlrdata;
1157 SCIP_CONSDATA* consdata;
1158 SCIP_EXPR* expr;
1159 int i;
1160
1161 assert(eventhdlr != NULL);
1162 assert(cons != NULL);
1163
1164 consdata = SCIPconsGetData(cons);
1165 assert(consdata != NULL);
1166 assert(consdata->varexprs != NULL);
1167 assert(consdata->nvarexprs >= 0);
1168
1169 /* check if we have catched variable events already */
1170 if( consdata->catchedevents )
1171 return SCIP_OKAY;
1172
1173 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1174 assert(conshdlrdata != NULL);
1175#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1176 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1177#endif
1178
1179 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1180
1181 for( i = 0; i < consdata->nvarexprs; ++i )
1182 {
1183 expr = consdata->varexprs[i];
1184
1185 assert(expr != NULL);
1186 assert(SCIPisExprVar(scip, expr));
1187
1188 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1189
1190 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1191 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1192 */
1193 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1194 {
1195 SCIP_INTERVAL activity;
1196 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1197 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1198 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1199#ifdef DEBUG_PROP
1200 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1201#endif
1202 }
1203 }
1204
1205 consdata->catchedevents = TRUE;
1206
1207 return SCIP_OKAY;
1208}
1209
1210/** unregisters event handler to catch variable events on variable
1211 *
1212 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1213 * If this was the last constraint, then the event handler is unregistered for this variable.
1214 */
1215static
1217 SCIP* scip, /**< SCIP data structure */
1218 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1219 SCIP_EXPR* expr, /**< variable expression */
1220 SCIP_CONS* cons /**< expr constraint */
1221 )
1222{
1223 SCIP_EXPR_OWNERDATA* ownerdata;
1224 int pos;
1225
1226 assert(eventhdlr != NULL);
1227 assert(expr != NULL);
1228 assert(SCIPisExprVar(scip, expr));
1229 assert(cons != NULL);
1230
1231 ownerdata = SCIPexprGetOwnerData(expr);
1232 assert(ownerdata != NULL);
1233 assert(ownerdata->nconss > 0);
1234
1235 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1236 {
1237 pos = ownerdata->nconss-1;
1238 }
1239 else
1240 {
1241 if( !ownerdata->consssorted )
1242 {
1243 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1244 ownerdata->consssorted = TRUE;
1245 }
1246
1247 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1248 {
1249 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1250 return SCIP_ERROR;
1251 }
1252 assert(pos >= 0 && pos < ownerdata->nconss);
1253 }
1254 assert(ownerdata->conss[pos] == cons);
1255
1256 /* move last constraint into position of removed constraint */
1257 if( pos < ownerdata->nconss-1 )
1258 {
1259 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1260 ownerdata->consssorted = FALSE;
1261 }
1262 --ownerdata->nconss;
1263
1264 /* drop variable events if that was the last constraint */
1265 if( ownerdata->nconss == 0 )
1266 {
1267 SCIP_EVENTTYPE eventtype;
1268
1269 assert(ownerdata->filterpos >= 0);
1270
1272
1273 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1274 ownerdata->filterpos = -1;
1275 }
1276
1277 return SCIP_OKAY;
1278}
1279
1280/** drop variable events */
1281static
1283 SCIP* scip, /**< SCIP data structure */
1284 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1285 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1286 )
1287{
1288 SCIP_CONSDATA* consdata;
1289 int i;
1290
1291 assert(eventhdlr != NULL);
1292 assert(cons != NULL);
1293
1294 consdata = SCIPconsGetData(cons);
1295 assert(consdata != NULL);
1296
1297 /* check if we have catched variable events already */
1298 if( !consdata->catchedevents )
1299 return SCIP_OKAY;
1300
1301 assert(consdata->varexprs != NULL);
1302 assert(consdata->nvarexprs >= 0);
1303
1304 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1305
1306 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1307 {
1308 assert(consdata->varexprs[i] != NULL);
1309
1310 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1311 }
1312
1313 consdata->catchedevents = FALSE;
1314
1315 return SCIP_OKAY;
1316}
1317
1318/** creates and captures a nonlinear constraint
1319 *
1320 * @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
1321 */
1322static
1324 SCIP* scip, /**< SCIP data structure */
1325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1326 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1327 const char* name, /**< name of constraint */
1328 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1329 SCIP_Real lhs, /**< left hand side of constraint */
1330 SCIP_Real rhs, /**< right hand side of constraint */
1331 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1332 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1333 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1334 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1335 * Usually set to TRUE. */
1336 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1337 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1338 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1339 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1340 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1341 * Usually set to TRUE. */
1342 SCIP_Bool local, /**< is constraint only valid locally?
1343 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1344 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1345 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1346 * adds coefficients to this constraint. */
1347 SCIP_Bool dynamic, /**< is constraint subject to aging?
1348 * Usually set to FALSE. Set to TRUE for own cuts which
1349 * are separated as constraints. */
1350 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1351 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1352 )
1353{
1354 SCIP_CONSHDLRDATA* conshdlrdata;
1355 SCIP_CONSDATA* consdata;
1356
1357 assert(conshdlr != NULL);
1358 assert(expr != NULL);
1359
1360 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1361 assert(conshdlrdata != NULL);
1362
1363 if( local && SCIPgetDepth(scip) != 0 )
1364 {
1365 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1366 return SCIP_INVALIDCALL;
1367 }
1368
1369 /* TODO we should allow for non-initial nonlinear constraints */
1370 if( !initial )
1371 {
1372 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1373 return SCIP_INVALIDCALL;
1374 }
1375
1376 /* create constraint data */
1378
1379 if( copyexpr )
1380 {
1381 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1382 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1383 }
1384 else
1385 {
1386 consdata->expr = expr;
1387 SCIPcaptureExpr(consdata->expr);
1388 }
1389 consdata->lhs = lhs;
1390 consdata->rhs = rhs;
1391 consdata->consindex = conshdlrdata->lastconsindex++;
1392 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1393
1394 /* create constraint */
1395 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1396 local, modifiable, dynamic, removable, FALSE) );
1397
1398 return SCIP_OKAY;
1399}
1400
1401/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1402 *
1403 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1404 * Assume that f(x) is associated with auxiliary variable z.
1405 *
1406 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1407 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1408 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1409 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1410 *
1411 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1412 */
1413static
1415 SCIP* scip, /**< SCIP data structure */
1416 SCIP_EXPR* expr, /**< expression */
1417 SCIP_SOL* sol, /**< solution that has been evaluated */
1418 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1419 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1420 )
1421{
1422 SCIP_EXPR_OWNERDATA* ownerdata;
1423 SCIP_Real auxvarvalue;
1424
1425 assert(expr != NULL);
1426
1427 ownerdata = SCIPexprGetOwnerData(expr);
1428 assert(ownerdata != NULL);
1429 assert(ownerdata->auxvar != NULL);
1430
1431 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1432 {
1433 if( violunder != NULL )
1434 *violunder = TRUE;
1435 if( violover != NULL )
1436 *violover = TRUE;
1437 return SCIPinfinity(scip);
1438 }
1439
1440 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1441
1442 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1443 {
1444 if( violunder != NULL )
1445 *violunder = FALSE;
1446 if( violover != NULL )
1447 *violover = TRUE;
1448 return auxvarvalue - SCIPexprGetEvalValue(expr);
1449 }
1450
1451 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1452 {
1453 if( violunder != NULL )
1454 *violunder = TRUE;
1455 if( violover != NULL )
1456 *violover = FALSE;
1457 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1458 }
1459
1460 if( violunder != NULL )
1461 *violunder = FALSE;
1462 if( violover != NULL )
1463 *violover = FALSE;
1464 return 0.0;
1465}
1466
1467/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1468 *
1469 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1470 * Assume that f(w) is associated with auxiliary variable z.
1471 *
1472 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1473 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1474 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1475 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1476 *
1477 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1478 */
1479static
1481 SCIP* scip, /**< SCIP data structure */
1482 SCIP_EXPR* expr, /**< expression */
1483 SCIP_Real auxvalue, /**< value of f(w) */
1484 SCIP_SOL* sol, /**< solution that has been evaluated */
1485 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1486 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1487 )
1488{
1489 SCIP_EXPR_OWNERDATA* ownerdata;
1490 SCIP_Real auxvarvalue;
1491
1492 assert(expr != NULL);
1493
1494 ownerdata = SCIPexprGetOwnerData(expr);
1495 assert(ownerdata != NULL);
1496 assert(ownerdata->auxvar != NULL);
1497
1498 if( auxvalue == SCIP_INVALID )
1499 {
1500 if( violunder != NULL )
1501 *violunder = TRUE;
1502 if( violover != NULL )
1503 *violover = TRUE;
1504 return SCIPinfinity(scip);
1505 }
1506
1507 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1508
1509 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1510 {
1511 if( violunder != NULL )
1512 *violunder = FALSE;
1513 if( violover != NULL )
1514 *violover = TRUE;
1515 return auxvarvalue - auxvalue;
1516 }
1517
1518 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1519 {
1520 if( violunder != NULL )
1521 *violunder = TRUE;
1522 if( violover != NULL )
1523 *violover = FALSE;
1524 return auxvalue - auxvarvalue;
1525 }
1526
1527 if( violunder != NULL )
1528 *violunder = FALSE;
1529 if( violover != NULL )
1530 *violover = FALSE;
1531
1532 return 0.0;
1533}
1534
1535/** computes violation of a constraint */
1536static
1538 SCIP* scip, /**< SCIP data structure */
1539 SCIP_CONS* cons, /**< constraint */
1540 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1541 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1542 )
1543{
1544 SCIP_CONSDATA* consdata;
1545 SCIP_Real activity;
1546
1547 assert(scip != NULL);
1548 assert(cons != NULL);
1549
1550 consdata = SCIPconsGetData(cons);
1551 assert(consdata != NULL);
1552
1553 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1554 activity = SCIPexprGetEvalValue(consdata->expr);
1555
1556 /* consider constraint as violated if it is undefined in the current point */
1557 if( activity == SCIP_INVALID )
1558 {
1559 consdata->lhsviol = SCIPinfinity(scip);
1560 consdata->rhsviol = SCIPinfinity(scip);
1561 return SCIP_OKAY;
1562 }
1563
1564 /* compute violations */
1565 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1566 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1567
1568 return SCIP_OKAY;
1569}
1570
1571/** returns absolute violation of a constraint
1572 *
1573 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1574 */
1575static
1577 SCIP_CONS* cons /**< constraint */
1578 )
1579{
1580 SCIP_CONSDATA* consdata;
1581
1582 assert(cons != NULL);
1583
1584 consdata = SCIPconsGetData(cons);
1585 assert(consdata != NULL);
1586
1587 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1588}
1589
1590/** computes relative violation of a constraint
1591 *
1592 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1593 */
1594static
1596 SCIP* scip, /**< SCIP data structure */
1597 SCIP_CONS* cons, /**< constraint */
1598 SCIP_Real* viol, /**< buffer to store violation */
1599 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1600 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1601 )
1602{
1603 SCIP_CONSHDLR* conshdlr;
1604 SCIP_CONSHDLRDATA* conshdlrdata;
1605 SCIP_CONSDATA* consdata;
1606 SCIP_Real scale;
1607
1608 assert(cons != NULL);
1609 assert(viol != NULL);
1610
1611 conshdlr = SCIPconsGetHdlr(cons);
1612 assert(conshdlr != NULL);
1613
1614 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1615 assert(conshdlrdata != NULL);
1616
1617 *viol = getConsAbsViolation(cons);
1618
1619 if( conshdlrdata->violscale == 'n' )
1620 return SCIP_OKAY;
1621
1622 if( SCIPisInfinity(scip, *viol) )
1623 return SCIP_OKAY;
1624
1625 consdata = SCIPconsGetData(cons);
1626 assert(consdata != NULL);
1627
1628 if( conshdlrdata->violscale == 'a' )
1629 {
1630 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1631
1632 /* consider value of side that is violated for scaling, too */
1633 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1634 {
1635 assert(!SCIPisInfinity(scip, -consdata->lhs));
1636 scale = REALABS(consdata->lhs);
1637 }
1638 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1639 {
1640 assert(!SCIPisInfinity(scip, consdata->rhs));
1641 scale = REALABS(consdata->rhs);
1642 }
1643
1644 *viol /= scale;
1645 return SCIP_OKAY;
1646 }
1647
1648 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1649 assert(conshdlrdata->violscale == 'g');
1650 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1651 {
1652 /* we need the varexprs to conveniently access the gradient */
1653 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1654
1655 /* update cached value of norm of gradient */
1656 consdata->gradnorm = 0.0;
1657
1658 /* compute gradient */
1659 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1660
1661 /* gradient evaluation error -> no scaling */
1662 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1663 {
1664 int i;
1665 for( i = 0; i < consdata->nvarexprs; ++i )
1666 {
1667 SCIP_Real deriv;
1668
1669 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1670 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1671 if( deriv == SCIP_INVALID )
1672 {
1673 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1674 consdata->gradnorm = 0.0;
1675 break;
1676 }
1677
1678 consdata->gradnorm += deriv*deriv;
1679 }
1680 }
1681 consdata->gradnorm = sqrt(consdata->gradnorm);
1682 consdata->gradnormsoltag = soltag;
1683 }
1684
1685 *viol /= MAX(1.0, consdata->gradnorm);
1686
1687 return SCIP_OKAY;
1688}
1689
1690/** returns whether constraint is currently violated
1691 *
1692 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1693 */
1694static
1696 SCIP* scip, /**< SCIP data structure */
1697 SCIP_CONS* cons /**< constraint */
1698 )
1699{
1700 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1701}
1702
1703/** checks for a linear variable that can be increased or decreased without harming feasibility */
1704static
1706 SCIP* scip, /**< SCIP data structure */
1707 SCIP_CONS* cons /**< constraint */
1708 )
1709{
1710 SCIP_CONSDATA* consdata;
1711 int poslock;
1712 int neglock;
1713 int i;
1714
1715 assert(cons != NULL);
1716
1717 consdata = SCIPconsGetData(cons);
1718 assert(consdata != NULL);
1719
1720 consdata->linvarincr = NULL;
1721 consdata->linvardecr = NULL;
1722 consdata->linvarincrcoef = 0.0;
1723 consdata->linvardecrcoef = 0.0;
1724
1725 /* root expression is not a sum -> no unlocked linear variable available */
1726 if( !SCIPisExprSum(scip, consdata->expr) )
1727 return;
1728
1729 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1730 {
1731 SCIP_EXPR* child;
1732
1733 child = SCIPexprGetChildren(consdata->expr)[i];
1734 assert(child != NULL);
1735
1736 /* check whether the child is a variable expression */
1737 if( SCIPisExprVar(scip, child) )
1738 {
1739 SCIP_VAR* var = SCIPgetVarExprVar(child);
1740 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1741
1742 if( coef > 0.0 )
1743 {
1744 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1745 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1746 }
1747 else
1748 {
1749 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1750 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1751 }
1753
1754 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1755 {
1756 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1757 * if we have already one candidate, then take the one where the loss in the objective function is less
1758 */
1759 if( (consdata->linvardecr == NULL) ||
1760 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1761 {
1762 consdata->linvardecr = var;
1763 consdata->linvardecrcoef = coef;
1764 }
1765 }
1766
1767 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1768 {
1769 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1770 * if we have already one candidate, then take the one where the loss in the objective function is less
1771 */
1772 if( (consdata->linvarincr == NULL) ||
1773 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1774 {
1775 consdata->linvarincr = var;
1776 consdata->linvarincrcoef = coef;
1777 }
1778 }
1779 }
1780 }
1781
1782 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1783 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1784
1785 if( consdata->linvarincr != NULL )
1786 {
1787 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1788 }
1789 if( consdata->linvardecr != NULL )
1790 {
1791 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1792 }
1793}
1794
1795/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1796 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1797 *
1798 * The method assumes that this is always possible and that not all constraints are feasible already.
1799 */
1800static
1802 SCIP* scip, /**< SCIP data structure */
1803 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1804 SCIP_CONS** conss, /**< constraints to process */
1805 int nconss, /**< number of constraints */
1806 SCIP_SOL* sol, /**< solution to process */
1807 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1808 )
1809{
1810 SCIP_CONSHDLRDATA* conshdlrdata;
1811 SCIP_SOL* newsol;
1812 int c;
1813
1814 assert(scip != NULL);
1815 assert(conshdlr != NULL);
1816 assert(conss != NULL || nconss == 0);
1817 assert(success != NULL);
1818
1819 *success = FALSE;
1820
1821 /* don't propose new solutions if not in presolve or solving */
1823 return SCIP_OKAY;
1824
1825 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1826 assert(conshdlrdata != NULL);
1827
1828 if( sol != NULL )
1829 {
1830 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1831 }
1832 else
1833 {
1834 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1835 }
1836 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1837 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1838 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1839
1840 for( c = 0; c < nconss; ++c )
1841 {
1842 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1843 SCIP_Real viol = 0.0;
1844 SCIP_Real delta;
1845 SCIP_Real gap;
1846
1847 assert(consdata != NULL);
1848
1849 /* get absolute violation and sign */
1850 if( consdata->lhsviol > SCIPfeastol(scip) )
1851 viol = consdata->lhsviol; /* lhs - activity */
1852 else if( consdata->rhsviol > SCIPfeastol(scip) )
1853 viol = -consdata->rhsviol; /* rhs - activity */
1854 else
1855 continue; /* constraint is satisfied */
1856
1857 if( consdata->linvarincr != NULL &&
1858 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1859 {
1860 SCIP_VAR* var = consdata->linvarincr;
1861
1862 /* compute how much we would like to increase var */
1863 delta = viol / consdata->linvarincrcoef;
1864 assert(delta > 0.0);
1865
1866 /* if var has an upper bound, may need to reduce delta */
1868 {
1869 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1870 delta = MIN(MAX(0.0, gap), delta);
1871 }
1872 if( SCIPisPositive(scip, delta) )
1873 {
1874 /* if variable is integral, round delta up so that it will still have an integer value */
1875 if( SCIPvarIsIntegral(var) )
1876 delta = SCIPceil(scip, delta);
1877
1878 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1879 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1880 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1881
1882 /* adjust constraint violation, if satisfied go on to next constraint */
1883 viol -= consdata->linvarincrcoef * delta;
1884 if( SCIPisZero(scip, viol) )
1885 continue;
1886 }
1887 }
1888
1889 assert(viol != 0.0);
1890 if( consdata->linvardecr != NULL &&
1891 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1892 {
1893 SCIP_VAR* var = consdata->linvardecr;
1894
1895 /* compute how much we would like to decrease var */
1896 delta = viol / consdata->linvardecrcoef;
1897 assert(delta < 0.0);
1898
1899 /* if var has a lower bound, may need to reduce delta */
1901 {
1902 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1903 delta = MAX(MIN(0.0, gap), delta);
1904 }
1905 if( SCIPisNegative(scip, delta) )
1906 {
1907 /* if variable is integral, round delta down so that it will still have an integer value */
1908 if( SCIPvarIsIntegral(var) )
1909 delta = SCIPfloor(scip, delta);
1910 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1911 /*lint --e{613} */
1912 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1913 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1914
1915 /* adjust constraint violation, if satisfied go on to next constraint */
1916 viol -= consdata->linvardecrcoef * delta;
1917 if( SCIPisZero(scip, viol) )
1918 continue;
1919 }
1920 }
1921
1922 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1923 break;
1924 }
1925
1926 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1927 * then pass it to the trysol heuristic
1928 */
1930 {
1931 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1932
1933 assert(conshdlrdata->trysolheur != NULL);
1934 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1935
1936 *success = TRUE;
1937 }
1938
1939 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1940
1941 return SCIP_OKAY;
1942}
1943
1944/** notify nonlinear handlers to add linearization in new solution that has been found
1945 *
1946 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1947 *
1948 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1949 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1950 * cut that is valid and supporting in the given solution.
1951 * For example, for convex constraints, we achieve this by linearizing.
1952 * For SOC, we also linearize, but on a a convex reformulation.
1953 *
1954 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1955 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1956 */
1957static
1959 SCIP* scip, /**< SCIP data structure */
1960 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1961 SCIP_CONS** conss, /**< constraints */
1962 int nconss, /**< number of constraints */
1963 SCIP_SOL* sol, /**< reference point where to estimate */
1964 SCIP_Bool solisbest /**< whether solution is best */
1965 )
1966{
1967 SCIP_CONSDATA* consdata;
1968 SCIP_Longint soltag;
1969 SCIP_EXPRITER* it;
1970 SCIP_EXPR* expr;
1971 int c, e;
1972
1973 assert(scip != NULL);
1974 assert(conshdlr != NULL);
1975 assert(conss != NULL || nconss == 0);
1976
1977 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1978
1979 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1980 * would be nice to recognize this and skip reevaluating
1981 */
1982 soltag = SCIPgetExprNewSoltag(scip);
1983
1987
1988 for( c = 0; c < nconss; ++c )
1989 {
1990 /* skip constraints that are not enabled or deleted or have separation disabled */
1991 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
1992 continue;
1993 assert(SCIPconsIsActive(conss[c]));
1994
1995 consdata = SCIPconsGetData(conss[c]);
1996 assert(consdata != NULL);
1997
1998 ENFOLOG(
1999 {
2000 int i;
2001 SCIPinfoMessage(scip, enfologfile, " constraint ");
2002 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2003 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2004 for( i = 0; i < consdata->nvarexprs; ++i )
2005 {
2006 SCIP_VAR* var;
2007 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2008 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2010 }
2011 })
2012
2013 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2014 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2015
2016 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2017 {
2018 SCIP_EXPR_OWNERDATA* ownerdata;
2019
2020 ownerdata = SCIPexprGetOwnerData(expr);
2021 assert(ownerdata != NULL);
2022
2023 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2024 assert(SCIPexprGetEvalTag(expr) == soltag);
2026 if( ownerdata->auxvar != NULL )
2027 {
2028 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2029 }
2030
2031 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2032 for( e = 0; e < ownerdata->nenfos; ++e )
2033 {
2034 /* call sollinearize callback, if implemented by nlhdlr */
2035 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2036 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2037 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2038 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2039 }
2040 }
2041 }
2042
2043 SCIPfreeExpriter(&it);
2044
2045 return SCIP_OKAY;
2046}
2047
2048/** processes the event that a new primal solution has been found */
2049static
2050SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2051{
2052 SCIP_CONSHDLR* conshdlr;
2053 SCIP_CONSHDLRDATA* conshdlrdata;
2054 SCIP_SOL* sol;
2055
2056 assert(scip != NULL);
2057 assert(event != NULL);
2058 assert(eventdata != NULL);
2059 assert(eventhdlr != NULL);
2061
2062 conshdlr = (SCIP_CONSHDLR*)eventdata;
2063
2064 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2065 return SCIP_OKAY;
2066
2067 sol = SCIPeventGetSol(event);
2068 assert(sol != NULL);
2069
2070 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2071 assert(conshdlrdata != NULL);
2072
2073 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2074 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2075 * from the tree, but postprocessed via proposeFeasibleSolution
2076 */
2077 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2078 return SCIP_OKAY;
2079
2080 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2081
2083
2084 return SCIP_OKAY;
2085}
2086
2087/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2088 *
2089 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2090 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2091 *
2092 * Nothing will happen if SCIP is not in presolve or solve.
2093 */
2094static
2096 SCIP* scip, /**< SCIP data structure */
2097 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2098 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2099 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2100 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2101 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2102 )
2103{
2104 SCIP_VAR* var;
2105 SCIP_Bool tightenedlb;
2106 SCIP_Bool tightenedub;
2107 SCIP_Bool force;
2108
2109 assert(scip != NULL);
2110 assert(conshdlr != NULL);
2111 assert(expr != NULL);
2112 assert(cutoff != NULL);
2113
2114 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2116
2117 *cutoff = FALSE;
2118
2120 if( var == NULL )
2121 return SCIP_OKAY;
2122
2123 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2124 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2125
2126 /* try to tighten lower bound of (auxiliary) variable */
2127 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2128 if( tightenedlb )
2129 {
2130 if( ntightenings != NULL )
2131 ++*ntightenings;
2132 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2133 }
2134 if( *cutoff )
2135 {
2136 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2137 return SCIP_OKAY;
2138 }
2139
2140 /* try to tighten upper bound of (auxiliary) variable */
2141 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2142 if( tightenedub )
2143 {
2144 if( ntightenings != NULL )
2145 ++*ntightenings;
2146 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2147 }
2148 if( *cutoff )
2149 {
2150 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2151 return SCIP_OKAY;
2152 }
2153
2154 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2155 * that seems unnecessary and we could easily undo this here, e.g.,
2156 * if( tightenedlb ) expr->activity.inf = bounds.inf
2157 */
2158
2159 return SCIP_OKAY;
2160}
2161
2162/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2163 * and tries to tighten the bounds of the auxiliary variables accordingly
2164 */
2165static
2167 SCIP* scip, /**< SCIP data structure */
2168 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2169 SCIP_EXPR* rootexpr, /**< expression */
2170 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2171 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2172 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2173 )
2174{
2175 SCIP_EXPRITER* it;
2176 SCIP_EXPR* expr;
2177 SCIP_EXPR_OWNERDATA* ownerdata;
2178 SCIP_CONSHDLRDATA* conshdlrdata;
2179
2180 assert(scip != NULL);
2181 assert(rootexpr != NULL);
2182
2183 if( infeasible != NULL )
2184 *infeasible = FALSE;
2185 if( ntightenings != NULL )
2186 *ntightenings = 0;
2187
2188 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2189 assert(conshdlrdata != NULL);
2190
2191 /* if value is valid and empty, then we cannot improve, so do nothing */
2192 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2193 {
2194 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2195
2196 if( infeasible != NULL )
2197 *infeasible = TRUE;
2198
2199 /* just update tag to curboundstag */
2200 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2201
2202 return SCIP_OKAY;
2203 }
2204
2205 /* if value is up-to-date, then nothing to do */
2206 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2207 {
2208 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2209
2210 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2211
2212 return SCIP_OKAY;
2213 }
2214
2215 ownerdata = SCIPexprGetOwnerData(rootexpr);
2216 assert(ownerdata != NULL);
2217
2218 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2219 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2220 * during detect, we are in some in-between state where we may want to eval activity
2221 * on exprs that we did not notify about their activity usage
2222 */
2223 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2224 {
2225#ifdef DEBUG_PROP
2226 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2227#endif
2228 SCIPABORT();
2229 return SCIP_OKAY;
2230 }
2231
2235
2236 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2237 {
2238 switch( SCIPexpriterGetStageDFS(it) )
2239 {
2241 {
2242 /* skip child if it has been evaluated already */
2243 SCIP_EXPR* child;
2244
2245 child = SCIPexpriterGetChildExprDFS(it);
2246 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2247 {
2249 *infeasible = TRUE;
2250
2251 expr = SCIPexpriterSkipDFS(it);
2252 continue;
2253 }
2254
2255 break;
2256 }
2257
2259 {
2260 SCIP_INTERVAL activity;
2261
2262 /* we should not have entered this expression if its activity was already up to date */
2263 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2264
2265 ownerdata = SCIPexprGetOwnerData(expr);
2266 assert(ownerdata != NULL);
2267
2268 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2269 * so we can assume that the activity is up to date for all these variables
2270 * UNLESS we changed the method used to evaluate activity of variable expressions
2271 * or we currently use global bounds (varevents are catched for local bound changes only)
2272 */
2273 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2274 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2275 {
2276#ifndef NDEBUG
2277 SCIP_INTERVAL exprhdlrinterval;
2278
2279 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2280 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2281 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2282#endif
2283#ifdef DEBUG_PROP
2284 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2285#endif
2286 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2287
2288 break;
2289 }
2290
2291 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2292 {
2293 /* start with entire activity if current one is invalid */
2295 }
2297 {
2298 /* If already empty, then don't try to compute even better activity.
2299 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2300 * so an assert(infeasible == NULL || *infeasible) should work here.
2301 * However, after reporting a cutoff due to expr->activity being empty,
2302 * SCIP may wander to a different node and call propagation again.
2303 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2304 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2305 * we will still have expr->activity being empty, but will have forgotten
2306 * that we found infeasibility here before (!2221#note_134120).
2307 * Therefore we just set *infeasibility=TRUE here and stop.
2308 */
2309 if( infeasible != NULL )
2310 *infeasible = TRUE;
2311 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2312 break;
2313 }
2314 else
2315 {
2316 /* start with current activity, since it is valid */
2317 activity = SCIPexprGetActivity(expr);
2318 }
2319
2320 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2321 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2322 {
2323#ifdef DEBUG_PROP
2324 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2325#endif
2326 break;
2327 }
2328
2329#ifdef DEBUG_PROP
2330 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2331 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2332 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2333#endif
2334
2335 /* run interval eval of nonlinear handlers or expression handler */
2336 if( ownerdata->nenfos > 0 )
2337 {
2338 SCIP_NLHDLR* nlhdlr;
2339 SCIP_INTERVAL nlhdlrinterval;
2340 int e;
2341
2342 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2343 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2344 {
2345 /* skip nlhdlr if it does not want to participate in activity computation */
2346 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2347 continue;
2348
2349 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2350 assert(nlhdlr != NULL);
2351
2352 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2353 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2354 continue;
2355
2356 /* let nlhdlr evaluate current expression */
2357 nlhdlrinterval = activity;
2358 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2359 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2360#ifdef DEBUG_PROP
2361 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2362#endif
2363
2364 /* update activity by intersecting with computed activity */
2365 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2366#ifdef DEBUG_PROP
2367 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2368#endif
2369 }
2370 }
2371 else
2372 {
2373 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2374 SCIP_INTERVAL exprhdlrinterval = activity;
2375 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2376#ifdef DEBUG_PROP
2377 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2378#endif
2379
2380 /* update expr->activity by intersecting with computed activity */
2381 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2382#ifdef DEBUG_PROP
2383 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2384#endif
2385 }
2386
2387 /* if expression is integral, then we try to tighten the interval bounds a bit
2388 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2389 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2390 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2391 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2392 * (constants should be ok, too)
2393 */
2394 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2395 {
2396 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2397 activity.inf = SCIPceil(scip, activity.inf);
2398 if( activity.sup < SCIP_INTERVAL_INFINITY )
2399 activity.sup = SCIPfloor(scip, activity.sup);
2400#ifdef DEBUG_PROP
2401 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2402#endif
2403 }
2404
2405 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2406 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2407 */
2408 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2409 {
2410 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2411 SCIPintervalSetEmpty(&activity);
2412 }
2413
2414 /* now finally store activity in expr */
2415 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2416
2418 {
2419 if( infeasible != NULL )
2420 *infeasible = TRUE;
2421 }
2422 else if( tightenauxvars && ownerdata->auxvar != NULL )
2423 {
2424 SCIP_Bool tighteninfeasible;
2425
2426 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2427 if( tighteninfeasible )
2428 {
2429 if( infeasible != NULL )
2430 *infeasible = TRUE;
2431 SCIPintervalSetEmpty(&activity);
2432 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2433 }
2434 }
2435
2436 break;
2437 }
2438
2439 default:
2440 /* you should never be here */
2441 SCIPerrorMessage("unexpected iterator stage\n");
2442 SCIPABORT();
2443 break;
2444 }
2445
2446 expr = SCIPexpriterGetNext(it);
2447 }
2448
2449 SCIPfreeExpriter(&it);
2450
2451 return SCIP_OKAY;
2452}
2453
2454/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2455 *
2456 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2457 *
2458 * If `subsetsufficient` is FALSE, then we require
2459 * - a change from an unbounded interval to a bounded one, or
2460 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2461 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2462 */
2463static
2465 SCIP* scip, /**< SCIP data structure */
2466 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2467 SCIP_INTERVAL newinterval, /**< new interval */
2468 SCIP_INTERVAL oldinterval /**< old interval */
2469 )
2470{
2471 assert(scip != NULL);
2474
2475 if( subsetsufficient )
2476 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2477 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2478
2479 /* check whether lower bound of interval becomes finite */
2480 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2481 return TRUE;
2482
2483 /* check whether upper bound of interval becomes finite */
2484 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2485 return TRUE;
2486
2487 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2488 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2489 return TRUE;
2490
2491 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2492 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2493 return TRUE;
2494
2495 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2496 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2497 return TRUE;
2498
2499 return FALSE;
2500}
2501
2502/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2503 *
2504 * The expression will be traversed in breadth first search by using this queue.
2505 *
2506 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2507 * forwardPropExpr() before calling this function.
2508 *
2509 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2510 */
2511static
2513 SCIP* scip, /**< SCIP data structure */
2514 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2515 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2516 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2517 )
2518{
2519 SCIP_CONSHDLRDATA* conshdlrdata;
2520 SCIP_EXPR* expr;
2521 SCIP_EXPR_OWNERDATA* ownerdata;
2522
2523 assert(infeasible != NULL);
2524 assert(ntightenings != NULL);
2525
2526 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2527 assert(conshdlrdata != NULL);
2528
2529 *ntightenings = 0;
2530
2531 /* main loop that calls reverse propagation for expressions on the queue
2532 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2533 */
2534 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2535 {
2536 SCIP_INTERVAL propbounds;
2537 int e;
2538
2539 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2540 assert(expr != NULL);
2541
2542 ownerdata = SCIPexprGetOwnerData(expr);
2543 assert(ownerdata != NULL);
2544
2545 assert(ownerdata->inpropqueue);
2546 /* mark that the expression is not in the queue anymore */
2547 ownerdata->inpropqueue = FALSE;
2548
2549 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2550 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2551 */
2552 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2553 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2554 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2555
2556 /* this intersects propbounds with activity and auxvar bounds
2557 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2558 * auxvar bounds separately, so disabling this for now
2559 */
2560#ifdef SCIP_DISABLED_CODE
2561 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2563 {
2564 *infeasible = TRUE;
2565 break;
2566 }
2567#else
2568 propbounds = ownerdata->propbounds;
2569#endif
2570
2571 if( ownerdata->nenfos > 0 )
2572 {
2573 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2574 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2575 {
2576 SCIP_NLHDLR* nlhdlr;
2577 int nreds;
2578
2579 /* skip nlhdlr if it does not want to participate in activity computation */
2580 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2581 continue;
2582
2583 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2584 assert(nlhdlr != NULL);
2585
2586 /* call the reverseprop of the nlhdlr */
2587#ifdef SCIP_DEBUG
2588 SCIPdebugMsg(scip, "call reverse propagation for ");
2589 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2590 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2591#endif
2592
2593 nreds = 0;
2594 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2595 assert(nreds >= 0);
2596 *ntightenings += nreds;
2597 }
2598 }
2600 {
2601 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2602 SCIP_INTERVAL* childrenbounds;
2603 int c;
2604
2605#ifdef SCIP_DEBUG
2606 SCIPdebugMsg(scip, "call reverse propagation for ");
2607 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2608 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2609#endif
2610
2611 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2612 * been initialized in detectNlhdlr yet (nenfos < 0)
2613 */
2614 assert(ownerdata->nenfos < 0);
2615
2616 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2617 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2618 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2619
2620 /* call the reverseprop of the exprhdlr */
2621 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2622
2623 if( !*infeasible )
2624 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2625 {
2626 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2627 }
2628
2629 SCIPfreeBufferArray(scip, &childrenbounds);
2630 }
2631 }
2632
2633 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2634 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2635 {
2636 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2637 assert(expr != NULL);
2638
2639 ownerdata = SCIPexprGetOwnerData(expr);
2640 assert(ownerdata != NULL);
2641
2642 /* mark that the expression is not in the queue anymore */
2643 ownerdata->inpropqueue = FALSE;
2644 }
2645
2646 return SCIP_OKAY;
2647}
2648
2649/** calls domain propagation for a given set of constraints
2650 *
2651 * The algorithm alternates calls of forward and reverse propagation.
2652 * Forward propagation ensures that activity of expressions is up to date.
2653 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2654 * [lhs,rhs] interval as starting point.
2655 *
2656 * The propagation algorithm works as follows:
2657 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2658 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2659 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2660 * provide tighter bounds
2661 * 3. apply reverse propagation to all collected expressions; don't explore
2662 * sub-expressions which have not changed since the beginning of the propagation loop
2663 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2664 *
2665 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2666 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2667 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2668 *
2669 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2670 * e.g., try less to propagate on convex constraints?
2671 */
2672static
2674 SCIP* scip, /**< SCIP data structure */
2675 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2676 SCIP_CONS** conss, /**< constraints to propagate */
2677 int nconss, /**< total number of constraints */
2678 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2679 SCIP_RESULT* result, /**< pointer to store the result */
2680 int* nchgbds /**< buffer to add the number of changed bounds */
2681 )
2682{
2683 SCIP_CONSHDLRDATA* conshdlrdata;
2684 SCIP_CONSDATA* consdata;
2685 SCIP_EXPR_OWNERDATA* ownerdata;
2686 SCIP_Bool cutoff = FALSE;
2687 SCIP_INTERVAL conssides;
2688 int ntightenings;
2689 int roundnr;
2690 SCIP_EXPRITER* revpropcollectit = NULL;
2691 int i;
2692
2693 assert(scip != NULL);
2694 assert(conshdlr != NULL);
2695 assert(conss != NULL);
2696 assert(nconss >= 0);
2697 assert(result != NULL);
2698 assert(nchgbds != NULL);
2699 assert(*nchgbds >= 0);
2700
2701 /* no constraints to propagate */
2702 if( nconss == 0 )
2703 {
2705 return SCIP_OKAY;
2706 }
2707
2708 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2709 assert(conshdlrdata != NULL);
2710#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2711 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2712#endif
2713 assert(!conshdlrdata->globalbounds);
2714
2716 roundnr = 0;
2717
2718 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2719 conshdlrdata->forceboundtightening = force;
2720
2721 /* invalidate all propbounds (probably not needed) */
2722 ++conshdlrdata->curpropboundstag;
2723
2724 /* create iterator that we will use if we need to look at all auxvars */
2725 if( conshdlrdata->propauxvars )
2726 {
2727 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2728 }
2729
2730 /* main propagation loop */
2731 do
2732 {
2733 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2734
2735 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2736
2737 /* apply forward propagation (update expression activities)
2738 * and add promising root expressions into queue for reversepropagation
2739 */
2740 for( i = 0; i < nconss; ++i )
2741 {
2742 consdata = SCIPconsGetData(conss[i]);
2743 assert(consdata != NULL);
2744
2745 /* skip deleted, non-active, or propagation-disabled constraints */
2746 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2747 continue;
2748
2749 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2750 * activity didn't change
2751 */
2752 if( consdata->ispropagated )
2753 continue;
2754
2755 /* update activities in expression */
2756 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2757 SCIPdebugPrintCons(scip, conss[i], NULL);
2758
2759 ntightenings = 0;
2760 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2762
2763 if( cutoff )
2764 {
2765 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2767 break;
2768 }
2769
2770 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2771
2772 /* 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 */
2773 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2774 {
2775 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2776 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2777 * so taking auxvar bounds is enough)
2778 */
2779 if( ownerdata->auxvar == NULL )
2780 {
2781 /* relax sides by SCIPepsilon() and handle infinite sides */
2782 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2783 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2784 SCIPintervalSetBounds(&conssides, lhs, rhs);
2785 }
2786 else
2787 {
2788 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2789 }
2790 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2791 }
2792 else
2793 {
2794 /* check whether bounds of any auxvar used in constraint provides a tightening
2795 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2796 * but skip exprs that have an auxvar, but do not participate in propagation
2797 */
2798 SCIP_EXPR* expr;
2799
2800 assert(revpropcollectit != NULL);
2801 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2802 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2803 {
2804 ownerdata = SCIPexprGetOwnerData(expr);
2805 assert(ownerdata != NULL);
2806
2807 if( ownerdata->auxvar == NULL )
2808 continue;
2809
2810 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2811 continue;
2812
2813 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2814 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2815 }
2816 }
2817
2818 if( cutoff )
2819 {
2820 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2822 break;
2823 }
2824
2825 assert(ntightenings >= 0);
2826 if( ntightenings > 0 )
2827 {
2828 *nchgbds += ntightenings;
2830 }
2831
2832 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2833 consdata->ispropagated = TRUE;
2834 }
2835
2836 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2837 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2838 assert(ntightenings >= 0);
2839 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2840
2841 if( cutoff )
2842 {
2843 SCIPdebugMsg(scip, " -> cutoff\n");
2845 break;
2846 }
2847
2848 if( ntightenings > 0 )
2849 {
2850 *nchgbds += ntightenings;
2852 }
2853 }
2854 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2855
2856 if( conshdlrdata->propauxvars )
2857 {
2858 SCIPfreeExpriter(&revpropcollectit);
2859 }
2860
2861 conshdlrdata->forceboundtightening = FALSE;
2862
2863 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2864 ++conshdlrdata->curpropboundstag;
2865
2866 return SCIP_OKAY;
2867}
2868
2869/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2870 *
2871 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2872 *
2873 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2874 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2875 */
2876static
2878 SCIP* scip, /**< SCIP data structure */
2879 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2880 SCIP_CONS** conss, /**< constraints to propagate */
2881 int nconss, /**< total number of constraints */
2882 SCIP_RESULT* result, /**< pointer to store the result */
2883 int* nchgbds /**< buffer to add the number of changed bounds */
2884 )
2885{
2886 SCIP_CONSDATA* consdata;
2887 SCIP_EXPRITER* it;
2888 SCIP_EXPR* expr;
2889 SCIP_EXPR_OWNERDATA* ownerdata;
2890 SCIP_Bool cutoff = FALSE;
2891 int ntightenings;
2892 int c;
2893 int e;
2894
2895 assert(scip != NULL);
2896 assert(conshdlr != NULL);
2897 assert(conss != NULL);
2898 assert(nconss >= 0);
2899 assert(result != NULL);
2900 assert(nchgbds != NULL);
2901 assert(*nchgbds >= 0);
2902
2903#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2904 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2905#endif
2906 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2907 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2908
2910
2913
2914 for( c = 0; c < nconss && !cutoff; ++c )
2915 {
2916 /* skip deleted, non-active, or propagation-disabled constraints */
2917 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2918 continue;
2919
2920 consdata = SCIPconsGetData(conss[c]);
2921 assert(consdata != NULL);
2922
2923 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2924 {
2925 ownerdata = SCIPexprGetOwnerData(expr);
2926 assert(ownerdata != NULL);
2927
2928 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2929 * this will propagate the current activity
2930 */
2931 for( e = 0; e < ownerdata->nenfos; ++e )
2932 {
2933 SCIP_NLHDLR* nlhdlr;
2934 assert(ownerdata->enfos[e] != NULL);
2935
2936 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2937 assert(nlhdlr != NULL);
2938 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2939 continue;
2940
2941 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2942 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2943 ntightenings = 0;
2944 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2945 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2946
2947 if( cutoff )
2948 {
2949 /* stop everything if we detected infeasibility */
2950 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2952 break;
2953 }
2954
2955 assert(ntightenings >= 0);
2956 if( ntightenings > 0 )
2957 {
2958 *nchgbds += ntightenings;
2960 }
2961 }
2962 }
2963 }
2964
2965 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2966 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2967 assert(ntightenings >= 0);
2968
2969 if( cutoff )
2970 {
2971 SCIPdebugMsg(scip, " -> cutoff\n");
2973 }
2974 else if( ntightenings > 0 )
2975 {
2976 *nchgbds += ntightenings;
2978 }
2979
2980 SCIPfreeExpriter(&it);
2981
2982 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2983 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2984
2985 return SCIP_OKAY;
2986}
2987
2988/** propagates variable locks through expression and adds locks to variables */
2989static
2991 SCIP* scip, /**< SCIP data structure */
2992 SCIP_EXPR* expr, /**< expression */
2993 int nlockspos, /**< number of positive locks */
2994 int nlocksneg /**< number of negative locks */
2995 )
2996{
2997 SCIP_EXPR_OWNERDATA* ownerdata;
2998 SCIP_EXPRITER* it;
2999 SCIP_EXPRITER_USERDATA ituserdata;
3000
3001 assert(expr != NULL);
3002
3003 /* if no locks, then nothing to propagate */
3004 if( nlockspos == 0 && nlocksneg == 0 )
3005 return SCIP_OKAY;
3006
3010 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3011
3012 /* store locks in root node */
3013 ituserdata.intvals[0] = nlockspos;
3014 ituserdata.intvals[1] = nlocksneg;
3015 SCIPexpriterSetCurrentUserData(it, ituserdata);
3016
3017 while( !SCIPexpriterIsEnd(it) )
3018 {
3019 /* collect locks */
3020 ituserdata = SCIPexpriterGetCurrentUserData(it);
3021 nlockspos = ituserdata.intvals[0];
3022 nlocksneg = ituserdata.intvals[1];
3023
3024 ownerdata = SCIPexprGetOwnerData(expr);
3025
3026 switch( SCIPexpriterGetStageDFS(it) )
3027 {
3029 {
3030 if( SCIPisExprVar(scip, expr) )
3031 {
3032 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3033 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3034 }
3035
3036 /* add locks to expression */
3037 ownerdata->nlockspos += nlockspos;
3038 ownerdata->nlocksneg += nlocksneg;
3039
3040 /* add monotonicity information if expression has been locked for the first time */
3041 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3043 {
3044 int i;
3045
3046 assert(ownerdata->monotonicity == NULL);
3047 assert(ownerdata->monotonicitysize == 0);
3048
3049 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3050 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3051
3052 /* store the monotonicity for each child */
3053 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3054 {
3055 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3056 }
3057 }
3058 break;
3059 }
3060
3062 {
3063 /* remove monotonicity information if expression has been unlocked */
3064 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3065 {
3066 assert(ownerdata->monotonicitysize > 0);
3067 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3068 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3069
3070 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3071 ownerdata->monotonicitysize = 0;
3072 }
3073 break;
3074 }
3075
3077 {
3078 SCIP_MONOTONE monotonicity;
3079
3080 /* get monotonicity of child */
3081 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3082 * SCIPcallExprMonotonicity
3083 */
3084 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3085
3086 /* compute resulting locks of the child expression */
3087 switch( monotonicity )
3088 {
3089 case SCIP_MONOTONE_INC:
3090 ituserdata.intvals[0] = nlockspos;
3091 ituserdata.intvals[1] = nlocksneg;
3092 break;
3093 case SCIP_MONOTONE_DEC:
3094 ituserdata.intvals[0] = nlocksneg;
3095 ituserdata.intvals[1] = nlockspos;
3096 break;
3098 ituserdata.intvals[0] = nlockspos + nlocksneg;
3099 ituserdata.intvals[1] = nlockspos + nlocksneg;
3100 break;
3102 ituserdata.intvals[0] = 0;
3103 ituserdata.intvals[1] = 0;
3104 break;
3105 }
3106 /* set locks in child expression */
3107 SCIPexpriterSetChildUserData(it, ituserdata);
3108
3109 break;
3110 }
3111
3112 default :
3113 /* you should never be here */
3114 SCIPABORT();
3115 break;
3116 }
3117
3118 expr = SCIPexpriterGetNext(it);
3119 }
3120
3121 SCIPfreeExpriter(&it);
3122
3123 return SCIP_OKAY;
3124}
3125
3126/** main function for adding locks to expressions and variables
3127 *
3128 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3129 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3130 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3131 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3132 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3133 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3134 * which implies that updating the monotonicity information during the next locking of this expression does not
3135 * break existing locks.
3136 *
3137 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3138 * locks from an expression and repropagating them after the structural changes have been applied.
3139 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3140 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3141 */
3142static
3144 SCIP* scip, /**< SCIP data structure */
3145 SCIP_CONS* cons, /**< nonlinear constraint */
3146 int nlockspos, /**< number of positive rounding locks */
3147 int nlocksneg /**< number of negative rounding locks */
3148 )
3149{
3150 SCIP_CONSDATA* consdata;
3151
3152 assert(cons != NULL);
3153
3154 if( nlockspos == 0 && nlocksneg == 0 )
3155 return SCIP_OKAY;
3156
3157 consdata = SCIPconsGetData(cons);
3158 assert(consdata != NULL);
3159
3160 /* no constraint sides -> nothing to lock */
3161 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3162 return SCIP_OKAY;
3163
3164 /* remember locks */
3165 consdata->nlockspos += nlockspos;
3166 consdata->nlocksneg += nlocksneg;
3167
3168 assert(consdata->nlockspos >= 0);
3169 assert(consdata->nlocksneg >= 0);
3170
3171 /* compute locks for lock propagation */
3172 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3173 {
3174 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3175 }
3176 else if( !SCIPisInfinity(scip, consdata->rhs) )
3177 {
3178 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3179 }
3180 else
3181 {
3182 assert(!SCIPisInfinity(scip, -consdata->lhs));
3183 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3184 }
3185
3186 return SCIP_OKAY;
3187}
3188
3189/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3190static
3192 SCIP* scip, /**< SCIP data structure */
3193 SCIP_CONS* cons /**< nonlinear constraint */
3194 )
3195{
3196 SCIP_CONSDATA* consdata;
3197
3198 assert(scip != NULL);
3199 assert(cons != NULL);
3200
3201 consdata = SCIPconsGetData(cons);
3202 assert(consdata != NULL);
3203 assert(consdata->expr != NULL);
3204
3205 if( consdata->nlrow != NULL )
3206 {
3207 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3208 }
3209
3210 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3211 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3212 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3213
3214 if( SCIPisExprSum(scip, consdata->expr) )
3215 {
3216 /* if root is a sum, then split into linear and nonlinear terms */
3217 SCIP_EXPR* nonlinpart;
3218 SCIP_EXPR* child;
3219 SCIP_Real* coefs;
3220 int i;
3221
3222 coefs = SCIPgetCoefsExprSum(consdata->expr);
3223
3224 /* constant term of sum */
3225 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3226
3227 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3228 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3229
3230 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3231 {
3232 child = SCIPexprGetChildren(consdata->expr)[i];
3233 if( SCIPisExprVar(scip, child) )
3234 {
3235 /* linear term */
3236 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3237 }
3238 else
3239 {
3240 /* nonlinear term */
3241 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3242 }
3243 }
3244
3245 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3246 {
3247 /* add expression to nlrow (this will make a copy) */
3248 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3249 }
3250 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3251 }
3252 else
3253 {
3254 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3255 }
3256
3257 return SCIP_OKAY;
3258}
3259
3260/** compares enfodata by enforcement priority of nonlinear handler
3261 *
3262 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3263 */
3264static
3266{
3267 SCIP_NLHDLR* h1;
3268 SCIP_NLHDLR* h2;
3269
3270 assert(elem1 != NULL);
3271 assert(elem2 != NULL);
3272
3273 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3274 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3275
3276 assert(h1 != NULL);
3277 assert(h2 != NULL);
3278
3281
3284
3285 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3286}
3287
3288/** install nlhdlrs in one expression */
3289static
3291 SCIP* scip, /**< SCIP data structure */
3292 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3293 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3294 )
3295{
3296 SCIP_EXPR_OWNERDATA* ownerdata;
3297 SCIP_CONSHDLRDATA* conshdlrdata;
3298 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3299 SCIP_NLHDLR_METHOD enforcemethods;
3300 SCIP_NLHDLR_METHOD enforcemethodsnew;
3301 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3302 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3303 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3304 int enfossize; /* allocated length of expr->enfos array */
3305 int h;
3306
3307 assert(expr != NULL);
3308
3309 ownerdata = SCIPexprGetOwnerData(expr);
3310 assert(ownerdata != NULL);
3311
3312 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3313 assert(conshdlrdata != NULL);
3314 assert(conshdlrdata->auxvarid >= 0);
3315 assert(!conshdlrdata->indetect);
3316
3317 /* there should be no enforcer yet and detection should not even have considered expr yet */
3318 assert(ownerdata->nenfos < 0);
3319 assert(ownerdata->enfos == NULL);
3320
3321 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3322 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3323 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3324 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3325 * - if no one uses activity, then do not need activity methods
3326 */
3327 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3328 if( ownerdata->nauxvaruses == 0 )
3329 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3330 else
3331 {
3332 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3333 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3334 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3335 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3336 }
3337 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3338 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3339
3340 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3341 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3342
3343 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3344 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3345
3346 ownerdata->nenfos = 0;
3347 enfossize = 2;
3348 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3349 conshdlrdata->indetect = TRUE;
3350
3351 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3352 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3353 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3354 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3355 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3356
3357 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3358 {
3359 SCIP_NLHDLR* nlhdlr;
3360
3361 nlhdlr = conshdlrdata->nlhdlrs[h];
3362 assert(nlhdlr != NULL);
3363
3364 /* skip disabled nlhdlrs */
3365 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3366 continue;
3367
3368 /* call detect routine of nlhdlr */
3369 nlhdlrexprdata = NULL;
3370 enforcemethodsnew = enforcemethods;
3371 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3372 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3373 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3374 /* coverity[var_deref_model] */
3375 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3376
3377 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3378 nlhdlrparticipating &= enforcemethodsallowed;
3379
3380 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3381 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3382
3383 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3384 * They are also cleaned up here to ensure that only the needed methods are claimed.
3385 */
3386 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3387
3388 /* nlhdlr needs to participate for the methods it is enforcing */
3389 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3390
3391 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3392 {
3393 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3394 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3395
3396 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3397 if( nlhdlrexprdata != NULL )
3398 {
3399 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3400 }
3401 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3402 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3403
3404 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3405
3406 continue;
3407 }
3408
3409 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3410 SCIPnlhdlrGetName(nlhdlr),
3411 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3412 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3413 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3414
3415 /* store nlhdlr and its data */
3416 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3417 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3418 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3419 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3420 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3421 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3422 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3423 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3424 ownerdata->nenfos++;
3425
3426 /* update enforcement flags */
3427 enforcemethods = enforcemethodsnew;
3428 }
3429
3430 conshdlrdata->indetect = FALSE;
3431
3432 /* stop if an enforcement method is missing but we are already in solving stage
3433 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3434 */
3435 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3436 {
3437 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3438 return SCIP_ERROR;
3439 }
3440
3441 assert(ownerdata->nenfos > 0);
3442
3443 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3444 if( ownerdata->nenfos > 1 )
3445 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3446
3447 /* resize enfos array to be nenfos long */
3448 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3449
3450 return SCIP_OKAY;
3451}
3452
3453/** detect nlhdlrs that can handle the expressions */
3454static
3456 SCIP* scip, /**< SCIP data structure */
3457 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3458 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3459 int nconss /**< total number of constraints */
3460 )
3461{
3462 SCIP_CONSHDLRDATA* conshdlrdata;
3463 SCIP_CONSDATA* consdata;
3464 SCIP_EXPR* expr;
3465 SCIP_EXPR_OWNERDATA* ownerdata;
3466 SCIP_EXPRITER* it;
3467 int i;
3468
3469 assert(conss != NULL || nconss == 0);
3470 assert(nconss >= 0);
3471 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 */
3472
3473 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3474 assert(conshdlrdata != NULL);
3475
3478
3480 {
3481 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3482 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3483 */
3485 conshdlrdata->globalbounds = TRUE;
3486 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3487 }
3488
3489 for( i = 0; i < nconss; ++i )
3490 {
3491 assert(conss != NULL && conss[i] != NULL);
3492
3493 consdata = SCIPconsGetData(conss[i]);
3494 assert(consdata != NULL);
3495 assert(consdata->expr != NULL);
3496
3497 /* if a constraint is separated, we currently need it to be initial, too
3498 * this is because INITLP will create the auxiliary variables that are used for any separation
3499 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3500 */
3501 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3502
3503 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3504 assert(ownerdata != NULL);
3505
3506 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3507 * then we would normally skip to run DETECT again
3508 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3509 * thus, if expr is the root expression, we rerun DETECT
3510 */
3511 if( ownerdata->nenfos > 0 )
3512 {
3513 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3514 assert(ownerdata->nenfos < 0);
3515 }
3516
3517 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3518 * this way we can treat the root expression like any other expression when enforcing via separation
3519 * if constraint will be propagated, then register activity usage of root expression
3520 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3521 */
3522 conshdlrdata->indetect = TRUE;
3525 SCIPconsIsPropagated(conss[i]),
3526 FALSE, FALSE) );
3527 conshdlrdata->indetect = FALSE;
3528
3529 /* compute integrality information for all subexpressions */
3530 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3531
3532 /* run detectNlhdlr on all expr where required */
3533 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3534 {
3535 ownerdata = SCIPexprGetOwnerData(expr);
3536 assert(ownerdata != NULL);
3537
3538 /* skip exprs that we already looked at */
3539 if( ownerdata->nenfos >= 0 )
3540 continue;
3541
3542 /* if there is use of the auxvar, then someone requires that
3543 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3544 * thus, we need to find nlhdlrs that separate or estimate
3545 * if there is use of the activity, then there is someone requiring that
3546 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3547 * thus, we need to find nlhdlrs that do interval-evaluation
3548 */
3549 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3550 {
3551 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3552
3553 assert(ownerdata->nenfos >= 0);
3554 }
3555 else
3556 {
3557 /* remember that we looked at this expression during detectNlhdlrs
3558 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3559 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3560 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3561 */
3562 ownerdata->nenfos = 0;
3563 }
3564 }
3565
3566 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3567 if( SCIPconsIsPropagated(conss[i]) )
3568 consdata->ispropagated = FALSE;
3569 }
3570
3572 {
3573 /* ensure that the local bounds are used again when reevaluating the expressions later;
3574 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3575 */
3577 conshdlrdata->globalbounds = FALSE;
3578 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3579 }
3580 else
3581 {
3582 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3584 }
3585
3586 SCIPfreeExpriter(&it);
3587
3588 return SCIP_OKAY;
3589}
3590
3591/** initializes (pre)solving data of constraints
3592 *
3593 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3594 * not be modified.
3595 * In particular, this function
3596 * - runs the detection method of nlhldrs
3597 * - looks for unlocked linear variables
3598 * - checks curvature (if not in presolve)
3599 * - creates and add row to NLP (if not in presolve)
3600 *
3601 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3602 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3603 */
3604static
3606 SCIP* scip, /**< SCIP data structure */
3607 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3608 SCIP_CONS** conss, /**< constraints */
3609 int nconss /**< number of constraints */
3610 )
3611{
3612 int c;
3613
3614 for( c = 0; c < nconss; ++c )
3615 {
3616 /* check for a linear variable that can be increase or decreased without harming feasibility */
3617 findUnlockedLinearVar(scip, conss[c]);
3618
3620 {
3621 SCIP_CONSDATA* consdata;
3622 SCIP_Bool success = FALSE;
3623
3624 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3625 assert(consdata != NULL);
3626 assert(consdata->expr != NULL);
3627
3628 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3629 {
3630 /* call the curvature detection algorithm of the convex nonlinear handler
3631 * Check only for those curvature that may result in a convex inequality, i.e.,
3632 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3633 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3634 */
3635 if( !SCIPisInfinity(scip, -consdata->lhs) )
3636 {
3637 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3638 if( success )
3639 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3640 }
3641 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3642 {
3643 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3644 if( success )
3645 consdata->curv = SCIP_EXPRCURV_CONVEX;
3646 }
3647 }
3648 else
3649 {
3650 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3651 {
3652 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3653 consdata->curv = SCIP_EXPRCURV_LINEAR;
3654 }
3655 else
3656 {
3657 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3658 }
3659 }
3660 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3661
3662 /* add nlrow representation to NLP, if NLP had been constructed */
3664 {
3665 if( consdata->nlrow == NULL )
3666 {
3667 SCIP_CALL( createNlRow(scip, conss[c]) );
3668 assert(consdata->nlrow != NULL);
3669 }
3670 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3671 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3672 }
3673 }
3674 }
3675
3676 /* register non linear handlers */
3677 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3678
3679 return SCIP_OKAY;
3680}
3681
3682/** deinitializes (pre)solving data of constraints
3683 *
3684 * This removes the initialization data created in initSolve().
3685 *
3686 * This function can be called in presolve and solve.
3687 *
3688 * TODO At the moment, it should not be called for a constraint if there are other constraints
3689 * that use the same expressions but still require their nlhdlr.
3690 * We should probably only decrement the auxvar and activity usage for the root expr and then
3691 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3692 */
3693static
3695 SCIP* scip, /**< SCIP data structure */
3696 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3697 SCIP_CONS** conss, /**< constraints */
3698 int nconss /**< number of constraints */
3699 )
3700{
3701 SCIP_EXPRITER* it;
3702 SCIP_EXPR* expr;
3703 SCIP_CONSDATA* consdata;
3704 SCIP_Bool rootactivityvalid;
3705 int c;
3706
3710
3711 /* call deinitialization callbacks of expression and nonlinear handlers
3712 * free nonlinear handlers information from expressions
3713 * remove auxiliary variables and nactivityuses counts from expressions
3714 */
3715 for( c = 0; c < nconss; ++c )
3716 {
3717 assert(conss != NULL);
3718 assert(conss[c] != NULL);
3719
3720 consdata = SCIPconsGetData(conss[c]);
3721 assert(consdata != NULL);
3722 assert(consdata->expr != NULL);
3723
3724 /* check and remember whether activity in root is valid */
3725 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3726
3727 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3728 {
3729 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3730
3731 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3732 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3733
3734 /* remove quadratic info */
3736
3737 if( rootactivityvalid )
3738 {
3739 /* ensure activity is valid if consdata->expr activity is valid
3740 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3741 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3742 * so this childs activity would be invalid, which can generate confusion
3743 */
3745 }
3746 }
3747
3748 if( consdata->nlrow != NULL )
3749 {
3750 /* remove row from NLP, if still in solving
3751 * if we are in exitsolve, the whole NLP will be freed anyway
3752 */
3754 {
3755 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3756 }
3757
3758 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3759 }
3760
3761 /* forget about linear variables that can be increased or decreased without harming feasibility */
3762 consdata->linvardecr = NULL;
3763 consdata->linvarincr = NULL;
3764
3765 /* forget about curvature */
3766 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3767 }
3768
3769 SCIPfreeExpriter(&it);
3770
3771 return SCIP_OKAY;
3772}
3773
3774/** helper method to decide whether a given expression is product of at least two binary variables */
3775static
3777 SCIP* scip, /**< SCIP data structure */
3778 SCIP_EXPR* expr /**< expression */
3779 )
3780{
3781 int i;
3782
3783 assert(expr != NULL);
3784
3785 /* check whether the expression is a product */
3786 if( !SCIPisExprProduct(scip, expr) )
3787 return FALSE;
3788
3789 /* don't consider products with a coefficient != 1 and products with a single child
3790 * simplification will take care of this expression later
3791 */
3792 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3793 return FALSE;
3794
3795 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3796 {
3797 SCIP_EXPR* child;
3798 SCIP_VAR* var;
3799 SCIP_Real ub;
3800 SCIP_Real lb;
3801
3802 child = SCIPexprGetChildren(expr)[i];
3803 assert(child != NULL);
3804
3805 if( !SCIPisExprVar(scip, child) )
3806 return FALSE;
3807
3808 var = SCIPgetVarExprVar(child);
3809 lb = SCIPvarGetLbLocal(var);
3810 ub = SCIPvarGetUbLocal(var);
3811
3812 /* check whether variable is integer and has [0,1] as variable bounds */
3813 if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3814 return FALSE;
3815 }
3816
3817 return TRUE;
3818}
3819
3820/** helper method to collect all bilinear binary product terms */
3821static
3823 SCIP* scip, /**< SCIP data structure */
3824 SCIP_EXPR* sumexpr, /**< sum expression */
3825 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3826 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3827 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3828 int* nterms /**< pointer to store the total number of bilinear binary terms */
3829 )
3830{
3831 int i;
3832
3833 assert(sumexpr != NULL);
3834 assert(SCIPisExprSum(scip, sumexpr));
3835 assert(xs != NULL);
3836 assert(ys != NULL);
3837 assert(childidxs != NULL);
3838 assert(nterms != NULL);
3839
3840 *nterms = 0;
3841
3842 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3843 {
3844 SCIP_EXPR* child;
3845
3846 child = SCIPexprGetChildren(sumexpr)[i];
3847 assert(child != NULL);
3848
3849 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3850 {
3853
3854 assert(x != NULL);
3855 assert(y != NULL);
3856
3857 if( x != y )
3858 {
3859 xs[*nterms] = x;
3860 ys[*nterms] = y;
3861 childidxs[*nterms] = i;
3862 ++(*nterms);
3863 }
3864 }
3865 }
3866
3867 return SCIP_OKAY;
3868}
3869
3870/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3871static
3873 SCIP* scip, /**< SCIP data structure */
3874 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3875 SCIP_CONS* cons, /**< constraint */
3876 SCIP_VAR* facvar, /**< variable that has been factorized */
3877 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3878 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3879 int nvars, /**< total number of variables in sum_j c_ij x_j */
3880 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3881 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3882 )
3883{
3884 SCIP_VAR* auxvar;
3885 SCIP_CONS* newcons;
3886 SCIP_Real minact = 0.0;
3887 SCIP_Real maxact = 0.0;
3888 SCIP_Bool integral = TRUE;
3889 char name [SCIP_MAXSTRLEN];
3890 int i;
3891
3892 assert(facvar != NULL);
3893 assert(vars != NULL);
3894 assert(nvars > 1);
3895 assert(newexpr != NULL);
3896
3897 /* compute minimum and maximum activity of sum_j c_ij x_j */
3898 /* 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 */
3899 for( i = 0; i < nvars; ++i )
3900 {
3901 minact += MIN(coefs[i], 0.0);
3902 maxact += MAX(coefs[i], 0.0);
3903 integral = integral && SCIPisIntegral(scip, coefs[i]);
3904 }
3905 assert(minact <= maxact);
3906
3907 /* create and add auxiliary variable */
3908 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3909 SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3910 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3911
3912 /* create and add z - maxact x <= 0 */
3913 if( !SCIPisZero(scip, maxact) )
3914 {
3915 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3916 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3917 SCIP_CALL( SCIPaddCons(scip, newcons) );
3918 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3919 if( naddconss != NULL )
3920 ++(*naddconss);
3921 }
3922
3923 /* create and add 0 <= z - minact x */
3924 if( !SCIPisZero(scip, minact) )
3925 {
3926 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3927 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3928 SCIP_CALL( SCIPaddCons(scip, newcons) );
3929 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3930 if( naddconss != NULL )
3931 ++(*naddconss);
3932 }
3933
3934 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3935 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3936 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3937 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3938 if( !SCIPisZero(scip, minact) )
3939 {
3940 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3941 }
3942 SCIP_CALL( SCIPaddCons(scip, newcons) );
3943 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3944 if( naddconss != NULL )
3945 ++(*naddconss);
3946
3947 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
3948 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3949 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3950 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3951 if( !SCIPisZero(scip, maxact) )
3952 {
3953 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
3954 }
3955 SCIP_CALL( SCIPaddCons(scip, newcons) );
3956 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3957 if( naddconss != NULL )
3958 ++(*naddconss);
3959
3960 /* create variable expression */
3961 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
3962
3963 /* release auxvar */
3964 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3965
3966 return SCIP_OKAY;
3967}
3968
3969/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3970static
3972 SCIP* scip, /**< SCIP data structure */
3973 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3974 SCIP_CONS* cons, /**< constraint */
3975 SCIP_EXPR* sumexpr, /**< expression */
3976 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
3977 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
3978 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3979 )
3980{
3981 SCIP_EXPR** exprs = NULL;
3982 SCIP_VAR** tmpvars = NULL;
3983 SCIP_VAR** vars = NULL;
3984 SCIP_VAR** xs = NULL;
3985 SCIP_VAR** ys = NULL;
3986 SCIP_Real* exprcoefs = NULL;
3987 SCIP_Real* tmpcoefs = NULL;
3988 SCIP_Real* sumcoefs;
3989 SCIP_Bool* isused = NULL;
3990 int* childidxs = NULL;
3991 int* count = NULL;
3992 int nchildren;
3993 int nexprs = 0;
3994 int nterms;
3995 int nvars;
3996 int ntotalvars;
3997 int i;
3998
3999 assert(sumexpr != NULL);
4000 assert(minterms > 1);
4001 assert(newexpr != NULL);
4002
4003 *newexpr = NULL;
4004
4005 /* check whether sumexpr is indeed a sum */
4006 if( !SCIPisExprSum(scip, sumexpr) )
4007 return SCIP_OKAY;
4008
4009 nchildren = SCIPexprGetNChildren(sumexpr);
4010 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4012 ntotalvars = SCIPgetNTotalVars(scip);
4013
4014 /* check whether there are enough terms available */
4015 if( nchildren < minterms )
4016 return SCIP_OKAY;
4017
4018 /* allocate memory */
4019 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4020 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4021 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4022
4023 /* collect all bilinear binary product terms */
4024 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4025
4026 /* check whether there are enough terms available */
4027 if( nterms < minterms )
4028 goto TERMINATE;
4029
4030 /* store how often each variable appears in a bilinear binary product */
4032 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4033 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4034
4035 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4036 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4039
4040 for( i = 0; i < nterms; ++i )
4041 {
4042 int xidx;
4043 int yidx;
4044
4045 assert(xs[i] != NULL);
4046 assert(ys[i] != NULL);
4047
4048 xidx = SCIPvarGetIndex(xs[i]);
4049 assert(xidx < ntotalvars);
4050 yidx = SCIPvarGetIndex(ys[i]);
4051 assert(yidx < ntotalvars);
4052
4053 ++count[xidx];
4054 ++count[yidx];
4055
4056 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4057 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4058 }
4059
4060 /* sort variables; don't change order of count array because it depends on problem indices */
4061 {
4062 int* tmpcount;
4063
4064 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4065 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4066 SCIPfreeBufferArray(scip, &tmpcount);
4067 }
4068
4069 for( i = 0; i < nvars; ++i )
4070 {
4071 SCIP_VAR* facvar = vars[i];
4072 int ntmpvars = 0;
4073 int j;
4074
4075 /* skip candidate if there are not enough terms left */
4076 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4077 continue;
4078
4079 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4080
4081 /* collect variables for x_i * sum_j c_ij x_j */
4082 for( j = 0; j < nterms; ++j )
4083 {
4084 int childidx = childidxs[j];
4085 assert(childidx >= 0 && childidx < nchildren);
4086
4087 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4088 {
4089 SCIP_Real coef;
4090 int xidx;
4091 int yidx;
4092
4093 coef = sumcoefs[childidx];
4094 assert(coef != 0.0);
4095
4096 /* collect corresponding variable */
4097 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4098 tmpcoefs[ntmpvars] = coef;
4099 ++ntmpvars;
4100
4101 /* update counters */
4102 xidx = SCIPvarGetIndex(xs[j]);
4103 assert(xidx < ntotalvars);
4104 yidx = SCIPvarGetIndex(ys[j]);
4105 assert(yidx < ntotalvars);
4106 --count[xidx];
4107 --count[yidx];
4108 assert(count[xidx] >= 0);
4109 assert(count[yidx] >= 0);
4110
4111 /* mark term to be used */
4112 isused[childidx] = TRUE;
4113 }
4114 }
4115 assert(ntmpvars >= minterms);
4116 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4117 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4118
4119 /* create required constraints and store the generated expression */
4120 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4121 exprcoefs[nexprs] = 1.0;
4122 ++nexprs;
4123 }
4124
4125 /* factorization was only successful if at least one expression has been generated */
4126 if( nexprs > 0 )
4127 {
4128 int nexprsold = nexprs;
4129
4130 /* add all children of the sum that have not been used */
4131 for( i = 0; i < nchildren; ++i )
4132 {
4133 if( !isused[i] )
4134 {
4135 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4136 exprcoefs[nexprs] = sumcoefs[i];
4137 ++nexprs;
4138 }
4139 }
4140
4141 /* create a new sum expression */
4142 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4143
4144 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4145 for( i = 0; i < nexprsold; ++i )
4146 {
4147 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4148 }
4149 }
4150
4151TERMINATE:
4152 /* free memory */
4153 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4154 SCIPfreeBufferArrayNull(scip, &tmpvars);
4155 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4158 SCIPfreeBufferArrayNull(scip, &isused);
4160 SCIPfreeBufferArray(scip, &childidxs);
4163
4164 return SCIP_OKAY;
4165}
4166
4167/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4168static
4170 SCIP* scip, /**< SCIP data structure */
4171 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4172 SCIP_EXPR* prodexpr, /**< product expression */
4173 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4174 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4175 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4176 )
4177{
4178 SCIP_VAR** vars;
4179 SCIP_CONS* cons;
4180 SCIP_Real* coefs;
4181 SCIP_VAR* w;
4182 char* name;
4183 int nchildren;
4184 int i;
4185
4186 assert(conshdlr != NULL);
4187 assert(prodexpr != NULL);
4188 assert(SCIPisExprProduct(scip, prodexpr));
4189 assert(newexpr != NULL);
4190
4191 nchildren = SCIPexprGetNChildren(prodexpr);
4192 assert(nchildren >= 2);
4193
4194 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4195 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4196 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4197 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4198
4199 /* prepare the names of the variable and the constraints */
4200 /* coverity[secure_coding] */
4201 strcpy(name, "binreform");
4202 for( i = 0; i < nchildren; ++i )
4203 {
4205 coefs[i] = 1.0;
4206 assert(vars[i] != NULL);
4207 (void) strcat(name, "_");
4208 (void) strcat(name, SCIPvarGetName(vars[i]));
4209 }
4210
4211 /* create and add variable */
4212 SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4214 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4215
4216 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4217 if( nchildren == 2 && !empathy4and )
4218 {
4219 SCIP_VAR* x = vars[0];
4220 SCIP_VAR* y = vars[1];
4221
4222 assert(x != NULL);
4223 assert(y != NULL);
4224 assert(x != y);
4225
4226 /* create and add x - w >= 0 */
4227 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4228 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4229 SCIP_CALL( SCIPaddCons(scip, cons) );
4230 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4231
4232 /* create and add y - w >= 0 */
4233 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4234 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4235 SCIP_CALL( SCIPaddCons(scip, cons) );
4236 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4237
4238 /* create and add x + y - w <= 1 */
4239 vars[2] = w;
4240 coefs[2] = -1.0;
4241 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4242 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4243 SCIP_CALL( SCIPaddCons(scip, cons) );
4244 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4245
4246 /* update number of added constraints */
4247 if( naddconss != NULL )
4248 *naddconss += 3;
4249 }
4250 else
4251 {
4252 /* create, add, and release AND constraint */
4253 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4254 SCIP_CALL( SCIPaddCons(scip, cons) );
4255 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4256 SCIPdebugMsg(scip, " create AND constraint\n");
4257
4258 /* update number of added constraints */
4259 if( naddconss != NULL )
4260 *naddconss += 1;
4261 }
4262
4263 /* create variable expression */
4264 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4265
4266 /* release created variable */
4268
4269 /* free memory */
4270 SCIPfreeBufferArray(scip, &name);
4271 SCIPfreeBufferArray(scip, &coefs);
4273
4274 return SCIP_OKAY;
4275}
4276
4277/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4278static
4280 SCIP* scip, /**< SCIP data structure */
4281 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4282 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4283 SCIP_EXPR* prodexpr, /**< product expression */
4284 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4285 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4286 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4287 )
4288{
4289 SCIP_CONSHDLRDATA* conshdlrdata;
4290 int nchildren;
4291
4292 assert(prodexpr != NULL);
4293 assert(newexpr != NULL);
4294
4295 *newexpr = NULL;
4296
4297 /* only consider products of binary variables */
4298 if( !isBinaryProduct(scip, prodexpr) )
4299 return SCIP_OKAY;
4300
4301 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4302 assert(conshdlrdata != NULL);
4303 nchildren = SCIPexprGetNChildren(prodexpr);
4304 assert(nchildren >= 2);
4305
4306 /* check whether there is already an expression that represents the product */
4307 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4308 {
4309 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4310 assert(*newexpr != NULL);
4311
4312 /* capture expression */
4313 SCIPcaptureExpr(*newexpr);
4314 }
4315 else
4316 {
4317 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4318
4319 if( nchildren == 2 )
4320 {
4321 SCIP_CLIQUE** xcliques;
4322 SCIP_VAR* x;
4323 SCIP_VAR* y;
4324 SCIP_Bool found_clique = FALSE;
4325 int c;
4326
4327 /* get variables from the product expression */
4328 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4329 assert(x != NULL);
4330 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4331 assert(y != NULL);
4332 assert(x != y);
4333
4334 /* first try to find a clique containing both variables */
4335 xcliques = SCIPvarGetCliques(x, TRUE);
4336
4337 /* look in cliques containing x */
4338 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4339 {
4340 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4341 {
4342 /* create zero value expression */
4343 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4344
4345 if( nchgcoefs != NULL )
4346 *nchgcoefs += 1;
4347
4348 found_clique = TRUE;
4349 break;
4350 }
4351
4352 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4353 {
4354 /* create variable expression for x */
4355 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4356
4357 if( nchgcoefs != NULL )
4358 *nchgcoefs += 2;
4359
4360 found_clique = TRUE;
4361 break;
4362 }
4363 }
4364
4365 if( !found_clique )
4366 {
4367 xcliques = SCIPvarGetCliques(x, FALSE);
4368
4369 /* look in cliques containing complement of x */
4370 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4371 {
4372 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4373 {
4374 /* create variable expression for y */
4375 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4376
4377 if( nchgcoefs != NULL )
4378 *nchgcoefs += 1;
4379
4380 found_clique = TRUE;
4381 break;
4382 }
4383
4384 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4385 {
4386 /* create sum expression */
4387 SCIP_EXPR* sum_children[2];
4388 SCIP_Real sum_coefs[2];
4389 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4390 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4391 sum_coefs[0] = 1.0;
4392 sum_coefs[1] = 1.0;
4393 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4394
4395 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4396 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4397
4398 if( nchgcoefs != NULL )
4399 *nchgcoefs += 3;
4400
4401 found_clique = TRUE;
4402 break;
4403 }
4404 }
4405 }
4406
4407 /* if the variables are not in a clique, do standard linearization */
4408 if( !found_clique )
4409 {
4410 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4411 }
4412 }
4413 else
4414 {
4415 /* linearize binary product using an AND constraint because nchildren > 2 */
4416 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4417 }
4418
4419 /* hash variable expression */
4420 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4421 }
4422
4423 return SCIP_OKAY;
4424}
4425
4426/** helper function to replace binary products in a given constraint */
4427static
4429 SCIP* scip, /**< SCIP data structure */
4430 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4431 SCIP_CONS* cons, /**< constraint */
4432 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4433 SCIP_EXPRITER* it, /**< expression iterator */
4434 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4435 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4436 )
4437{
4438 SCIP_CONSHDLRDATA* conshdlrdata;
4439 SCIP_CONSDATA* consdata;
4440 SCIP_EXPR* expr;
4441
4442 assert(conshdlr != NULL);
4443 assert(cons != NULL);
4444 assert(exprmap != NULL);
4445 assert(it != NULL);
4446
4447 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4448 assert(conshdlrdata != NULL);
4449
4450 consdata = SCIPconsGetData(cons);
4451 assert(consdata != NULL);
4452 assert(consdata->expr != NULL);
4453
4454 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4455
4456 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4457 {
4458 SCIP_EXPR* newexpr = NULL;
4459 SCIP_EXPR* childexpr;
4460 int childexpridx;
4461
4462 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4463 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4464 childexpr = SCIPexpriterGetChildExprDFS(it);
4465 assert(childexpr != NULL);
4466
4467 /* try to factorize variables in a sum expression that contains several products of binary variables */
4468 if( conshdlrdata->reformbinprodsfac > 1 )
4469 {
4470 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4471 }
4472
4473 /* try to create an expression that represents a product of binary variables */
4474 if( newexpr == NULL )
4475 {
4476 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4477 }
4478
4479 if( newexpr != NULL )
4480 {
4481 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4482
4483 /* replace product expression */
4484 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4485
4486 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4487 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4488
4489 /* mark the constraint to not be simplified anymore */
4490 consdata->issimplified = FALSE;
4491 }
4492 }
4493
4494 return SCIP_OKAY;
4495}
4496
4497/** reformulates products of binary variables during presolving in the following way:
4498 *
4499 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4500 * 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}:
4501 * \f[
4502 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4503 * \f]
4504 *
4505 * 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$.
4506 * These cliques allow for a better reformulation. There are four cases:
4507 *
4508 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4509 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4510 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4511 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4512 *
4513 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4514 *
4515 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4516 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4517 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4518 * Such a lower sum is reformulated with only one extra variable w_i:
4519 * \f{align}{
4520 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4521 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4522 * \text{minact}\, x_i & \leq w_i, \\
4523 * w_i &\leq \text{maxact}\, x_i, \\
4524 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4525 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4526 * \f}
4527 * 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
4528 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4529 * of terms are prioritized.
4530 */
4531static
4533 SCIP* scip, /**< SCIP data structure */
4534 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4535 SCIP_CONS** conss, /**< constraints */
4536 int nconss, /**< total number of constraints */
4537 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4538 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4539 )
4540{
4541 SCIP_CONSHDLRDATA* conshdlrdata;
4542 SCIP_HASHMAP* exprmap;
4543 SCIP_EXPRITER* it;
4544 int c;
4545
4546 assert(conshdlr != NULL);
4547
4548 /* no nonlinear constraints or binary variables -> skip */
4549 if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4550 return SCIP_OKAY;
4551 assert(conss != NULL);
4552
4553 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4554 assert(conshdlrdata != NULL);
4555
4556 /* create expression hash map */
4558
4559 /* create expression iterator */
4563
4564 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4565
4566 for( c = 0; c < nconss; ++c )
4567 {
4568 SCIP_CONSDATA* consdata;
4569 SCIP_EXPR* newexpr = NULL;
4570
4571 assert(conss[c] != NULL);
4572
4573 consdata = SCIPconsGetData(conss[c]);
4574 assert(consdata != NULL);
4575
4576 /* try to reformulate the root expression */
4577 if( conshdlrdata->reformbinprodsfac > 1 )
4578 {
4579 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4580 }
4581
4582 /* release the root node if another expression has been found */
4583 if( newexpr != NULL )
4584 {
4585 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4586 consdata->expr = newexpr;
4587
4588 /* mark constraint to be not simplified anymore */
4589 consdata->issimplified = FALSE;
4590 }
4591
4592 /* replace each product of binary variables separately */
4593 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4594 }
4595
4596 /* free memory */
4597 SCIPhashmapFree(&exprmap);
4598 SCIPfreeExpriter(&it);
4599
4600 return SCIP_OKAY;
4601}
4602
4603/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4604 *
4605 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4606 * Then scale by -1 if
4607 * - \f$n_+ < n_-\f$, or
4608 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4609 */
4610static
4612 SCIP* scip, /**< SCIP data structure */
4613 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4614 SCIP_CONS* cons, /**< nonlinear constraint */
4615 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4616 )
4617{
4618 SCIP_CONSDATA* consdata;
4619 int i;
4620
4621 assert(cons != NULL);
4622
4623 consdata = SCIPconsGetData(cons);
4624 assert(consdata != NULL);
4625
4626 if( SCIPisExprSum(scip, consdata->expr) )
4627 {
4628 SCIP_Real* coefs;
4629 SCIP_Real constant;
4630 int nchildren;
4631 int counter = 0;
4632
4633 coefs = SCIPgetCoefsExprSum(consdata->expr);
4634 constant = SCIPgetConstantExprSum(consdata->expr);
4635 nchildren = SCIPexprGetNChildren(consdata->expr);
4636
4637 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4638 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4639 {
4640 SCIP_EXPR* expr;
4641 expr = consdata->expr;
4642
4643 consdata->expr = SCIPexprGetChildren(expr)[0];
4644 assert(!SCIPisExprSum(scip, consdata->expr));
4645
4646 SCIPcaptureExpr(consdata->expr);
4647
4648 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4649 consdata->lhs = -consdata->lhs;
4650 consdata->rhs = -consdata->rhs;
4651
4652 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4653 *changed = TRUE;
4654 return SCIP_OKAY;
4655 }
4656
4657 /* compute n_+ - n_i */
4658 for( i = 0; i < nchildren; ++i )
4659 counter += coefs[i] > 0 ? 1 : -1;
4660
4661 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4662 {
4663 SCIP_EXPR* expr;
4664 SCIP_Real* newcoefs;
4665
4666 /* allocate memory */
4667 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4668
4669 for( i = 0; i < nchildren; ++i )
4670 newcoefs[i] = -coefs[i];
4671
4672 /* create a new sum expression */
4673 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4674
4675 /* replace expression in constraint data and scale sides */
4676 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4677 consdata->expr = expr;
4678 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4679 consdata->lhs = -consdata->lhs;
4680 consdata->rhs = -consdata->rhs;
4681
4682 /* free memory */
4683 SCIPfreeBufferArray(scip, &newcoefs);
4684
4685 *changed = TRUE;
4686 }
4687 }
4688
4689 return SCIP_OKAY;
4690}
4691
4692/** forbid multiaggrations of variables that appear nonlinear in constraints */
4693static
4695 SCIP* scip, /**< SCIP data structure */
4696 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4697 SCIP_CONS** conss, /**< constraints */
4698 int nconss /**< number of constraints */
4699 )
4700{
4701 SCIP_EXPRITER* it;
4702 SCIP_CONSDATA* consdata;
4703 SCIP_EXPR* expr;
4704 int c;
4705
4706 assert(scip != NULL);
4707 assert(conshdlr != NULL);
4708
4709 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4710 return SCIP_OKAY;
4711
4714
4715 for( c = 0; c < nconss; ++c )
4716 {
4717 consdata = SCIPconsGetData(conss[c]);
4718 assert(consdata != NULL);
4719
4720 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4721 * i.e., skip children of sum that are variables
4722 */
4723 if( SCIPisExprSum(scip, consdata->expr) )
4724 {
4725 int i;
4726 SCIP_EXPR* child;
4727 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4728 {
4729 child = SCIPexprGetChildren(consdata->expr)[i];
4730
4731 /* skip variable expression, as they correspond to a linear term */
4732 if( SCIPisExprVar(scip, child) )
4733 continue;
4734
4735 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4736 if( SCIPisExprVar(scip, expr) )
4737 {
4739 }
4740 }
4741 }
4742 else
4743 {
4744 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4745 if( SCIPisExprVar(scip, expr) )
4746 {
4748 }
4749 }
4750 }
4751
4752 SCIPfreeExpriter(&it);
4753
4754 return SCIP_OKAY;
4755}
4756
4757/** simplifies expressions and replaces common subexpressions for a set of constraints
4758 * @todo put the constant to the constraint sides
4759 */
4760static
4762 SCIP* scip, /**< SCIP data structure */
4763 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4764 SCIP_CONS** conss, /**< constraints */
4765 int nconss, /**< total number of constraints */
4766 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4767 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4768 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4769 int* naddconss, /**< counter to add number of added constraints, or NULL */
4770 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4771 )
4772{
4773 SCIP_CONSHDLRDATA* conshdlrdata;
4774 SCIP_CONSDATA* consdata;
4775 int* nlockspos;
4776 int* nlocksneg;
4777 SCIP_Bool havechange;
4778 int i;
4779
4780 assert(scip != NULL);
4781 assert(conshdlr != NULL);
4782 assert(conss != NULL);
4783 assert(nconss > 0);
4784 assert(infeasible != NULL);
4785
4786 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4787 assert(conshdlrdata != NULL);
4788
4789 /* update number of canonicalize calls */
4790 ++(conshdlrdata->ncanonicalizecalls);
4791
4792 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4793
4794 *infeasible = FALSE;
4795
4796 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4797 havechange = conshdlrdata->ncanonicalizecalls == 1;
4798
4799 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4800 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4801
4802 /* allocate memory for storing locks of each constraint */
4803 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4804 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4805
4806 /* unlock all constraints */
4807 for( i = 0; i < nconss; ++i )
4808 {
4809 assert(conss[i] != NULL);
4810
4811 consdata = SCIPconsGetData(conss[i]);
4812 assert(consdata != NULL);
4813
4814 /* remember locks */
4815 nlockspos[i] = consdata->nlockspos;
4816 nlocksneg[i] = consdata->nlocksneg;
4817
4818 /* remove locks */
4819 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4820 assert(consdata->nlockspos == 0);
4821 assert(consdata->nlocksneg == 0);
4822 }
4823
4824#ifndef NDEBUG
4825 /* check whether all locks of each expression have been removed */
4826 for( i = 0; i < nconss; ++i )
4827 {
4828 SCIP_EXPR* expr;
4829 SCIP_EXPRITER* it;
4830
4832
4833 consdata = SCIPconsGetData(conss[i]);
4834 assert(consdata != NULL);
4835
4837 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4838 {
4839 assert(expr != NULL);
4840 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4841 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4842 }
4843 SCIPfreeExpriter(&it);
4844 }
4845#endif
4846
4847 /* reformulate products of binary variables */
4848 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4849 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4850 {
4851 int tmpnaddconss = 0;
4852 int tmpnchgcoefs = 0;
4853
4854 /* call this function before simplification because expressions might not be simplified after reformulating
4855 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4856 */
4857 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4858
4859 /* update counters */
4860 if( naddconss != NULL )
4861 *naddconss = tmpnaddconss;
4862 if( nchgcoefs != NULL )
4863 *nchgcoefs = tmpnchgcoefs;
4864
4865 /* check whether at least one expression has changed */
4866 if( tmpnaddconss + tmpnchgcoefs > 0 )
4867 havechange = TRUE;
4868 }
4869
4870 for( i = 0; i < nconss; ++i )
4871 {
4872 consdata = SCIPconsGetData(conss[i]);
4873 assert(consdata != NULL);
4874
4875 /* call simplify for each expression */
4876 if( !consdata->issimplified && consdata->expr != NULL )
4877 {
4878 SCIP_EXPR* simplified;
4879 SCIP_Bool changed;
4880
4881 changed = FALSE;
4882 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4883 consdata->issimplified = TRUE;
4884
4885 if( changed )
4886 havechange = TRUE;
4887
4888 /* 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").
4889 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4890 */
4891 if( simplified != consdata->expr )
4892 {
4893 assert(changed);
4894
4895 /* release old expression */
4896 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4897
4898 /* store simplified expression */
4899 consdata->expr = simplified;
4900 }
4901 else
4902 {
4903 /* The simplify captures simplified in any case, also if nothing has changed.
4904 * Therefore, we have to release it here.
4905 */
4906 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4907 }
4908
4909 if( *infeasible )
4910 break;
4911
4912 /* scale constraint sides */
4913 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4914
4915 if( changed )
4916 havechange = TRUE;
4917
4918 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4919 if( SCIPisExprValue(scip, consdata->expr) )
4920 {
4921 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4922 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4923 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4924 {
4925 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4926 SCIPdebugPrintCons(scip, conss[i], NULL);
4927 *infeasible = TRUE;
4928 break;
4929 }
4930 else
4931 {
4932 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
4933 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
4934 if( ndelconss != NULL )
4935 ++*ndelconss;
4936 havechange = TRUE;
4937 }
4938 }
4939 }
4940 }
4941
4942 /* replace common subexpressions */
4943 if( havechange && !*infeasible )
4944 {
4945 SCIP_CONS** consssorted;
4946 SCIP_EXPR** rootexprs;
4947 SCIP_Bool replacedroot;
4948
4949 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
4950 for( i = 0; i < nconss; ++i )
4951 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
4952
4953 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
4954
4955 /* update pointer to root expr in constraints, if any has changed
4956 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
4957 */
4958 if( replacedroot )
4959 for( i = 0; i < nconss; ++i )
4960 SCIPconsGetData(conss[i])->expr = rootexprs[i];
4961
4962 SCIPfreeBufferArray(scip, &rootexprs);
4963
4964 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
4965 * been changed after simplification; now we completely recollect all variable expression and variable events
4966 */
4967
4968 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
4969 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
4970 */
4971 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
4972 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
4973
4974 for( i = nconss-1; i >= 0; --i )
4975 {
4976 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
4977 if( SCIPconsIsDeleted(consssorted[i]) )
4978 continue;
4979
4980 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4981 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
4982 }
4983 for( i = 0; i < nconss; ++i )
4984 {
4985 if( SCIPconsIsDeleted(consssorted[i]) )
4986 continue;
4987
4988 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
4989 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4990 }
4991
4992 SCIPfreeBufferArray(scip, &consssorted);
4993
4994 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
4995 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
4996 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
4997 */
4998 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
4999 }
5000
5001 /* restore locks */
5002 for( i = 0; i < nconss; ++i )
5003 {
5004 if( SCIPconsIsDeleted(conss[i]) )
5005 continue;
5006
5007 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5008 }
5009
5010 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5011 * TODO can we skip this in presoltiming fast?
5012 */
5013 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5014 {
5015 /* reset one of the number of detections counter to count only current presolving round */
5016 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5017 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5018
5019 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5020 }
5021
5022 /* free allocated memory */
5023 SCIPfreeBufferArray(scip, &nlocksneg);
5024 SCIPfreeBufferArray(scip, &nlockspos);
5025
5026 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5027
5028 return SCIP_OKAY;
5029}
5030
5031/** merges constraints that have the same root expression */
5032static
5034 SCIP* scip, /**< SCIP data structure */
5035 SCIP_CONS** conss, /**< constraints to process */
5036 int nconss, /**< number of constraints */
5037 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5038 )
5039{
5040 SCIP_HASHMAP* expr2cons;
5041 SCIP_Bool* updatelocks;
5042 int* nlockspos;
5043 int* nlocksneg;
5044 int c;
5045
5046 assert(success != NULL);
5047
5048 *success = FALSE;
5049
5050 /* not enough constraints available */
5051 if( nconss <= 1 )
5052 return SCIP_OKAY;
5053
5054 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5055 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5056 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5057 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5058
5059 for( c = 0; c < nconss; ++c )
5060 {
5061 SCIP_CONSDATA* consdata;
5062
5063 /* ignore deleted constraints */
5064 if( SCIPconsIsDeleted(conss[c]) )
5065 continue;
5066
5067 consdata = SCIPconsGetData(conss[c]);
5068 assert(consdata != NULL);
5069
5070 /* add expression to the hash map if not seen so far */
5071 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5072 {
5073 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5074 }
5075 else
5076 {
5077 SCIP_CONSDATA* imgconsdata;
5078 int idx;
5079
5080 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5081 assert(idx >= 0 && idx < nconss);
5082
5083 imgconsdata = SCIPconsGetData(conss[idx]);
5084 assert(imgconsdata != NULL);
5085 assert(imgconsdata->expr == consdata->expr);
5086
5087 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5088 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5089
5090 /* check whether locks need to be updated */
5091 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5092 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5093 {
5094 nlockspos[idx] = imgconsdata->nlockspos;
5095 nlocksneg[idx] = imgconsdata->nlocksneg;
5096 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5097 updatelocks[idx] = TRUE;
5098 }
5099
5100 /* update constraint sides */
5101 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5102 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5103
5104 /* delete constraint */
5105 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5106 *success = TRUE;
5107 }
5108 }
5109
5110 /* restore locks of updated constraints */
5111 if( *success )
5112 {
5113 for( c = 0; c < nconss; ++c )
5114 {
5115 if( updatelocks[c] )
5116 {
5117 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5118 }
5119 }
5120 }
5121
5122 /* free memory */
5123 SCIPfreeBufferArray(scip, &nlocksneg);
5124 SCIPfreeBufferArray(scip, &nlockspos);
5125 SCIPfreeBufferArray(scip, &updatelocks);
5126 SCIPhashmapFree(&expr2cons);
5127
5128 return SCIP_OKAY;
5129}
5130
5131/** interval evaluation of variables as used in redundancy check
5132 *
5133 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5134 */
5135static
5136SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5137{ /*lint --e{715}*/
5138 SCIP_CONSHDLRDATA* conshdlrdata;
5139 SCIP_INTERVAL interval;
5140 SCIP_Real lb;
5141 SCIP_Real ub;
5142
5143 assert(scip != NULL);
5144 assert(var != NULL);
5145
5146 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5147 assert(conshdlrdata != NULL);
5148
5149 if( conshdlrdata->globalbounds )
5150 {
5151 lb = SCIPvarGetLbGlobal(var);
5152 ub = SCIPvarGetUbGlobal(var);
5153 }
5154 else
5155 {
5156 lb = SCIPvarGetLbLocal(var);
5157 ub = SCIPvarGetUbLocal(var);
5158 }
5159 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5160
5161 /* relax variable bounds, if there are bounds and variable is not fixed
5162 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5163 */
5164 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5165 {
5166 if( !SCIPisInfinity(scip, -lb) )
5167 lb -= SCIPfeastol(scip);
5168
5169 if( !SCIPisInfinity(scip, ub) )
5170 ub += SCIPfeastol(scip);
5171 }
5172
5173 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5176 assert(lb <= ub);
5177
5178 SCIPintervalSetBounds(&interval, lb, ub);
5179
5180 return interval;
5181}
5182
5183/** removes constraints that are always feasible or very simple
5184 *
5185 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5186 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5187 * might violate variable bounds by up to feastol, too.
5188 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5189 *
5190 * Also removes constraints of the form lhs &le; variable &le; rhs.
5191 *
5192 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5193 *
5194 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5195 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5196 * would appear as if the constraint is redundant.
5197 */
5198static
5200 SCIP* scip, /**< SCIP data structure */
5201 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5202 SCIP_CONS** conss, /**< constraints to propagate */
5203 int nconss, /**< total number of constraints */
5204 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5205 int* ndelconss, /**< buffer to add the number of deleted constraints */
5206 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5207 )
5208{
5209 SCIP_CONSHDLRDATA* conshdlrdata;
5210 SCIP_CONSDATA* consdata;
5211 SCIP_INTERVAL activity;
5212 SCIP_INTERVAL sides;
5213 int i;
5214
5215 assert(scip != NULL);
5216 assert(conshdlr != NULL);
5217 assert(conss != NULL);
5218 assert(nconss >= 0);
5219 assert(cutoff != NULL);
5220 assert(ndelconss != NULL);
5221 assert(nchgbds != NULL);
5222
5223 /* no constraints to check */
5224 if( nconss == 0 )
5225 return SCIP_OKAY;
5226
5227 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5228 assert(conshdlrdata != NULL);
5229
5230 /* increase curboundstag and set lastvaractivitymethodchange
5231 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5232 * for the redundancy check differently than for domain propagation
5233 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5234 */
5235 ++conshdlrdata->curboundstag;
5236 assert(conshdlrdata->curboundstag > 0);
5237 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5238 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5239 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5240
5241 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5242
5243 *cutoff = FALSE;
5244 for( i = 0; i < nconss; ++i )
5245 {
5246 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5247 continue;
5248
5249 consdata = SCIPconsGetData(conss[i]);
5250 assert(consdata != NULL);
5251
5252 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5253 if( SCIPisExprValue(scip, consdata->expr) )
5254 {
5255 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5256
5257 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5258 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5259 {
5260 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5261 *cutoff = TRUE;
5262
5263 goto TERMINATE;
5264 }
5265
5266 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5267
5268 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5269 ++*ndelconss;
5270
5271 continue;
5272 }
5273
5274 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5275 if( SCIPisExprVar(scip, consdata->expr) )
5276 {
5277 SCIP_VAR* var;
5278 SCIP_Bool tightened;
5279
5280 var = SCIPgetVarExprVar(consdata->expr);
5281 assert(var != NULL);
5282
5283 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);
5284
5285 /* ensure that variable bounds are within constraint sides */
5286 if( !SCIPisInfinity(scip, -consdata->lhs) )
5287 {
5288 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5289
5290 if( tightened )
5291 ++*nchgbds;
5292
5293 if( *cutoff )
5294 goto TERMINATE;
5295 }
5296
5297 if( !SCIPisInfinity(scip, consdata->rhs) )
5298 {
5299 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5300
5301 if( tightened )
5302 ++*nchgbds;
5303
5304 if( *cutoff )
5305 goto TERMINATE;
5306 }
5307
5308 /* delete the (now) redundant constraint locally */
5309 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5310 ++*ndelconss;
5311
5312 continue;
5313 }
5314
5315 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5316 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5317 * variable bounds by up to feastol
5318 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5319 */
5320 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5321 SCIPdebugPrintCons(scip, conss[i], NULL);
5322
5323 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5325
5326 /* it is unlikely that we detect infeasibility by doing forward propagation */
5327 if( *cutoff )
5328 {
5329 SCIPdebugMsg(scip, " -> cutoff\n");
5330 goto TERMINATE;
5331 }
5332
5333 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5334 activity = SCIPexprGetActivity(consdata->expr);
5335
5336 /* relax sides by feastol
5337 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5338 */
5339 SCIPintervalSetBounds(&sides,
5340 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5341 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5342
5343 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5344 {
5345 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5346
5347 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5348 ++*ndelconss;
5349
5350 continue;
5351 }
5352
5353 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5354 }
5355
5356TERMINATE:
5357 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5358 ++conshdlrdata->curboundstag;
5359 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5360 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5361 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5362
5363 return SCIP_OKAY;
5364}
5365
5366/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5367static
5369 SCIP* scip, /**< SCIP data structure */
5370 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5371 SCIP_CONS* cons, /**< source constraint to try to convert */
5372 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5373 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5374 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5375 )
5376{
5377 SCIP_CONSHDLRDATA* conshdlrdata;
5378 SCIP_CONSDATA* consdata;
5379 SCIP_CONS** upgdconss;
5380 int upgdconsssize;
5381 int nupgdconss_;
5382 int i;
5383
5384 assert(scip != NULL);
5385 assert(conshdlr != NULL);
5386 assert(cons != NULL);
5388 assert(upgraded != NULL);
5389 assert(nupgdconss != NULL);
5390 assert(naddconss != NULL);
5391
5392 *upgraded = FALSE;
5393
5394 nupgdconss_ = 0;
5395
5396 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5397 assert(conshdlrdata != NULL);
5398
5399 /* if there are no upgrade methods, we can stop */
5400 if( conshdlrdata->nconsupgrades == 0 )
5401 return SCIP_OKAY;
5402
5403 upgdconsssize = 2;
5404 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5405
5406 /* call the upgrading methods */
5407 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5409
5410 consdata = SCIPconsGetData(cons);
5411 assert(consdata != NULL);
5412
5413 /* try all upgrading methods in priority order in case the upgrading step is enable */
5414 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5415 {
5416 if( !conshdlrdata->consupgrades[i]->active )
5417 continue;
5418
5419 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5420
5421 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5422
5423 while( nupgdconss_ < 0 )
5424 {
5425 /* upgrade function requires more memory: resize upgdconss and call again */
5426 assert(-nupgdconss_ > upgdconsssize);
5427 upgdconsssize = -nupgdconss_;
5428 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5429
5430 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5431
5432 assert(nupgdconss_ != 0);
5433 }
5434
5435 if( nupgdconss_ > 0 )
5436 {
5437 /* got upgrade */
5438 int j;
5439
5440 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5441
5442 /* add the upgraded constraints to the problem and forget them */
5443 for( j = 0; j < nupgdconss_; ++j )
5444 {
5445 SCIPdebugMsgPrint(scip, "\t");
5446 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5447
5448 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5449 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5450 }
5451
5452 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5453 *nupgdconss += 1;
5454 *naddconss += nupgdconss_ - 1;
5455 *upgraded = TRUE;
5456
5457 /* delete upgraded constraint */
5458 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5459 SCIP_CALL( SCIPdelCons(scip, cons) );
5460
5461 break;
5462 }
5463 }
5464
5465 SCIPfreeBufferArray(scip, &upgdconss);
5466
5467 return SCIP_OKAY;
5468}
5469
5470/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5471 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5472 * variable bounds, and is not binary
5473 */
5474static
5476 SCIP* scip, /**< SCIP data structure */
5477 SCIP_EXPR* expr /**< variable expression */
5478 )
5479{
5480 SCIP_VAR* var;
5481 SCIP_EXPR_OWNERDATA* ownerdata;
5482
5483 assert(SCIPisExprVar(scip, expr));
5484
5485 var = SCIPgetVarExprVar(expr);
5486 assert(var != NULL);
5487
5488 ownerdata = SCIPexprGetOwnerData(expr);
5489 assert(ownerdata != NULL);
5490
5491 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5492 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5493 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5497}
5498
5499/** removes all variable expressions that are contained in a given expression from a hash map */
5500static
5502 SCIP* scip, /**< SCIP data structure */
5503 SCIP_EXPR* expr, /**< expression */
5504 SCIP_EXPRITER* it, /**< expression iterator */
5505 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5506 )
5507{
5508 SCIP_EXPR* e;
5509
5510 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5511 {
5512 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5513 {
5514 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5515 }
5516 }
5517
5518 return SCIP_OKAY;
5519}
5520
5521/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5522 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5523 *
5524 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5525 * Otherwise, a bound disjunction constraint is added.
5526 *
5527 * @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
5528 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5529 * 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
5530 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5531 */
5532static
5534 SCIP* scip, /**< SCIP data structure */
5535 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5536 SCIP_CONS* cons, /**< nonlinear constraint */
5537 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5538 int* naddconss, /**< pointer to store the total number of added constraints */
5539 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5540 )
5541{
5542 SCIP_CONSHDLRDATA* conshdlrdata;
5543 SCIP_CONSDATA* consdata;
5544 SCIP_EXPR** singlelocked;
5545 SCIP_HASHMAP* exprcands;
5546 SCIP_Bool hasbounddisj;
5547 SCIP_Bool haslhs;
5548 SCIP_Bool hasrhs;
5549 int nsinglelocked = 0;
5550 int i;
5551
5552 assert(conshdlr != NULL);
5553 assert(cons != NULL);
5554 assert(nchgvartypes != NULL);
5555 assert(naddconss != NULL);
5556 assert(infeasible != NULL);
5557
5558 *nchgvartypes = 0;
5559 *naddconss = 0;
5560 *infeasible = FALSE;
5561
5562 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5563 assert(conshdlrdata != NULL);
5564 consdata = SCIPconsGetData(cons);
5565 assert(consdata != NULL);
5566
5567 /* only consider constraints with one finite side */
5568 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5569 return SCIP_OKAY;
5570
5571 /* only consider sum expressions */
5572 if( !SCIPisExprSum(scip, consdata->expr) )
5573 return SCIP_OKAY;
5574
5575 /* remember which side is finite */
5576 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5577 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5578
5579 /* allocate memory */
5580 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5581 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5582
5583 /* check all variable expressions for single locked variables */
5584 for( i = 0; i < consdata->nvarexprs; ++i )
5585 {
5586 assert(consdata->varexprs[i] != NULL);
5587
5588 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5589 {
5590 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5591 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5592 }
5593 }
5594 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5595
5596 if( nsinglelocked > 0 )
5597 {
5598 SCIP_EXPR** children;
5599 SCIP_EXPRITER* it;
5600 int nchildren;
5601
5602 children = SCIPexprGetChildren(consdata->expr);
5603 nchildren = SCIPexprGetNChildren(consdata->expr);
5604
5605 /* create iterator */
5609
5610 for( i = 0; i < nchildren; ++i )
5611 {
5612 SCIP_EXPR* child;
5613 SCIP_Real coef;
5614
5615 child = children[i];
5616 assert(child != NULL);
5617 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5618
5619 /* ignore linear terms */
5620 if( SCIPisExprVar(scip, child) )
5621 continue;
5622
5623 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5624 * expression that represents f_j and remove each variable expression from exprcands
5625 */
5626 else if( SCIPisExprProduct(scip, child) )
5627 {
5628 int j;
5629
5630 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5631 {
5632 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5633
5634 if( !SCIPisExprVar(scip, grandchild) )
5635 {
5636 /* mark all variable expressions that are contained in the expression */
5637 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5638 }
5639 }
5640 }
5641 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5642 * for an integer k >= 1
5643 */
5644 else if( SCIPisExprPower(scip, child) )
5645 {
5646 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5647 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5648 SCIP_Bool valid;
5649
5650 /* check for even integral exponent */
5651 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5652
5653 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5654 {
5655 /* mark all variable expressions that are contained in the expression */
5656 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5657 }
5658 }
5659 /* all other cases cannot be handled */
5660 else
5661 {
5662 /* mark all variable expressions that are contained in the expression */
5663 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5664 }
5665 }
5666
5667 /* free expression iterator */
5668 SCIPfreeExpriter(&it);
5669 }
5670
5671 /* check whether the bound disjunction constraint handler is available */
5672 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5673
5674 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5675 for( i = 0; i < nsinglelocked; ++i )
5676 {
5677 /* only consider expressions that are still contained in the exprcands map */
5678 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5679 {
5680 SCIP_CONS* newcons;
5681 SCIP_VAR* vars[2];
5682 SCIP_BOUNDTYPE boundtypes[2];
5683 SCIP_Real bounds[2];
5684 char name[SCIP_MAXSTRLEN];
5685 SCIP_VAR* var;
5686
5687 var = SCIPgetVarExprVar(singlelocked[i]);
5688 assert(var != NULL);
5689 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5691
5692 /* try to change the variable type to binary */
5693 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5694 {
5697 ++(*nchgvartypes);
5698
5699 if( *infeasible )
5700 {
5701 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5702 break;
5703 }
5704 }
5705 /* add bound disjunction constraint if bounds of the variable are finite */
5706 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5707 {
5708 vars[0] = var;
5709 vars[1] = var;
5710 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5711 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5712 bounds[0] = SCIPvarGetUbGlobal(var);
5713 bounds[1] = SCIPvarGetLbGlobal(var);
5714
5715 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5716
5717 /* create, add, and release bound disjunction constraint */
5718 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5719 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5721 SCIP_CALL( SCIPaddCons(scip, newcons) );
5722 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5723 ++(*naddconss);
5724 }
5725 }
5726 }
5727
5728 /* free memory */
5729 SCIPfreeBufferArray(scip, &singlelocked);
5730 SCIPhashmapFree(&exprcands);
5731
5732 return SCIP_OKAY;
5733}
5734
5735/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5736static
5738 SCIP* scip, /**< SCIP data structure */
5739 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5740 SCIP_CONS** conss, /**< nonlinear constraints */
5741 int nconss, /**< total number of nonlinear constraints */
5742 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5743 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5744 )
5745{
5746 int c;
5747
5748 assert(scip != NULL);
5749 assert(conshdlr != NULL);
5750 assert(conss != NULL || nconss == 0);
5751 assert(nchgvartypes != NULL);
5752 assert(infeasible != NULL);
5753
5754 *infeasible = FALSE;
5755
5756 /* nothing can be done if there are no binary and integer variables available */
5757 if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5758 return SCIP_OKAY;
5759
5760 /* no continuous var can be made implicit-integer if there are no continuous variables */
5761 if( SCIPgetNContVars(scip) == 0 )
5762 return SCIP_OKAY;
5763
5764 for( c = 0; c < nconss; ++c )
5765 {
5766 SCIP_CONSDATA* consdata;
5767 SCIP_EXPR** children;
5768 int nchildren;
5769 SCIP_Real* coefs;
5770 SCIP_EXPR* cand = NULL;
5771 SCIP_Real candcoef = 0.0;
5772 int i;
5773
5774 assert(conss != NULL && conss[c] != NULL);
5775
5776 consdata = SCIPconsGetData(conss[c]);
5777 assert(consdata != NULL);
5778
5779 /* the constraint must be an equality constraint */
5780 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5781 continue;
5782
5783 /* the root expression needs to be a sum expression */
5784 if( !SCIPisExprSum(scip, consdata->expr) )
5785 continue;
5786
5787 children = SCIPexprGetChildren(consdata->expr);
5788 nchildren = SCIPexprGetNChildren(consdata->expr);
5789
5790 /* the sum expression must have at least two children
5791 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5792 */
5793 if( nchildren <= 1 )
5794 continue;
5795
5796 coefs = SCIPgetCoefsExprSum(consdata->expr);
5797
5798 /* find first continuous variable and get value of its coefficient */
5799 for( i = 0; i < nchildren; ++i )
5800 {
5801 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5802 continue;
5803
5804 candcoef = coefs[i];
5805 assert(candcoef != 0.0);
5806
5807 /* lhs/rhs - constant divided by candcoef must be integral
5808 * if not, break with cand == NULL, so give up
5809 */
5810 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5811 cand = children[i];
5812
5813 break;
5814 }
5815
5816 /* no suitable continuous variable found */
5817 if( cand == NULL )
5818 continue;
5819
5820 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5821 for( i = 0; i < nchildren; ++i )
5822 {
5823 if( children[i] == cand )
5824 continue;
5825
5826 /* child i must be integral */
5827 if( !SCIPexprIsIntegral(children[i]) )
5828 {
5829 cand = NULL;
5830 break;
5831 }
5832
5833 /* coefficient of child i must be integral if diving by candcoef */
5834 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5835 {
5836 cand = NULL;
5837 break;
5838 }
5839 }
5840
5841 if( cand == NULL )
5842 continue;
5843
5844 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5846
5847 /* change variable type */
5849
5850 if( *infeasible )
5851 return SCIP_OKAY;
5852
5853 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5855 }
5856
5857 return SCIP_OKAY;
5858}
5859
5860/** creates auxiliary variable for a given expression
5861 *
5862 * @note for a variable expression it does nothing
5863 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5864 */
5865static
5867 SCIP* scip, /**< SCIP data structure */
5868 SCIP_EXPR* expr /**< expression */
5869 )
5870{
5871 SCIP_EXPR_OWNERDATA* ownerdata;
5872 SCIP_CONSHDLRDATA* conshdlrdata;
5873 SCIP_VARTYPE vartype;
5874 SCIP_INTERVAL activity;
5875 char name[SCIP_MAXSTRLEN];
5876
5877 assert(scip != NULL);
5878 assert(expr != NULL);
5879
5880 ownerdata = SCIPexprGetOwnerData(expr);
5881 assert(ownerdata != NULL);
5882 assert(ownerdata->nauxvaruses > 0);
5883
5884 /* if we already have auxvar, then do nothing */
5885 if( ownerdata->auxvar != NULL )
5886 return SCIP_OKAY;
5887
5888 /* if expression is a variable-expression, then do nothing */
5889 if( SCIPisExprVar(scip, expr) )
5890 return SCIP_OKAY;
5891
5893 {
5894 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5895 return SCIP_INVALIDCALL;
5896 }
5897
5898 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5899 assert(conshdlrdata != NULL);
5900 assert(conshdlrdata->auxvarid >= 0);
5901
5902 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5903 * but it usually indicates a missing simplify
5904 * if we find situations where we need to have an auxvar for a constant, then remove this assert
5905 */
5906 assert(!SCIPisExprValue(scip, expr));
5907
5908 /* create and capture auxiliary variable */
5909 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5910 ++conshdlrdata->auxvarid;
5911
5912 /* type of auxiliary variable depends on integrality information of the expression */
5914
5915 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5916 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5917 {
5918 activity = SCIPexprGetActivity(expr);
5919 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5920 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5921 * and abort in debug mode only
5922 */
5924 {
5925 SCIPABORT();
5927 }
5928 }
5929 else
5931
5932 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
5933 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
5934 */
5935 if( SCIPgetDepth(scip) == 0 )
5936 {
5937 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
5938 }
5939 else
5940 {
5941 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
5942 }
5943
5944 /* mark the auxiliary variable to be added for the relaxation only
5945 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
5946 * or to copy the variable to a subscip
5947 */
5948 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
5949
5950 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
5951
5952 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
5953
5954 /* add variable locks in both directions
5955 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
5956 * but then we need to also update the auxvars locks when the expr locks change
5957 */
5958 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
5959
5960#ifdef WITH_DEBUG_SOLUTION
5961 if( SCIPdebugIsMainscip(scip) )
5962 {
5963 /* store debug solution value of auxiliary variable
5964 * assumes that expression has been evaluated in debug solution before
5965 */
5966 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
5967 }
5968#endif
5969
5970 if( SCIPgetDepth(scip) > 0 )
5971 {
5972 /* initialize local bounds to (locally valid) activity */
5973 SCIP_Bool cutoff;
5974 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
5975 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
5976 }
5977
5978 return SCIP_OKAY;
5979}
5980
5981/** initializes separation for constraint
5982 *
5983 * - ensures that activities are up to date in all expressions
5984 * - creates auxiliary variables where required
5985 * - calls propExprDomains() to possibly tighten auxvar bounds
5986 * - calls separation initialization callback of nlhdlrs
5987 */
5988static
5990 SCIP* scip, /**< SCIP data structure */
5991 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5992 SCIP_CONS** conss, /**< constraints */
5993 int nconss, /**< number of constraints */
5994 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
5995 )
5996{
5997 SCIP_CONSDATA* consdata;
5998 SCIP_CONSHDLRDATA* conshdlrdata;
5999 SCIP_EXPRITER* it;
6000 SCIP_EXPR* expr;
6002 SCIP_VAR* auxvar;
6003 int nreductions = 0;
6004 int c, e;
6005
6006 assert(scip != NULL);
6007 assert(conshdlr != NULL);
6008 assert(conss != NULL || nconss == 0);
6009 assert(nconss >= 0);
6010 assert(infeasible != NULL);
6011
6012 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6013 assert(conshdlrdata != NULL);
6014
6015 /* start with new propbounds (just to be sure, should not be needed) */
6016 ++conshdlrdata->curpropboundstag;
6017
6020
6021 /* first ensure activities are up to date and create auxvars */
6022 *infeasible = FALSE;
6023 for( c = 0; c < nconss; ++c )
6024 {
6025 assert(conss != NULL);
6026 assert(conss[c] != NULL);
6027
6028 consdata = SCIPconsGetData(conss[c]);
6029 assert(consdata != NULL);
6030 assert(consdata->expr != NULL);
6031
6032#ifdef WITH_DEBUG_SOLUTION
6033 if( SCIPdebugIsMainscip(scip) )
6034 {
6035 SCIP_SOL* debugsol;
6036
6037 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6038
6039 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6040 {
6041 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6042 * in createAuxVar()
6043 */
6044 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6045 }
6046 }
6047#endif
6048
6049 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6050 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6051
6052 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6053 {
6054 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6055 {
6056 SCIP_CALL( createAuxVar(scip, expr) );
6057 }
6058 }
6059
6060 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6061 if( auxvar != NULL )
6062 {
6063 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6064 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6065 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6066 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6067 if( *infeasible )
6068 {
6069 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6070 break;
6071 }
6072
6073 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6074 if( *infeasible )
6075 {
6076 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6077 break;
6078 }
6079 }
6080 }
6081
6082 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6083 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6084 * (e.g., log(x*y), which becomes log(w), w=x*y
6085 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6086 */
6087 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6088 if( result == SCIP_CUTOFF )
6089 *infeasible = TRUE;
6090
6091 /* now call initsepa of nlhdlrs
6092 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6093 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6094 */
6096 for( c = 0; c < nconss && !*infeasible; ++c )
6097 {
6098 assert(conss != NULL);
6099 assert(conss[c] != NULL);
6100
6101 consdata = SCIPconsGetData(conss[c]);
6102 assert(consdata != NULL);
6103 assert(consdata->expr != NULL);
6104
6105 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6106 {
6107 SCIP_EXPR_OWNERDATA* ownerdata;
6108
6109 ownerdata = SCIPexprGetOwnerData(expr);
6110 assert(ownerdata != NULL);
6111
6112 if( ownerdata->nauxvaruses == 0 )
6113 continue;
6114
6115 for( e = 0; e < ownerdata->nenfos; ++e )
6116 {
6117 SCIP_NLHDLR* nlhdlr;
6118 SCIP_Bool underestimate;
6119 SCIP_Bool overestimate;
6120 assert(ownerdata->enfos[e] != NULL);
6121
6122 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6123 * which participated in a previous initSepa() call
6124 */
6125 if( ownerdata->enfos[e]->issepainit )
6126 continue;
6127
6128 /* only call initsepa if it will actually separate */
6129 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6130 continue;
6131
6132 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6133 assert(nlhdlr != NULL);
6134
6135 /* only init sepa if there is an initsepa callback */
6136 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6137 continue;
6138
6139 /* check whether expression needs to be under- or overestimated */
6140 overestimate = ownerdata->nlocksneg > 0;
6141 underestimate = ownerdata->nlockspos > 0;
6142 assert(underestimate || overestimate);
6143
6144 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6145
6146 /* call the separation initialization callback of the nonlinear handler */
6147 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6148 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6149 ownerdata->enfos[e]->issepainit = TRUE;
6150
6151 if( *infeasible )
6152 {
6153 /* stop everything if we detected infeasibility */
6154 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6155 break;
6156 }
6157 }
6158 }
6159 }
6160
6161 SCIPfreeExpriter(&it);
6162
6163 return SCIP_OKAY;
6164}
6165
6166/** returns whether we are ok to branch on auxiliary variables
6167 *
6168 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6169 */
6170static
6172 SCIP* scip, /**< SCIP data structure */
6173 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6174 )
6175{
6176 SCIP_CONSHDLRDATA* conshdlrdata;
6177
6178 assert(conshdlr != NULL);
6179
6180 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6181 assert(conshdlrdata != NULL);
6182
6183 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6184}
6185
6186/** gets weight of variable when splitting violation score onto several variables in an expression */
6187static
6189 SCIP* scip, /**< SCIP data structure */
6190 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6191 SCIP_VAR* var, /**< variable */
6192 SCIP_SOL* sol /**< current solution */
6193 )
6194{
6195 SCIP_CONSHDLRDATA* conshdlrdata;
6196
6197 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6198 assert(conshdlrdata != NULL);
6199
6200 switch( conshdlrdata->branchviolsplit )
6201 {
6202 case 'u' : /* uniform: everyone gets the same score */
6203 return 1.0;
6204
6205 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6206 {
6207 SCIP_Real weight;
6209 return MAX(0.05, weight);
6210 }
6211
6212 case 'd' : /* domain width */
6214
6215 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6216 {
6217 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6218 assert(width > 0.0);
6219 if( width > 10.0 )
6220 return 10.0*log10(width);
6221 if( width < 0.1 )
6222 return 0.1/(-log10(width));
6223 return width;
6224 }
6225
6226 default :
6227 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6228 SCIPABORT();
6229 return SCIP_INVALID;
6230 }
6231}
6232
6233/** adds violation-branching score to a set of expressions, thereby distributing the score
6234 *
6235 * Each expression must either be a variable expression or have an aux-variable.
6236 *
6237 * If unbounded variables are present, each unbounded var gets an even score.
6238 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6239 */
6240static
6242 SCIP* scip, /**< SCIP data structure */
6243 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6244 int nexprs, /**< number of expressions */
6245 SCIP_Real violscore, /**< violation-branching score to add to expression */
6246 SCIP_SOL* sol, /**< current solution */
6247 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6248 )
6249{
6250 SCIP_CONSHDLR* conshdlr;
6251 SCIP_VAR* var;
6252 SCIP_Real weight;
6253 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6254 int nunbounded = 0; /* number of candidates with unbounded domain */
6255 int i;
6256
6257 assert(exprs != NULL);
6258 assert(nexprs > 0);
6259 assert(success != NULL);
6260
6261 if( nexprs == 1 )
6262 {
6263 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6264 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6266 *success = TRUE;
6267 return;
6268 }
6269
6270 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6271
6272 for( i = 0; i < nexprs; ++i )
6273 {
6275 assert(var != NULL);
6276
6278 ++nunbounded;
6280 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6281 }
6282
6283 *success = FALSE;
6284 for( i = 0; i < nexprs; ++i )
6285 {
6287 assert(var != NULL);
6288
6289 if( nunbounded > 0 )
6290 {
6292 {
6293 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6294 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6295 100.0/nunbounded, violscore,
6297 *success = TRUE;
6298 }
6299 }
6301 {
6302 assert(weightsum > 0.0);
6303
6304 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6305 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6306 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6307 100*weight / weightsum, violscore,
6309 *success = TRUE;
6310 }
6311 else
6312 {
6313 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6315 }
6316 }
6317}
6318
6319/** adds violation-branching score to children of expression for given auxiliary variables
6320 *
6321 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6322 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6323 *
6324 * @note This method may modify the given auxvars array by means of sorting.
6325 */
6326static
6328 SCIP* scip, /**< SCIP data structure */
6329 SCIP_EXPR* expr, /**< expression where to start searching */
6330 SCIP_Real violscore, /**< violation score to add to expression */
6331 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6332 int nauxvars, /**< number of auxiliary variables */
6333 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6334 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6335 )
6336{
6337 SCIP_EXPRITER* it;
6338 SCIP_VAR* auxvar;
6339 SCIP_EXPR** exprs;
6340 int nexprs;
6341 int pos;
6342
6343 assert(scip != NULL);
6344 assert(expr != NULL);
6345 assert(auxvars != NULL);
6346 assert(success != NULL);
6347
6348 /* sort variables to make lookup below faster */
6349 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6350
6353
6354 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6355 nexprs = 0;
6356
6357 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6358 {
6359 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6360 if( auxvar == NULL )
6361 continue;
6362
6363 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6364 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6365 {
6366 assert(auxvars[pos] == auxvar);
6367
6368 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6369 exprs[nexprs++] = expr;
6370
6371 if( nexprs == nauxvars )
6372 break;
6373 }
6374 }
6375
6376 SCIPfreeExpriter(&it);
6377
6378 if( nexprs > 0 )
6379 {
6380 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6381 }
6382 else
6383 *success = FALSE;
6384
6385 SCIPfreeBufferArray(scip, &exprs);
6386
6387 return SCIP_OKAY;
6388}
6389
6390/** registers all unfixed variables in violated constraints as branching candidates */
6391static
6393 SCIP* scip, /**< SCIP data structure */
6394 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6395 SCIP_CONS** conss, /**< constraints */
6396 int nconss, /**< number of constraints */
6397 int* nnotify /**< counter for number of notifications performed */
6398 )
6399{
6400 SCIP_CONSDATA* consdata;
6401 SCIP_VAR* var;
6402 int c;
6403 int i;
6404
6405 assert(conshdlr != NULL);
6406 assert(conss != NULL || nconss == 0);
6407 assert(nnotify != NULL);
6408
6409 *nnotify = 0;
6410
6411 for( c = 0; c < nconss; ++c )
6412 {
6413 assert(conss != NULL && conss[c] != NULL);
6414
6415 consdata = SCIPconsGetData(conss[c]);
6416 assert(consdata != NULL);
6417
6418 /* consider only violated constraints */
6419 if( !isConsViolated(scip, conss[c]) )
6420 continue;
6421
6422 /* register all variables that have not been fixed yet */
6423 assert(consdata->varexprs != NULL);
6424 for( i = 0; i < consdata->nvarexprs; ++i )
6425 {
6426 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6427 assert(var != NULL);
6428
6430 {
6432 ++(*nnotify);
6433 }
6434 }
6435 }
6436
6437 return SCIP_OKAY;
6438}
6439
6440/** registers all variables in violated constraints with branching scores as external branching candidates */
6441static
6443 SCIP* scip, /**< SCIP data structure */
6444 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6445 SCIP_CONS** conss, /**< constraints */
6446 int nconss, /**< number of constraints */
6447 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6448 )
6449{
6450 SCIP_CONSDATA* consdata;
6451 SCIP_EXPRITER* it = NULL;
6452 int c;
6453
6454 assert(conshdlr != NULL);
6455 assert(success != NULL);
6456
6457 *success = FALSE;
6458
6459 if( branchAuxNonlinear(scip, conshdlr) )
6460 {
6463 }
6464
6465 /* register external branching candidates */
6466 for( c = 0; c < nconss; ++c )
6467 {
6468 assert(conss != NULL && conss[c] != NULL);
6469
6470 consdata = SCIPconsGetData(conss[c]);
6471 assert(consdata != NULL);
6472 assert(consdata->varexprs != NULL);
6473
6474 /* consider only violated constraints */
6475 if( !isConsViolated(scip, conss[c]) )
6476 continue;
6477
6478 if( !branchAuxNonlinear(scip, conshdlr) )
6479 {
6480 int i;
6481
6482 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6483 * only, so we can loop over variable expressions
6484 */
6485 for( i = 0; i < consdata->nvarexprs; ++i )
6486 {
6487 SCIP_Real violscore;
6488 SCIP_Real lb;
6489 SCIP_Real ub;
6490 SCIP_VAR* var;
6491
6492 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6493
6494 /* skip variable expressions that do not have a violation score */
6495 if( violscore == 0.0 )
6496 continue;
6497
6498 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6499 assert(var != NULL);
6500
6501 lb = SCIPvarGetLbLocal(var);
6502 ub = SCIPvarGetUbLocal(var);
6503
6504 /* consider variable for branching if it has not been fixed yet */
6505 if( !SCIPisEQ(scip, lb, ub) )
6506 {
6507 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6509 *success = TRUE;
6510 }
6511 else
6512 {
6513 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6514 }
6515
6516 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6517 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6518 */
6519 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6520 }
6521 }
6522 else
6523 {
6524 SCIP_EXPR* expr;
6525 SCIP_VAR* var;
6526 SCIP_Real lb;
6527 SCIP_Real ub;
6528 SCIP_Real violscore;
6529
6530 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6531 {
6532 violscore = SCIPgetExprViolScoreNonlinear(expr);
6533 if( violscore == 0.0 )
6534 continue;
6535
6536 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6537 * variable, so this expression should either be an original variable or have an auxiliary variable
6538 */
6540 assert(var != NULL);
6541
6542 lb = SCIPvarGetLbLocal(var);
6543 ub = SCIPvarGetUbLocal(var);
6544
6545 /* consider variable for branching if it has not been fixed yet */
6546 if( !SCIPisEQ(scip, lb, ub) )
6547 {
6548 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6549
6551 *success = TRUE;
6552 }
6553 else
6554 {
6555 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6556 }
6557 }
6558 }
6559 }
6560
6561 if( it != NULL )
6562 SCIPfreeExpriter(&it);
6563
6564 return SCIP_OKAY;
6565}
6566
6567/** collect branching candidates from violated constraints
6568 *
6569 * Fills array with expressions that serve as branching candidates.
6570 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6571 * branching candidate.
6572 *
6573 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6574 * through variable-expressions only.
6575 */
6576static
6578 SCIP* scip, /**< SCIP data structure */
6579 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6580 SCIP_CONS** conss, /**< constraints to process */
6581 int nconss, /**< number of constraints */
6582 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6583 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6584 SCIP_Longint soltag, /**< tag of solution */
6585 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6586 int* ncands /**< number of candidates found */
6587 )
6588{
6589 SCIP_CONSHDLRDATA* conshdlrdata;
6590 SCIP_CONSDATA* consdata;
6591 SCIP_EXPRITER* it = NULL;
6592 int c;
6593 int attempt;
6594 SCIP_VAR* var;
6595
6596 assert(scip != NULL);
6597 assert(conshdlr != NULL);
6598 assert(cands != NULL);
6599 assert(ncands != NULL);
6600
6601 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6602 assert(conshdlrdata != NULL);
6603
6604 if( branchAuxNonlinear(scip, conshdlr) )
6605 {
6608 }
6609
6610 *ncands = 0;
6611 for( attempt = 0; attempt < 2; ++attempt )
6612 {
6613 /* collect branching candidates from violated constraints
6614 * in the first attempt, consider only constraints with large violation
6615 * in the second attempt, consider all remaining violated constraints
6616 */
6617 for( c = 0; c < nconss; ++c )
6618 {
6619 SCIP_Real consviol;
6620
6621 assert(conss != NULL && conss[c] != NULL);
6622
6623 /* consider only violated constraints */
6624 if( !isConsViolated(scip, conss[c]) )
6625 continue;
6626
6627 consdata = SCIPconsGetData(conss[c]);
6628 assert(consdata != NULL);
6629 assert(consdata->varexprs != NULL);
6630
6631 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6632
6633 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6634 continue;
6635 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6636 continue;
6637
6638 if( !branchAuxNonlinear(scip, conshdlr) )
6639 {
6640 int i;
6641
6642 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6643 * only, so we can loop over variable expressions
6644 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6645 * variable, therefore we invalidate the score of a variable after processing it.
6646 */
6647 for( i = 0; i < consdata->nvarexprs; ++i )
6648 {
6649 SCIP_Real lb;
6650 SCIP_Real ub;
6651
6652 /* skip variable expressions that do not have a valid violation score */
6653 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6654 continue;
6655
6656 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6657 assert(var != NULL);
6658
6659 lb = SCIPvarGetLbLocal(var);
6660 ub = SCIPvarGetUbLocal(var);
6661
6662 /* skip already fixed variable */
6663 if( SCIPisEQ(scip, lb, ub) )
6664 {
6665 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6666 continue;
6667 }
6668
6669 assert(*ncands + 1 < SCIPgetNVars(scip));
6670 cands[*ncands].expr = consdata->varexprs[i];
6671 cands[*ncands].var = var;
6672 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6673 ++(*ncands);
6674
6675 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6676 * several times as external branching candidate */
6677 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6678 }
6679 }
6680 else
6681 {
6682 SCIP_EXPR* expr;
6683 SCIP_Real lb;
6684 SCIP_Real ub;
6685
6686 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6687 {
6688 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6689 continue;
6690
6691 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6692 * variables, so this expression should either be an original variable or have an auxiliary variable
6693 */
6695 assert(var != NULL);
6696
6697 lb = SCIPvarGetLbLocal(var);
6698 ub = SCIPvarGetUbLocal(var);
6699
6700 /* skip already fixed variable */
6701 if( SCIPisEQ(scip, lb, ub) )
6702 {
6703 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6704 continue;
6705 }
6706
6707 assert(*ncands + 1 < SCIPgetNVars(scip));
6708 cands[*ncands].expr = expr;
6709 cands[*ncands].var = var;
6710 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6711 ++(*ncands);
6712 }
6713 }
6714 }
6715
6716 /* if we have branching candidates, then we don't need another attempt */
6717 if( *ncands > 0 )
6718 break;
6719 }
6720
6721 if( it != NULL )
6722 SCIPfreeExpriter(&it);
6723
6724 return SCIP_OKAY;
6725}
6726
6727/** computes a branching score for a variable that reflects how important branching on this variable would be for
6728 * improving the dual bound from the LP relaxation
6729 *
6730 * Assume the Lagrangian for the current LP is something of the form
6731 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6732 * where x are the original variables, z the auxiliary variables,
6733 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6734 *
6735 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6736 * If we could have used not only an estimator, but the actual function f(x), then this would
6737 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6738 * Using a lot of handwaving, we claim that
6739 * lambda_i * (f(x) - a_i'x + b_i)
6740 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6741 * If an estimator depended on local bounds, then it could be improved by branching.
6742 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6743 *
6744 * 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.
6745 * To scale, we divide by the LP objective value (if >1).
6746 *
6747 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6748 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6749 *
6750 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6751 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6752 * would also be branching candidates
6753 */
6754static
6756 SCIP* scip, /**< SCIP data structure */
6757 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6758 SCIP_VAR* var /**< variable */
6759 )
6760{
6761 SCIP_COL* col;
6762 SCIP_ROW** rows;
6763 int nrows;
6764 int r;
6765 SCIP_Real dualscore;
6766
6767 assert(scip != NULL);
6768 assert(conshdlr != NULL);
6769 assert(var != NULL);
6770
6771 /* if LP not solved, then the dual branching score is not available */
6773 return 0.0;
6774
6775 /* if var is not in the LP, then the dual branching score is not available */
6777 return 0.0;
6778
6779 col = SCIPvarGetCol(var);
6780 assert(col != NULL);
6781
6782 if( !SCIPcolIsInLP(col) )
6783 return 0.0;
6784
6785 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6786 rows = SCIPcolGetRows(col);
6787
6788 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6789
6790 /* aggregate duals from all rows from consexpr with non-zero dual
6791 * TODO: this is a quick-and-dirty implementation, and not used by default
6792 * in the long run, this should be either removed or replaced by a proper implementation
6793 */
6794 dualscore = 0.0;
6795 for( r = 0; r < nrows; ++r )
6796 {
6797 SCIP_Real estimategap;
6798 const char* estimategapstr;
6799
6800 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6801 * these would typically be local, unless they are created at the root node
6802 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6803 if( !SCIProwIsLocal(rows[r]) )
6804 continue;
6805 */
6806 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6807 continue;
6808 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6809 continue;
6810
6811 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6812 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6813 continue;
6814 estimategap = atof(estimategapstr + 13);
6815 assert(estimategap >= 0.0);
6816 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6817 estimategap = SCIPgetHugeValue(scip);
6818
6819 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6820 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6821
6822 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6823 }
6824
6825 /* divide by optimal value of LP for scaling */
6826 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6827
6828 return dualscore;
6829}
6830
6831/** computes branching scores (including weighted score) for a set of candidates
6832 *
6833 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6834 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6835 *
6836 * For each score, compute the maximum over all candidates.
6837 *
6838 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6839 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6840 * score of all candidates.
6841 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6842 *
6843 * For example:
6844 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6845 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6846 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6847 * - 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.
6848 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6849 */
6850static
6852 SCIP* scip, /**< SCIP data structure */
6853 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6854 BRANCHCAND* cands, /**< branching candidates */
6855 int ncands, /**< number of candidates */
6856 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6857 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6858 )
6859{
6860 SCIP_CONSHDLRDATA* conshdlrdata;
6861 BRANCHCAND maxscore;
6862 int c;
6863
6864 assert(scip != NULL);
6865 assert(conshdlr != NULL);
6866 assert(cands != NULL);
6867 assert(ncands > 0);
6868
6869 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6870 assert(conshdlrdata != NULL);
6871
6872 /* initialize counts to 0 */
6873 memset(&maxscore, 0, sizeof(BRANCHCAND));
6874
6875 for( c = 0; c < ncands; ++c )
6876 {
6877 if( conshdlrdata->branchviolweight > 0.0 )
6878 {
6879 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6880 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6881 }
6882
6883 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarGetType(cands[c].var) <= SCIP_VARTYPE_INTEGER )
6884 {
6885 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
6886 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
6887 */
6888 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
6889
6890 if( considerfracnl && cands[c].fractionality == 0.0 )
6891 {
6892 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
6893 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
6894 */
6895 SCIP_Real solval;
6896 SCIP_Real rounded;
6897
6898 solval = SCIPgetSolVal(scip, NULL, cands[c].var);
6899 rounded = SCIPround(scip, solval);
6900
6901 cands[c].fractionality = REALABS(solval - rounded);
6902 }
6903
6904 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
6905 }
6906 else
6907 cands[c].fractionality = 0.0;
6908
6909 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
6910 {
6911 SCIP_Real domainwidth;
6912 SCIP_VAR* var;
6913
6914 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6915 assert(var != NULL);
6916
6917 /* get domain width, taking infinity at 1e20 on purpose */
6918 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6919
6920 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6921 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6922 * the idea is to penalize very large and very small domains
6923 */
6924 if( domainwidth >= 1.0 )
6925 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6926 else
6927 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6928
6929 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6930 }
6931 else
6932 cands[c].domain = 0.0;
6933
6934 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
6935 {
6936 SCIP_VAR* var;
6937
6938 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6939 assert(var != NULL);
6940
6941 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6942 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6943 }
6944 else
6945 cands[c].dual = 0.0;
6946
6947 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6948 {
6949 SCIP_VAR* var;
6950
6951 var = cands[c].var;
6952 assert(var != NULL);
6953
6954 if( cands[c].expr != NULL )
6955 {
6957 cands[c].pscost = SCIP_INVALID;
6958 else
6959 {
6960 SCIP_Real brpoint;
6961 SCIP_Real pscostdown;
6962 SCIP_Real pscostup;
6963 char strategy;
6964
6965 /* decide how to compute pseudo-cost scores
6966 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
6967 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
6968 */
6970 strategy = conshdlrdata->branchpscostupdatestrategy;
6971 else
6972 strategy = 'l';
6973
6975
6976 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
6977 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
6978 * For here, I use a simple #counts >= branchpscostreliable.
6979 * TODO use SCIPgetVarPseudocostCount() instead?
6980 */
6981 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
6982 {
6983 switch( strategy )
6984 {
6985 case 's' :
6987 break;
6988 case 'd' :
6990 break;
6991 case 'l' :
6993 pscostdown = SCIP_INVALID;
6994 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
6995 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
6996 else
6998 break;
6999 default :
7000 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7001 pscostdown = SCIP_INVALID;
7002 }
7003 }
7004 else
7005 pscostdown = SCIP_INVALID;
7006
7007 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7008 {
7009 switch( strategy )
7010 {
7011 case 's' :
7013 break;
7014 case 'd' :
7016 break;
7017 case 'l' :
7019 pscostup = SCIP_INVALID;
7020 else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7021 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7022 else
7024 break;
7025 default :
7026 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7027 pscostup = SCIP_INVALID;
7028 }
7029 }
7030 else
7031 pscostup = SCIP_INVALID;
7032
7033 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7034 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7035 */
7036 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7037 cands[c].pscost = SCIP_INVALID;
7038 else if( pscostdown == SCIP_INVALID )
7039 cands[c].pscost = pscostup;
7040 else if( pscostup == SCIP_INVALID )
7041 cands[c].pscost = pscostdown;
7042 else
7043 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7044 }
7045 }
7046 else
7047 {
7048 SCIP_Real pscostdown;
7049 SCIP_Real pscostup;
7050 SCIP_Real solval;
7051
7052 solval = SCIPgetSolVal(scip, NULL, cands[c].var);
7053
7054 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7055 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7056 * and different between variable value and rounded up value for pscostup
7057 */
7058 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7059 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7060 else
7061 pscostdown = SCIP_INVALID;
7062
7063 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7064 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7065 else
7066 pscostup = SCIP_INVALID;
7067
7068 /* TODO see above for nonlinear variable case */
7069 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7070 cands[c].pscost = SCIP_INVALID;
7071 else if( pscostdown == SCIP_INVALID )
7072 cands[c].pscost = pscostup;
7073 else if( pscostup == SCIP_INVALID )
7074 cands[c].pscost = pscostdown;
7075 else
7076 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7077 }
7078
7079 if( cands[c].pscost != SCIP_INVALID )
7080 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7081 }
7082 else
7083 cands[c].pscost = SCIP_INVALID;
7084
7085 if( conshdlrdata->branchvartypeweight > 0.0 )
7086 {
7087 switch( SCIPvarGetType(cands[c].var) )
7088 {
7089 case SCIP_VARTYPE_BINARY :
7090 cands[c].vartype = 1.0;
7091 break;
7093 cands[c].vartype = 0.1;
7094 break;
7096 cands[c].vartype = 0.01;
7097 break;
7099 default:
7100 cands[c].vartype = 0.0;
7101 }
7102 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7103 }
7104 }
7105
7106 /* now compute a weighted score for each candidate from the single scores
7107 * the single scores are scaled to be in [0,1] for this
7108 */
7109 for( c = 0; c < ncands; ++c )
7110 {
7111 SCIP_Real weightsum;
7112
7113 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7114
7115 cands[c].weighted = 0.0;
7116 weightsum = 0.0;
7117
7118 if( maxscore.auxviol > 0.0 )
7119 {
7120 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7121 weightsum += conshdlrdata->branchviolweight;
7122
7123 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7124 }
7125
7126 if( maxscore.fractionality > 0.0 )
7127 {
7128 cands[c].fractionality += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7129 weightsum += conshdlrdata->branchfracweight;
7130
7131 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7132 }
7133
7134 if( maxscore.domain > 0.0 )
7135 {
7136 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7137 weightsum += conshdlrdata->branchdomainweight;
7138
7139 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7140 }
7141
7142 if( maxscore.dual > 0.0 )
7143 {
7144 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7145 weightsum += conshdlrdata->branchdualweight;
7146
7147 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7148 }
7149
7150 if( maxscore.pscost > 0.0 )
7151 {
7152 /* use pseudo-costs only if available */
7153 if( cands[c].pscost != SCIP_INVALID )
7154 {
7155 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7156 weightsum += conshdlrdata->branchpscostweight;
7157
7158 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7159 }
7160 else
7161 {
7162 /* do not add pscostscore, if not available, also do not add into weightsum */
7163 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7164 }
7165 }
7166
7167 if( maxscore.vartype > 0.0 )
7168 {
7169 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7170 weightsum += conshdlrdata->branchvartypeweight;
7171
7172 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7173 }
7174
7175 assert(weightsum > 0.0); /* we should have got at least one valid score */
7176 cands[c].weighted /= weightsum;
7177
7178 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7179 }
7180}
7181
7182/** compare two branching candidates by their weighted score
7183 *
7184 * if weighted score is equal, use variable index of (aux)var
7185 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7186 */
7187static
7188SCIP_DECL_SORTINDCOMP(branchcandCompare)
7189{
7190 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7191
7192 if( cands[ind1].weighted != cands[ind2].weighted )
7193 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7194
7195 if( cands[ind1].var != cands[ind2].var )
7196 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7197
7198 return cands[ind1].expr != NULL ? 1 : -1;
7199}
7200
7201/** picks a candidate from array of branching candidates */
7202static
7204 SCIP* scip, /**< SCIP data structure */
7205 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7206 BRANCHCAND* cands, /**< branching candidates */
7207 int ncands, /**< number of candidates */
7208 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7209 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7210)
7211{
7212 SCIP_CONSHDLRDATA* conshdlrdata;
7213 int* perm;
7214 int c;
7215 int left;
7216 int right;
7217 SCIP_Real threshold;
7218
7219 assert(cands != NULL);
7220 assert(ncands >= 1);
7221 assert(selected != NULL);
7222
7223 if( ncands == 1 )
7224 {
7225 *selected = cands;
7226 return SCIP_OKAY;
7227 }
7228
7229 /* if there are more than one candidate, then compute scores and select */
7230
7231 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7232 assert(conshdlrdata != NULL);
7233
7234 /* compute additional scores on branching candidates and weighted score */
7235 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, NULL);
7236
7237 /* sort candidates by weighted score */
7238 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7239 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7240
7241 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7242 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7243 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7244
7245 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7246 left = 0;
7247 right = ncands - 1;
7248 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7249 while( left < right )
7250 {
7251 int mid = (left + right) / 2;
7252 if( cands[perm[mid]].weighted >= threshold )
7253 left = mid + 1;
7254 else
7255 right = mid;
7256 }
7257 assert(left <= ncands);
7258
7259 if( left < ncands )
7260 {
7261 if( cands[perm[left]].weighted >= threshold )
7262 {
7263 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7264 ncands = left + 1;
7265 }
7266 else
7267 {
7268 assert(cands[perm[left]].weighted < threshold);
7269 ncands = left;
7270 }
7271 }
7272 assert(ncands > 0);
7273
7274 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7275 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7276 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7277
7278 if( ncands > 1 )
7279 {
7280 /* choose at random from candidates 0..ncands-1 */
7281 if( conshdlrdata->branchrandnumgen == NULL )
7282 {
7283 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7284 }
7285 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7286 *selected = &cands[perm[c]];
7287 }
7288 else
7289 *selected = &cands[perm[0]];
7290
7291 SCIPfreeBufferArray(scip, &perm);
7292
7293 return SCIP_OKAY;
7294}
7295
7296/** do spatial branching or register branching candidates */
7297static
7299 SCIP* scip, /**< SCIP data structure */
7300 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7301 SCIP_CONS** conss, /**< constraints to process */
7302 int nconss, /**< number of constraints */
7303 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7304 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7305 SCIP_Longint soltag, /**< tag of solution */
7306 SCIP_RESULT* result /**< pointer to store the result of branching */
7307 )
7308{
7309 SCIP_CONSHDLRDATA* conshdlrdata;
7310 BRANCHCAND* cands;
7311 int ncands;
7312 BRANCHCAND* selected = NULL;
7313 SCIP_NODE* downchild;
7314 SCIP_NODE* eqchild;
7315 SCIP_NODE* upchild;
7316
7317 assert(conshdlr != NULL);
7318 assert(result != NULL);
7319
7321
7322 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7323 assert(conshdlrdata != NULL);
7324
7325 if( conshdlrdata->branchexternal )
7326 {
7327 /* just register branching candidates as external */
7328 SCIP_Bool success;
7329
7330 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7331 if( success )
7333
7334 return SCIP_OKAY;
7335 }
7336
7337 /* collect branching candidates and their auxviol-score */
7339 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7340
7341 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7342 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7343 */
7344 if( ncands == 0 )
7345 goto TERMINATE;
7346
7347 /* here we include fractionality of integer variables into the branching score
7348 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7349 */
7350 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, SCIPgetNLPBranchCands(scip) > 0, &selected) );
7351 assert(selected != NULL);
7352 assert(selected->expr != NULL);
7353
7354 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7355 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7356
7357 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7358 &upchild) );
7359 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7361 else
7362 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7364
7365 TERMINATE:
7366 SCIPfreeBufferArray(scip, &cands);
7367
7368 return SCIP_OKAY;
7369}
7370
7371/** call enforcement or estimate callback of nonlinear handler
7372 *
7373 * Calls the enforcement callback, if available.
7374 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7375 *
7376 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7377 */
7378static
7380 SCIP* scip, /**< SCIP main data structure */
7381 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7382 SCIP_CONS* cons, /**< nonlinear constraint */
7383 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7384 SCIP_EXPR* expr, /**< expression */
7385 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7386 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7387 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7388 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7389 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7390 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7391 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7392 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7393 SCIP_RESULT* result /**< pointer to store the result */
7394 )
7395{
7396 assert(result != NULL);
7397
7398 /* call enforcement callback of the nlhdlr */
7399 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7400 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7401
7402 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7404 {
7405 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7406 SCIPnlhdlrGetName(nlhdlr), *result); )
7407 return SCIP_OKAY;
7408 }
7409 else
7410 {
7411 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7412 }
7413
7415
7416 /* now call the estimator callback of the nlhdlr */
7417 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7418 {
7419 SCIP_VAR* auxvar;
7420 SCIP_Bool sepasuccess = FALSE;
7421 SCIP_Bool branchscoresuccess = FALSE;
7422 SCIP_PTRARRAY* rowpreps;
7423 int minidx;
7424 int maxidx;
7425 int r;
7426 SCIP_ROWPREP* rowprep;
7427
7428 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7429
7430 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7431 assert(auxvar != NULL);
7432
7433 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7434 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7435
7436 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7437 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7438
7439 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7440
7441 if( !sepasuccess )
7442 {
7443 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7444 SCIPnlhdlrGetName(nlhdlr)); )
7445 }
7446
7447 for( r = minidx; r <= maxidx; ++r )
7448 {
7449 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7450
7451 assert(rowprep != NULL);
7453
7454 if( !branchcandonly )
7455 {
7456 /* complete estimator to cut */
7457 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7458
7459 /* add the cut and/or branching scores
7460 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7461 */
7462 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7463 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7464 }
7465
7466 SCIPfreeRowprep(scip, &rowprep);
7467 }
7468
7469 if( branchcandonly && branchscoresuccess )
7470 {
7471 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7473 }
7474
7475 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7476 }
7477
7478 return SCIP_OKAY;
7479}
7480
7481/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7482 *
7483 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7484 */
7485static
7487 SCIP* scip, /**< SCIP data structure */
7488 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7489 SCIP_CONS* cons, /**< nonlinear constraint */
7490 SCIP_EXPR* expr, /**< expression */
7491 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7492 SCIP_Longint soltag, /**< tag of solution */
7493 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7494 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7495 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7496 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7497 )
7498{
7499 SCIP_CONSHDLRDATA* conshdlrdata;
7500 SCIP_EXPR_OWNERDATA* ownerdata;
7501 SCIP_Real origviol;
7502 SCIP_Bool underestimate;
7503 SCIP_Bool overestimate;
7504 SCIP_Real auxviol;
7505 SCIP_Bool auxunderestimate;
7506 SCIP_Bool auxoverestimate;
7507 SCIP_RESULT hdlrresult;
7508 int e;
7509
7510 assert(scip != NULL);
7511 assert(expr != NULL);
7512 assert(result != NULL);
7513
7514 ownerdata = SCIPexprGetOwnerData(expr);
7515 assert(ownerdata != NULL);
7516 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7517
7519
7520 /* make sure that this expression has been evaluated */
7521 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7522
7523 /* decide whether under- or overestimate is required and get amount of violation */
7524 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7525
7526 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7527 assert(conshdlrdata != NULL);
7528
7529 /* no sufficient violation w.r.t. the original variables -> skip expression */
7530 if( !overestimate && !underestimate )
7531 {
7532 return SCIP_OKAY;
7533 }
7534
7535 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7536 for( e = 0; e < ownerdata->nenfos; ++e )
7537 {
7538 SCIP_NLHDLR* nlhdlr;
7539
7540 /* skip nlhdlr that do not want to participate in any separation */
7541 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7542 continue;
7543
7544 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7545 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7546 continue;
7547
7548 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7549 assert(nlhdlr != NULL);
7550
7551 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7552 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7553 ENFOLOG(
7554 SCIPinfoMessage(scip, enfologfile, " expr ");
7555 SCIPprintExpr(scip, expr, enfologfile);
7556 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7557 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7558 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7559 )
7560
7561 /* TODO if expr is root of constraint (consdata->expr == expr),
7562 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7563 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7564 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7565 * so we should enforce in these auxiliaries first
7566 * if changing this here, we must also adapt analyzeViolation()
7567 */
7568
7569 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7570 assert(auxviol >= 0.0);
7571
7572 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7573 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7574 {
7575 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7576 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7577 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7578
7579 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7580 continue;
7581 }
7582
7583 /* 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 */
7584 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7585 {
7586 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7587 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7588 underestimate, overestimate); )
7589
7590 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7591 continue;
7592 }
7593
7594 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7595 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7596 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7597
7598 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7599 * wants to be called for separation on this side, then call separation of nlhdlr
7600 */
7601 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7602 {
7603 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7604 hdlrresult = SCIP_DIDNOTFIND;
7605 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7606 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7607
7608 if( hdlrresult == SCIP_CUTOFF )
7609 {
7610 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7612 ownerdata->lastenforced = conshdlrdata->enforound;
7613 break;
7614 }
7615
7616 if( hdlrresult == SCIP_SEPARATED )
7617 {
7618 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7620 ownerdata->lastenforced = conshdlrdata->enforound;
7621 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7622 break;
7623 }
7624
7625 if( hdlrresult == SCIP_REDUCEDDOM )
7626 {
7627 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7629 ownerdata->lastenforced = conshdlrdata->enforound;
7630 /* TODO or should we always just stop here? */
7631 }
7632
7633 if( hdlrresult == SCIP_BRANCHED )
7634 {
7635 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7636 assert(inenforcement);
7637
7638 /* separation and domain reduction takes precedence over branching */
7640 if( *result == SCIP_DIDNOTFIND )
7642 ownerdata->lastenforced = conshdlrdata->enforound;
7643 }
7644 }
7645
7646 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7647 * wants to be called for separation on this side, then call separation of nlhdlr
7648 */
7649 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7650 {
7651 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7652 hdlrresult = SCIP_DIDNOTFIND;
7653 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7654 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7655
7656 if( hdlrresult == SCIP_CUTOFF )
7657 {
7658 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7660 ownerdata->lastenforced = conshdlrdata->enforound;
7661 break;
7662 }
7663
7664 if( hdlrresult == SCIP_SEPARATED )
7665 {
7666 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7668 ownerdata->lastenforced = conshdlrdata->enforound;
7669 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7670 break;
7671 }
7672
7673 if( hdlrresult == SCIP_REDUCEDDOM )
7674 {
7675 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7677 ownerdata->lastenforced = conshdlrdata->enforound;
7678 /* TODO or should we always just stop here? */
7679 }
7680
7681 if( hdlrresult == SCIP_BRANCHED )
7682 {
7683 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7684 assert(inenforcement);
7685
7686 /* separation takes precedence over branching */
7688 if( *result == SCIP_DIDNOTFIND )
7690 ownerdata->lastenforced = conshdlrdata->enforound;
7691 }
7692 }
7693 }
7694
7695 return SCIP_OKAY;
7696}
7697
7698/** helper function to enforce a single constraint */
7699static
7701 SCIP* scip, /**< SCIP data structure */
7702 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7703 SCIP_CONS* cons, /**< constraint to process */
7704 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7705 SCIP_Longint soltag, /**< tag of solution */
7706 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7707 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7708 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7709 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7710 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7711 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7712 )
7713{
7714 SCIP_CONSDATA* consdata;
7715 SCIP_CONSHDLRDATA* conshdlrdata;
7716 SCIP_EXPR* expr;
7717
7718 assert(conshdlr != NULL);
7719 assert(cons != NULL);
7720 assert(it != NULL);
7721 assert(result != NULL);
7722 assert(success != NULL);
7723
7724 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7725 assert(conshdlrdata != NULL);
7726
7727 consdata = SCIPconsGetData(cons);
7728 assert(consdata != NULL);
7729 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7730
7731 *success = FALSE;
7732
7733 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7734 {
7735 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7736 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7737 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7738 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7739 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7740 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7741 * confuse the stalling check for how long to do separation).
7742 */
7743 SCIP_Bool infeasible;
7744 int ntightenings;
7745
7746 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7747 if( infeasible )
7748 {
7750 return SCIP_OKAY;
7751 }
7752 /* if we tightened an auxvar bound, we better communicate that */
7753 if( ntightenings > 0 )
7755 }
7756
7757 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7758 {
7759 SCIP_EXPR_OWNERDATA* ownerdata;
7760 SCIP_RESULT resultexpr;
7761
7762 ownerdata = SCIPexprGetOwnerData(expr);
7763 assert(ownerdata != NULL);
7764
7765 /* we can only enforce if there is an auxvar to compare with */
7766 if( ownerdata->auxvar == NULL )
7767 continue;
7768
7769 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7770 if( ownerdata->lastenforced == conshdlrdata->enforound )
7771 {
7772 ENFOLOG(
7773 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7774 SCIPprintExpr(scip, expr, enfologfile);
7775 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7776 )
7777 *success = TRUE;
7778 continue;
7779 }
7780
7781 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7782
7783 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7784 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7785 if( ownerdata->lastenforced == conshdlrdata->enforound )
7786 *success = TRUE;
7787
7788 if( resultexpr == SCIP_CUTOFF )
7789 {
7791 break;
7792 }
7793
7794 if( resultexpr == SCIP_SEPARATED )
7796
7797 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7799
7800 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7802 }
7803
7804 return SCIP_OKAY;
7805}
7806
7807/** try to separate violated constraints and, if in enforcement, register branching scores
7808 *
7809 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7810 *
7811 * Sets result to
7812 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7813 * - SCIP_CUTOFF, if node can be cutoff,
7814 * - SCIP_SEPARATED, if a cut has been added,
7815 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7816 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7817 * - SCIP_INFEASIBLE, if external branching candidates were registered
7818 */
7819static
7821 SCIP* scip, /**< SCIP data structure */
7822 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7823 SCIP_CONS** conss, /**< constraints to process */
7824 int nconss, /**< number of constraints */
7825 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7826 SCIP_Longint soltag, /**< tag of solution */
7827 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7828 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7829 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7830 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7831 )
7832{
7833 SCIP_CONSHDLRDATA* conshdlrdata;
7834 SCIP_EXPRITER* it;
7835 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7836 int c;
7837
7838 assert(conshdlr != NULL);
7839 assert(conss != NULL || nconss == 0);
7840 assert(result != NULL);
7841
7842 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7843 assert(conshdlrdata != NULL);
7844
7845 /* increase tag to tell whether branching scores in expression belong to this sweep
7846 * and which expressions have already been enforced in this sweep
7847 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7848 */
7849 ++(conshdlrdata->enforound);
7850
7852
7855
7856 for( c = 0; c < nconss; ++c )
7857 {
7858 assert(conss != NULL && conss[c] != NULL);
7859
7860 /* skip constraints that are not enabled or deleted */
7861 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7862 continue;
7863 assert(SCIPconsIsActive(conss[c]));
7864
7865 /* skip constraints that have separation disabled if we are only in separation */
7866 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7867 continue;
7868
7869 /* skip non-violated constraints */
7870 if( !isConsViolated(scip, conss[c]) )
7871 continue;
7872
7873 ENFOLOG(
7874 {
7875 SCIP_CONSDATA* consdata;
7876 int i;
7877 consdata = SCIPconsGetData(conss[c]);
7878 assert(consdata != NULL);
7879 SCIPinfoMessage(scip, enfologfile, " constraint ");
7880 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7881 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7882 for( i = 0; i < consdata->nvarexprs; ++i )
7883 {
7884 SCIP_VAR* var;
7885 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7886 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7888 }
7889 })
7890
7891 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
7892
7893 if( *result == SCIP_CUTOFF )
7894 break;
7895
7896 if( !consenforced && inenforcement && !branchcandonly )
7897 {
7898 SCIP_Real viol;
7899
7900 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7901 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7902 {
7903 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7904 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7905
7906 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
7907
7908 if( consenforced )
7909 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7910
7911 if( *result == SCIP_CUTOFF )
7912 break;
7913 }
7914 }
7915 }
7916
7917 SCIPfreeExpriter(&it);
7918
7919 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7920
7921 if( *result == SCIP_BRANCHED && !branchcandonly )
7922 {
7923 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7924 * branching
7925 */
7926 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7927
7928 /* branching should either have branched: result == SCIP_BRANCHED,
7929 * or fixed a variable: result == SCIP_REDUCEDDOM,
7930 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7931 * or have not done anything: result == SCIP_DIDNOTFIND
7932 */
7934 }
7935
7936 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7937
7938 return SCIP_OKAY;
7939}
7940
7941/** decide whether to branch on fractional integer or nonlinear variable
7942 *
7943 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
7944 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
7945 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
7946 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
7947 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
7948 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
7949 */
7950static
7952 SCIP* scip, /**< SCIP data structure */
7953 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7954 SCIP_CONS** conss, /**< constraints to process */
7955 int nconss, /**< number of constraints */
7956 SCIP_Longint soltag, /**< tag of LP solution */
7957 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7958 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
7959 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
7960 )
7961{
7963 int nlpcands;
7964 SCIP_VAR** lpcands; /* fractional integer variables */
7965 SCIP_Real* lpcandsfrac; /* fractionalities */
7966 BRANCHCAND* cands;
7967 BRANCHCAND* selected;
7968 int ncands;
7969 int c;
7970
7971 assert(scip != NULL);
7972 assert(conshdlr != NULL);
7973 assert(conss != NULL);
7974 assert(nconss > 0);
7975 assert(branchintegral != NULL);
7976 assert(cutoff != NULL);
7977
7978 *branchintegral = FALSE;
7979 *cutoff = FALSE;
7980
7982 return SCIP_OKAY;
7983
7984 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
7985 switch( result )
7986 {
7987 case SCIP_DIDNOTFIND:
7988 /* no branching candidates found could mean that the LP solution is in a convex region */
7989 *branchintegral = TRUE;
7990 return SCIP_OKAY;
7991
7992 case SCIP_CUTOFF:
7993 /* probably cannot happen, but easy to handle */
7994 *cutoff = TRUE;
7995 return SCIP_OKAY;
7996
7997 case SCIP_SEPARATED:
7998 case SCIP_REDUCEDDOM:
7999 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8000 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8001 return SCIP_ERROR;
8002
8003 case SCIP_BRANCHED:
8004 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8005 break;
8006
8007 case SCIP_INFEASIBLE:
8008 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8009 * but this was disabled by branchcandonly = TRUE)
8010 */
8011 default:
8012 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8013 return SCIP_ERROR;
8014 } /*lint !e788*/
8015
8016 /* collect spatial branching candidates and their auxviol-score */
8018 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8019
8020 /* add fractional integer variables to branching candidates */
8022
8023 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8024
8025 for( c = 0; c < nlpcands; ++c )
8026 {
8029 cands[ncands].expr = NULL;
8030 cands[ncands].var = lpcands[c];
8031 cands[ncands].auxviol = 0.0;
8032 cands[ncands].fractionality = lpcandsfrac[c];
8033 ++ncands;
8034 }
8035
8036 /* select a variable for branching
8037 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8038 * the same variables appear among the candides for branching on integrality, where its fractionality is considered
8039 */
8040 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, &selected) );
8041 assert(selected != NULL);
8042
8043 if( selected->expr == NULL )
8044 {
8045 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8046
8047 *branchintegral = TRUE;
8048 }
8049
8050 SCIPfreeBufferArray(scip, &cands);
8051
8052 return SCIP_OKAY;
8053}
8054
8055/** decide whether to consider spatial branching before integrality has been enforced
8056 *
8057 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8058 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8059 *
8060 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8061 */
8062static
8064 SCIP* scip, /**< SCIP data structure */
8065 SCIP_CONSHDLR* conshdlr /**< constraint handler */
8066)
8067{
8068 SCIP_CONSHDLRDATA* conshdlrdata;
8069
8070 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8071 assert(conshdlrdata != NULL);
8072
8073 /* if LP still unbounded, then work on nonlinear constraints first */
8075 return FALSE;
8076
8077 /* no branching in cons_integral if no fractional integer variables */
8079 return FALSE;
8080
8081 /* branchmixfractional being infinity means that integral should always go first */
8082 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8083 return TRUE;
8084
8085 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8086 if( conshdlrdata->branchmixfractional == 0.0 )
8087 return FALSE;
8088
8089 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8090 * @todo this gives the total pseudocost count divided by the number of discrete variables
8091 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8092 */
8093 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8094 return TRUE;
8095 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8096 return TRUE;
8097
8098 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8099 return FALSE;
8100}
8101
8102/** collect (and print (if debugging enfo)) information on violation in expressions
8103 *
8104 * assumes that constraint violations have been computed
8105 */
8106static
8108 SCIP* scip, /**< SCIP data structure */
8109 SCIP_CONS** conss, /**< constraints */
8110 int nconss, /**< number of constraints */
8111 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8112 SCIP_Longint soltag, /**< tag of solution */
8113 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8114 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8115 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8116 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8117 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8118 )
8119{
8120 SCIP_CONSDATA* consdata;
8121 SCIP_EXPRITER* it;
8122 SCIP_EXPR* expr;
8123 SCIP_Real v;
8124 int c;
8125
8126 assert(conss != NULL || nconss == 0);
8127 assert(maxabsconsviol != NULL);
8128 assert(maxrelconsviol != NULL);
8129 assert(maxauxviol != NULL);
8130 assert(maxvarboundviol != NULL);
8131
8134
8135 *maxabsconsviol = 0.0;
8136 *maxrelconsviol = 0.0;
8137 *minauxviol = SCIPinfinity(scip);
8138 *maxauxviol = 0.0;
8139 *maxvarboundviol = 0.0;
8140
8141 for( c = 0; c < nconss; ++c )
8142 {
8143 assert(conss != NULL && conss[c] != NULL);
8144
8145 consdata = SCIPconsGetData(conss[c]);
8146 assert(consdata != NULL);
8147
8148 /* skip constraints that are not enabled, deleted, or have separation disabled */
8149 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8150 continue;
8151 assert(SCIPconsIsActive(conss[c]));
8152
8153 v = getConsAbsViolation(conss[c]);
8154 *maxabsconsviol = MAX(*maxabsconsviol, v);
8155
8156 /* skip non-violated constraints */
8157 if( !isConsViolated(scip, conss[c]) )
8158 continue;
8159
8160 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8161 *maxrelconsviol = MAX(*maxrelconsviol, v);
8162
8163 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8164 {
8165 SCIP_EXPR_OWNERDATA* ownerdata;
8166 SCIP_Real auxvarvalue;
8167 SCIP_Real auxvarlb;
8168 SCIP_Real auxvarub;
8169 SCIP_Bool violunder;
8170 SCIP_Bool violover;
8171 SCIP_Real origviol;
8172 SCIP_Real auxviol;
8173 int e;
8174
8175 ownerdata = SCIPexprGetOwnerData(expr);
8176 assert(ownerdata != NULL);
8177
8178 if( ownerdata->auxvar == NULL )
8179 {
8180 /* check violation of variable bounds of original variable */
8181 if( SCIPisExprVar(scip, expr) )
8182 {
8183 SCIP_VAR* var;
8184 var = SCIPgetVarExprVar(expr);
8185 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8186 auxvarlb = SCIPvarGetLbLocal(var);
8187 auxvarub = SCIPvarGetUbLocal(var);
8188
8189 origviol = 0.0;
8190 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8191 origviol = auxvarlb - auxvarvalue;
8192 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8193 origviol = auxvarvalue - auxvarub;
8194 if( origviol <= 0.0 )
8195 continue;
8196
8197 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8198
8199 ENFOLOG(
8200 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8201 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8202 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8203 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8204 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8205 SCIPinfoMessage(scip, enfologfile, "\n");
8206 )
8207 }
8208
8209 continue;
8210 }
8211
8212 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8213 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8214 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8215
8216 /* check violation of variable bounds of auxiliary variable */
8217 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8218 *maxvarboundviol = auxvarlb - auxvarvalue;
8219 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8220 *maxvarboundviol = auxvarvalue - auxvarub;
8221
8222 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8223
8224 ENFOLOG(
8225 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8226 {
8227 SCIPinfoMessage(scip, enfologfile, "expr ");
8228 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8229 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8230
8231 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8232 if( origviol > 0.0 )
8233 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8234 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8235 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8236 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8237 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8238 SCIPinfoMessage(scip, enfologfile, "\n");
8239 }
8240 )
8241
8242 /* no violation w.r.t. the original variables -> skip expression */
8243 if( origviol == 0.0 )
8244 continue;
8245
8246 /* compute aux-violation for each nonlinear handlers */
8247 for( e = 0; e < ownerdata->nenfos; ++e )
8248 {
8249 SCIP_NLHDLR* nlhdlr;
8250
8251 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8252 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8253 continue;
8254
8255 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8256 assert(nlhdlr != NULL);
8257
8258 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8259 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8260
8261 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8262
8263 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8264
8265 if( auxviol > 0.0 )
8266 {
8267 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8268 *maxauxviol = MAX(*maxauxviol, auxviol);
8269 *minauxviol = MIN(*minauxviol, auxviol);
8270 }
8271 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8272 }
8273 }
8274 }
8275
8276 SCIPfreeExpriter(&it);
8277
8278 return SCIP_OKAY;
8279} /*lint !e715*/
8280
8281/** enforcement of constraints called by enfolp and enforelax */
8282static
8284 SCIP* scip, /**< SCIP data structure */
8285 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8286 SCIP_CONS** conss, /**< constraints to process */
8287 int nconss, /**< number of constraints */
8288 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8289 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8290 )
8291{
8292 SCIP_CONSHDLRDATA* conshdlrdata;
8293 SCIP_Real maxabsconsviol;
8294 SCIP_Real maxrelconsviol;
8295 SCIP_Real minauxviol;
8296 SCIP_Real maxauxviol;
8297 SCIP_Real maxvarboundviol;
8298 SCIP_Longint soltag;
8299 SCIP_Bool branchintegral;
8300 int nnotify;
8301 int c;
8302
8303 if( sol == NULL && branchingIntegralFirst(scip, conshdlr) )
8304 {
8305 /* let cons_integral handle enforcement */
8307 return SCIP_OKAY;
8308 }
8309
8310 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8311 assert(conshdlr != NULL);
8312
8313 soltag = SCIPgetExprNewSoltag(scip);
8314
8316 for( c = 0; c < nconss; ++c )
8317 {
8318 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8319
8320 if( isConsViolated(scip, conss[c]) )
8322 }
8323
8324 if( *result == SCIP_FEASIBLE )
8325 {
8326 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8328 return SCIP_OKAY;
8329 }
8330
8331 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8332 &minauxviol, &maxauxviol, &maxvarboundviol) );
8333
8334 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8335 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8336 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8337 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8338
8339 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8340
8341 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8342 if( sol == NULL )
8343 {
8344 SCIP_Bool cutoff;
8345
8346 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8347 if( cutoff )
8348 {
8350 return SCIP_OKAY;
8351 }
8352 if( branchintegral )
8353 {
8354 /* let cons_integral handle enforcement */
8356 return SCIP_OKAY;
8357 }
8358 }
8359
8360 /* try to propagate */
8361 if( conshdlrdata->propinenforce )
8362 {
8363 SCIP_RESULT propresult;
8364 int nchgbds = 0;
8365
8366 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8367
8368 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8369 {
8370 *result = propresult;
8371 return SCIP_OKAY;
8372 }
8373 }
8374
8375 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8376 * all violated expr/auxvar in violated constraints)
8377 */
8378 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8379 sol == NULL )
8380 {
8381 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8382 ++conshdlrdata->ntightenlp;
8383
8385
8386 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8387 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8388
8389 return SCIP_OKAY;
8390 }
8391
8392 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8393 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8394 */
8395 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8396 {
8397 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8398 ++conshdlrdata->ntightenlp;
8399
8401
8402 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8403
8404 return SCIP_OKAY;
8405 }
8406
8407 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8408
8411 return SCIP_OKAY;
8412
8414
8415 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8416 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8417
8418 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8419 {
8420 /* if there are still fractional integer variables, then let cons_integral go first */
8422 return SCIP_OKAY;
8423 }
8424
8425 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8426 {
8427 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8428 ++conshdlrdata->ntightenlp;
8429
8431
8432 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8433 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8434
8435 return SCIP_OKAY;
8436 }
8437
8438 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8439 SCIPgetLPFeastol(scip)) && sol == NULL )
8440 {
8441 /* try whether tighten the LP feasibility tolerance could help
8442 * maybe it is just some cut that hasn't been taken into account sufficiently
8443 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8444 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8445 * until the LP feastol reaches epsilon
8446 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8447 * when maxauxviol is above LP feastol)
8448 */
8449 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8450 ++conshdlrdata->ndesperatetightenlp;
8451
8453
8454 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8455
8456 return SCIP_OKAY;
8457 }
8458
8459 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8460 if( !conshdlrdata->propinenforce )
8461 {
8462 SCIP_RESULT propresult;
8463 int nchgbds = 0;
8464
8465 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8466
8467 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8468 {
8469 *result = propresult;
8470 return SCIP_OKAY;
8471 }
8472 }
8473
8474 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8475 * now look if we find any unfixed variable that we could still branch on
8476 */
8477 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8478
8479 if( nnotify > 0 )
8480 {
8481 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8482 ++conshdlrdata->ndesperatebranch;
8483
8484 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8485
8486 return SCIP_OKAY;
8487 }
8488
8489 /* if everything is fixed in violated constraints, then let's cut off the node
8490 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8491 * result may not be conclusive (when constraint violations are small)
8492 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8493 * sufficiently (see st_e40)
8494 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8495 * not "desperate", but a pretty obvious thing to do
8496 */
8497 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8499
8500 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8501 if( !SCIPisZero(scip, maxvarboundviol) )
8502 ++conshdlrdata->ndesperatecutoff;
8503
8504 return SCIP_OKAY;
8505}
8506
8507/** separation for all violated constraints to be used by SEPA callbacks */
8508static
8510 SCIP* scip, /**< SCIP data structure */
8511 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8512 SCIP_CONS** conss, /**< constraints to process */
8513 int nconss, /**< number of constraints */
8514 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8515 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8516 )
8517{
8518 SCIP_Longint soltag;
8519 SCIP_Bool haveviol = FALSE;
8520 int c;
8521
8523
8524 soltag = SCIPgetExprNewSoltag(scip);
8525
8526 /* compute violations */
8527 for( c = 0; c < nconss; ++c )
8528 {
8529 assert(conss[c] != NULL);
8530
8531 /* skip constraints that are not enabled, deleted, or have separation disabled */
8532 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8533 continue;
8534 assert(SCIPconsIsActive(conss[c]));
8535
8536 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8537
8538 if( isConsViolated(scip, conss[c]) )
8539 haveviol = TRUE;
8540 }
8541
8542 /* if none of our constraints are violated, don't attempt separation */
8543 if( !haveviol )
8544 {
8545 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8546 return SCIP_OKAY;
8547 }
8548
8549 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8550
8551 /* call separation */
8552 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8553
8554 return SCIP_OKAY;
8555}
8556
8557/** hash key retrieval function for bilinear term entries */
8558static
8559SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8560{ /*lint --e{715}*/
8561 SCIP_CONSHDLRDATA* conshdlrdata;
8562 int idx;
8563
8564 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8565 assert(conshdlrdata != NULL);
8566
8567 idx = ((int)(size_t)elem) - 1;
8568 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8569
8570 return (void*)&conshdlrdata->bilinterms[idx];
8571}
8572
8573/** returns TRUE iff the bilinear term entries are equal */
8574static
8575SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8576{ /*lint --e{715}*/
8579
8580 /* get corresponding entries */
8581 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8582 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8583 assert(entry1->x != NULL && entry1->y != NULL);
8584 assert(entry2->x != NULL && entry2->y != NULL);
8585 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8586 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8587
8588 return entry1->x == entry2->x && entry1->y == entry2->y;
8589}
8590
8591/** returns the hash value of the key */
8592static
8593SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8594{ /*lint --e{715}*/
8596
8597 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8598 assert(entry->x != NULL && entry->y != NULL);
8599 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8600
8601 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8602}
8603
8604/** compare two auxiliary expressions
8605 *
8606 * Compares auxiliary variables, followed by coefficients, and then constants.
8607 */
8608static
8610{
8613 int compvars;
8614 int i;
8615
8616 /* compare the auxiliary variables */
8617 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8618
8619 if( compvars != 0 )
8620 return compvars;
8621
8622 /* compare the coefficients and constants */
8623 for( i = 0; i < 3; ++i )
8624 {
8625 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8626 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8627 }
8628
8629 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8630}
8631
8632/* add an auxiliary expression to a bilinear term */
8633static
8635 SCIP* scip, /**< SCIP data structure */
8636 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8637 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8638 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8639 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8640 )
8641{
8642 SCIP_Bool found;
8643 int pos;
8644 int i;
8645
8646 *added = FALSE;
8647
8648 /* check if auxexpr has already been added to term */
8649 if( term->nauxexprs == 0 )
8650 {
8651 found = FALSE;
8652 pos = 0;
8653 }
8654 else
8655 {
8656 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8657 }
8658
8659 if( !found )
8660 {
8661 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8662 return SCIP_OKAY;
8663
8665 assert(term->auxexprssize >= term->nauxexprs + 1);
8666
8667 /* insert expression at the correct position */
8668 for( i = term->nauxexprs; i > pos; --i )
8669 {
8670 term->aux.exprs[i] = term->aux.exprs[i-1];
8671 }
8672 term->aux.exprs[pos] = auxexpr;
8673 ++(term->nauxexprs);
8674 *added = TRUE;
8675 }
8676 else
8677 {
8678 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8679 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8680 }
8681
8682 return SCIP_OKAY;
8683}
8684
8685/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8686static
8688 SCIP* scip, /**< SCIP data structure */
8689 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8690 SCIP_CONS** conss, /**< nonlinear constraints */
8691 int nconss /**< total number of nonlinear constraints */
8692 )
8693{
8694 SCIP_CONSHDLRDATA* conshdlrdata;
8695 SCIP_EXPRITER* it;
8696 int c;
8697
8698 assert(conss != NULL || nconss == 0);
8699
8700 if( nconss == 0 )
8701 return SCIP_OKAY;
8702
8703 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8704 assert(conshdlrdata != NULL);
8705
8706 /* check whether the bilinear terms have been stored already */
8707 if( conshdlrdata->bilinterms != NULL )
8708 return SCIP_OKAY;
8709
8710 /* create and initialize iterator */
8714
8715 /* iterate through all constraints */
8716 for( c = 0; c < nconss; ++c )
8717 {
8718 SCIP_CONSDATA* consdata;
8719 SCIP_EXPR* expr;
8720
8721 assert(conss != NULL && conss[c] != NULL);
8722 consdata = SCIPconsGetData(conss[c]);
8723 assert(consdata != NULL);
8724
8725 /* iterate through all expressions */
8726 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8727 {
8728 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8729 SCIP_VAR* x = NULL;
8730 SCIP_VAR* y = NULL;
8731
8732 /* check whether the expression is of the form f(..)^2 */
8733 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8734 {
8735 x = SCIPgetExprAuxVarNonlinear(children[0]);
8736 y = x;
8737 }
8738 /* check whether the expression is of the form f(..) * g(..) */
8739 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8740 {
8741 x = SCIPgetExprAuxVarNonlinear(children[0]);
8742 y = SCIPgetExprAuxVarNonlinear(children[1]);
8743 }
8744
8745 /* add variables to the hash table */
8746 if( x != NULL && y != NULL )
8747 {
8750 }
8751 }
8752 }
8753
8754 /* release iterator */
8755 SCIPfreeExpriter(&it);
8756
8757 return SCIP_OKAY;
8758}
8759
8760/** store x, y and the locks in a new bilinear term */
8761static
8763 SCIP* scip, /**< SCIP data structure */
8764 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8765 SCIP_VAR* x, /**< the first variable */
8766 SCIP_VAR* y, /**< the second variable */
8767 int nlockspos, /**< number of positive locks of the bilinear term */
8768 int nlocksneg, /**< number of negative locks of the bilinear term */
8769 int* idx, /**< pointer to store the position of the term in bilinterms array */
8770 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8771 )
8772{
8773 SCIP_CONSHDLRDATA* conshdlrdata;
8775
8776 assert(conshdlr != NULL);
8777 assert(x != NULL);
8778 assert(y != NULL);
8779 assert(nlockspos >= 0);
8780 assert(nlocksneg >= 0);
8781
8782 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8783 assert(conshdlrdata != NULL);
8784
8785 /* ensure that x.index <= y.index */
8786 if( SCIPvarCompare(x, y) == 1 )
8787 {
8788 SCIPswapPointers((void**)&x, (void**)&y);
8789 }
8790 assert(SCIPvarCompare(x, y) < 1);
8791
8792 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8793
8794 /* update or create the term */
8795 if( *idx >= 0 )
8796 { /* the term has already been added */
8797 assert(conshdlrdata->bilinterms[*idx].x == x);
8798 assert(conshdlrdata->bilinterms[*idx].y == y);
8799
8800 /* get term and add locks */
8801 term = &conshdlrdata->bilinterms[*idx];
8802 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8803 term->nlockspos += nlockspos;
8804 term->nlocksneg += nlocksneg;
8805 }
8806 else
8807 { /* this is the first time we encounter this product */
8808 /* ensure size of bilinterms array */
8809 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8810
8811 *idx = conshdlrdata->nbilinterms;
8812
8813 /* get term and set values in the created bilinear term */
8814 term = &conshdlrdata->bilinterms[*idx];
8815 assert(term != NULL);
8816 term->x = x;
8817 term->y = y;
8818 term->nauxexprs = 0;
8819 term->auxexprssize = 0;
8820 term->nlockspos = nlockspos;
8821 term->nlocksneg = nlocksneg;
8822 term->existing = existing;
8823 if( existing )
8824 term->aux.var = NULL;
8825 else
8826 term->aux.exprs = NULL;
8827
8828 /* increase the total number of bilinear terms */
8829 ++(conshdlrdata->nbilinterms);
8830
8831 /* save to the hashtable */
8832 if( conshdlrdata->bilinhashtable == NULL )
8833 {
8834 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8835 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8836 (void*)conshdlrdata) );
8837 }
8838 assert(conshdlrdata->bilinhashtable != NULL);
8839
8840 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8841 * because zero can not be inserted into hash table
8842 */
8843 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8844
8845 /* capture product variables */
8848 }
8849
8850 return SCIP_OKAY;
8851}
8852
8853/** frees array of bilinear terms and hash table */
8854static
8856 SCIP* scip, /**< SCIP data structure */
8857 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8858 )
8859{
8860 int i;
8861 int j;
8862
8863 assert(conshdlrdata != NULL);
8864
8865 /* check whether bilinear terms have been stored */
8866 if( conshdlrdata->bilinterms == NULL )
8867 {
8868 assert(conshdlrdata->bilinterms == NULL);
8869 assert(conshdlrdata->nbilinterms == 0);
8870 assert(conshdlrdata->bilintermssize == 0);
8871
8872 return SCIP_OKAY;
8873 }
8874
8875 /* release variables */
8876 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8877 {
8878 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8879 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8880
8881 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8882 {
8883 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8884 {
8885 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8886 }
8887 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8888 }
8889
8890 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8891 {
8892 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8893 continue;
8894 }
8895
8896 /* the rest is for simple terms with a single auxvar */
8897
8898 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8899 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8900 {
8901 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8902 }
8903 }
8904
8905 /* free hash table */
8906 if( conshdlrdata->bilinhashtable != NULL )
8907 {
8908 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8909 }
8910
8911 /* free bilinterms array; reset counters */
8912 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8913 conshdlrdata->nbilinterms = 0;
8914 conshdlrdata->bilintermssize = 0;
8915
8916 return SCIP_OKAY;
8917}
8918
8919/*
8920 * vertex polyhedral separation
8921 */
8922
8923/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8924static
8926 SCIP* scip, /**< SCIP data structure */
8927 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8928 SCIP_LPI** lp /**< pointer to store created LP */
8929 )
8930{
8931 SCIP_Real* obj;
8932 SCIP_Real* lb;
8933 SCIP_Real* ub;
8934 SCIP_Real* val;
8935 int* beg;
8936 int* ind;
8937 unsigned int nnonz;
8938 unsigned int ncols;
8939 unsigned int nrows;
8940 unsigned int i;
8941 unsigned int k;
8942
8943 assert(scip != NULL);
8944 assert(lp != NULL);
8945 assert(nvars > 0);
8947
8948 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8949
8950 /* create lpi to store the LP */
8952
8953 nrows = (unsigned int)nvars + 1;
8954 ncols = POWEROFTWO((unsigned int)nvars);
8955 nnonz = (ncols * (nrows + 1)) / 2;
8956
8957 /* allocate necessary memory; set obj, lb, and ub to zero */
8960 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8961 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8962 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8963 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8964
8965 /* calculate nonzero entries in the LP */
8966 for( i = 0, k = 0; i < ncols; ++i )
8967 {
8968 int row;
8969 unsigned int a;
8970
8971 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8972 ub[i] = SCIPlpiInfinity(*lp);
8973
8974 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8975 beg[i] = (int)k;
8976 row = 0;
8977
8978 /* iterate through the bit representation of i */
8979 a = 1;
8980 while( a <= i )
8981 {
8982 if( (a & i) != 0 )
8983 {
8984 val[k] = 1.0;
8985 ind[k] = row;
8986
8987 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8988
8989 ++k;
8990 }
8991
8992 a <<= 1;
8993 ++row;
8994 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8995 assert(POWEROFTWO(row) == a);
8996 }
8997
8998 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8999 val[k] = 1.0;
9000 ind[k] = (int)nrows - 1;
9001 ++k;
9002 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9003 }
9004 assert(k == nnonz);
9005
9006 /* load all data into LP interface
9007 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9008 */
9009 assert(nrows <= ncols);
9011 (int)ncols, obj, lb, ub, NULL,
9012 (int)nrows, lb, lb, NULL,
9013 (int)nnonz, beg, ind, val) );
9014
9015 /* for the last row, we can set the rhs to 1.0 already */
9016 ind[0] = (int)nrows - 1;
9017 val[0] = 1.0;
9018 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9019
9020 /* free allocated memory */
9027
9028 return SCIP_OKAY;
9029}
9030
9031/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9032 * \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
9033 * set of vertices of the domain
9034 */
9035static
9037 SCIP* scip, /**< SCIP data structure */
9038 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9039 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9040 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9041 int nallvars, /**< number of all variables */
9042 int nvars, /**< number of unfixed variables */
9043 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9044 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9045 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9046 )
9047{
9048 SCIP_Real maxerror;
9049 SCIP_Real facetval;
9050 SCIP_Real funval;
9051 SCIP_Real error;
9052 unsigned int i;
9053 unsigned int ncorners;
9054 unsigned int prev;
9055
9056 assert(scip != NULL);
9057 assert(funvals != NULL);
9058 assert(box != NULL);
9059 assert(nonfixedpos != NULL);
9060 assert(facetcoefs != NULL);
9061
9062 ncorners = POWEROFTWO(nvars);
9063 maxerror = 0.0;
9064
9065 /* check the origin (all variables at lower bound) */
9066 facetval = facetconstant;
9067 for( i = 0; i < (unsigned int) nallvars; ++i )
9068 facetval += facetcoefs[i] * box[2*i];
9069
9070 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9071 funval = funvals[0];
9072 if( overestimate )
9073 error = funval - facetval;
9074 else
9075 error = facetval - funval;
9076
9077 /* update maximum error */
9078 maxerror = MAX(error, maxerror);
9079
9080 prev = 0;
9081 for( i = 1; i < ncorners; ++i )
9082 {
9083 unsigned int gray;
9084 unsigned int diff;
9085 unsigned int pos;
9086 int origpos;
9087
9088 gray = i ^ (i >> 1);
9089 diff = gray ^ prev;
9090
9091 /* compute position of unique 1 of diff */
9092 pos = 0;
9093 while( (diff >>= 1) != 0 )
9094 ++pos;
9095 assert(pos < (unsigned int)nvars);
9096
9097 origpos = nonfixedpos[pos];
9098
9099 if( gray > prev )
9100 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9101 else
9102 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9103
9104 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9105 funval = funvals[gray];
9106 if( overestimate )
9107 error = funval - facetval;
9108 else
9109 error = facetval - funval;
9110
9111 /* update maximum error */
9112 maxerror = MAX(error, maxerror);
9113
9114 prev = gray;
9115 }
9116
9117 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9118
9119 return maxerror;
9120}
9121
9122/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9123static
9125 SCIP* scip, /**< SCIP data structure */
9126 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9127 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9128 SCIP_Real* xstar, /**< point to be separated */
9129 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9130 int nallvars, /**< half of the length of box */
9131 int* nonfixedpos, /**< indices of nonfixed variables */
9132 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9133 int nvars, /**< number of nonfixed variables */
9134 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9135 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9136 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9137 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9138 )
9139{ /*lint --e{715}*/
9140 SCIP_CONSHDLRDATA* conshdlrdata;
9141 SCIP_LPI* lp;
9142 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9143 int* inds;
9144 int ncols;
9145 int nrows;
9146 int i;
9147 SCIP_Real facetvalue;
9148 SCIP_Real mindomwidth;
9149 SCIP_RETCODE lpsolveretcode;
9150
9151 assert(scip != NULL);
9152 assert(conshdlr != NULL);
9153 assert(xstar != NULL);
9154 assert(box != NULL);
9155 assert(nonfixedpos != NULL);
9156 assert(funvals != NULL);
9157 assert(nvars >= 0);
9159 assert(success != NULL);
9160 assert(facetcoefs != NULL);
9161 assert(facetconstant != NULL);
9162
9163 *success = FALSE;
9164
9165 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9166 assert(conshdlrdata != NULL);
9167
9168 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9169 {
9170 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9171 }
9172
9173 /* construct an LP for this size, if not having one already */
9174 if( conshdlrdata->vp_lp[nvars] == NULL )
9175 {
9176 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9177 }
9178 lp = conshdlrdata->vp_lp[nvars];
9179 assert(lp != NULL);
9180
9181 /* get number of cols and rows of separation lp */
9182 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9183 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9184
9185 /* number of columns should equal the number of corners = 2^nvars */
9186 assert(ncols == (int)POWEROFTWO(nvars));
9187
9188 /* allocate necessary memory */
9189 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9190 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9191
9192 /*
9193 * set up the described LP on the transformed space
9194 */
9195
9196 for( i = 0; i < ncols; ++i )
9197 inds[i] = i;
9198
9199 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9200 mindomwidth = 2*SCIPinfinity(scip);
9201 for( i = 0; i < nrows-1; ++i )
9202 {
9203 SCIP_Real solval;
9204 SCIP_Real lb;
9205 SCIP_Real ub;
9206 int varpos;
9207
9208 assert(i < nvars);
9209
9210 varpos = nonfixedpos[i];
9211 lb = box[2 * varpos];
9212 ub = box[2 * varpos + 1];
9213 solval = xstar[varpos];
9214
9215 if( ub - lb < mindomwidth )
9216 mindomwidth = ub - lb;
9217
9218 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9219 if( solval <= lb )
9220 aux[i] = 0.0;
9221 else if( solval >= ub )
9222 aux[i] = 1.0;
9223 else
9224 aux[i] = (solval - lb) / (ub - lb);
9225
9226 /* perturb point to hopefully obtain a facet of the convex envelope */
9227 if( conshdlrdata->vp_maxperturb > 0.0 )
9228 {
9229 assert(conshdlrdata->vp_randnumgen != NULL);
9230
9231 if( aux[i] == 1.0 )
9232 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9233 else if( aux[i] == 0.0 )
9234 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9235 else
9236 {
9237 SCIP_Real perturbation;
9238
9239 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9240 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9241 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9242 }
9243 assert(0.0 < aux[i] && aux[i] < 1.0);
9244 }
9245
9246 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9247 }
9248
9249 /* update LP */
9250 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9251 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9253
9254 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9255 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9256 {
9257 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9258 }
9259 /* set an iteration limit so we do not run forever */
9261 /* 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 */
9263 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9264 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9265 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9266 */
9268
9269#ifdef SCIP_DEBUG
9271#endif
9272
9273 /*
9274 * solve the LP and store the resulting facet for the transformed space
9275 */
9276 if( conshdlrdata->vp_dualsimplex )
9277 {
9278 lpsolveretcode = SCIPlpiSolveDual(lp);
9279 }
9280 else
9281 {
9282 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9283 }
9284 if( lpsolveretcode == SCIP_LPERROR )
9285 {
9286 SCIPdebugMsg(scip, "LP error, aborting.\n");
9287 goto CLEANUP;
9288 }
9289 SCIP_CALL( lpsolveretcode );
9290
9291 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9292 if( !SCIPlpiIsDualFeasible(lp) )
9293 {
9294 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9295 goto CLEANUP;
9296 }
9297
9298 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9299 * columns than needed, in particular, \bar \beta is the last dual multiplier
9300 */
9301 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9302
9303 for( i = 0; i < nvars; ++i )
9304 facetcoefs[nonfixedpos[i]] = aux[i];
9305 /* last dual multiplier is the constant */
9306 *facetconstant = aux[nrows - 1];
9307
9308#ifdef SCIP_DEBUG
9309 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9310 for( i = 0; i < nallvars; ++i )
9311 {
9312 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9313 }
9314 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9315#endif
9316
9317 /*
9318 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9319 */
9320
9321 SCIPdebugMsg(scip, "facet in orig. space: ");
9322
9323 facetvalue = 0.0;
9324 for( i = 0; i < nvars; ++i )
9325 {
9326 SCIP_Real lb;
9327 SCIP_Real ub;
9328 int varpos;
9329
9330 varpos = nonfixedpos[i];
9331 lb = box[2 * varpos];
9332 ub = box[2 * varpos + 1];
9333 assert(!SCIPisEQ(scip, lb, ub));
9334
9335 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9336 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9337
9338 /* beta = beta_bar - sum_i alpha_i * lb_i */
9339 *facetconstant -= facetcoefs[varpos] * lb;
9340
9341 /* evaluate */
9342 facetvalue += facetcoefs[varpos] * xstar[varpos];
9343
9344 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9345 }
9346 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9347
9348 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9349 facetvalue += *facetconstant;
9350
9351 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9352
9353 /* if overestimate, then we want facetvalue < targetvalue
9354 * if underestimate, then we want facetvalue > targetvalue
9355 * if none holds, give up
9356 * so maybe here we should check against the minimal violation
9357 */
9358 if( overestimate == (facetvalue > targetvalue) )
9359 {
9360 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9361 goto CLEANUP;
9362 }
9363
9364 /* if we made it until here, then we have a nice facet */
9365 *success = TRUE;
9366
9367CLEANUP:
9368 /* free allocated memory */
9369 SCIPfreeBufferArray(scip, &inds);
9371
9372 return SCIP_OKAY;
9373}
9374
9375/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9376 *
9377 * In other words, compute the line that passes through two given points.
9378 */
9379static
9381 SCIP* scip, /**< SCIP data structure */
9382 SCIP_Real left, /**< left coordinate */
9383 SCIP_Real right, /**< right coordinate */
9384 SCIP_Real funleft, /**< value of function in left coordinate */
9385 SCIP_Real funright, /**< value of function in right coordinate */
9386 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9387 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9388 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9389 )
9390{
9391 assert(scip != NULL);
9392 assert(SCIPisLE(scip, left, right));
9393 assert(!SCIPisInfinity(scip, -left));
9394 assert(!SCIPisInfinity(scip, right));
9395 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9396 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9397 assert(success != NULL);
9398 assert(facetcoef != NULL);
9399 assert(facetconstant != NULL);
9400
9401 *facetcoef = (funright - funleft) / (right - left);
9402 *facetconstant = funleft - *facetcoef * left;
9403
9404 *success = TRUE;
9405
9406 return SCIP_OKAY;
9407}
9408
9409/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9410 *
9411 * Three points a, b, and c are given.
9412 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9413 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9414 */
9415static
9417 SCIP* scip, /**< SCIP data structure */
9418 SCIP_Real a1, /**< first coordinate of a */
9419 SCIP_Real a2, /**< second coordinate of a */
9420 SCIP_Real a3, /**< third coordinate of a */
9421 SCIP_Real b1, /**< first coordinate of b */
9422 SCIP_Real b2, /**< second coordinate of b */
9423 SCIP_Real b3, /**< third coordinate of b */
9424 SCIP_Real c1, /**< first coordinate of c */
9425 SCIP_Real c2, /**< second coordinate of c */
9426 SCIP_Real c3, /**< third coordinate of c */
9427 SCIP_Real* alpha, /**< coefficient of first coordinate */
9428 SCIP_Real* beta, /**< coefficient of second coordinate */
9429 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9430 SCIP_Real* delta /**< constant right-hand side */
9431 )
9432{
9433 assert(scip != NULL);
9434 assert(alpha != NULL);
9435 assert(beta != NULL);
9436 assert(gamma_ != NULL);
9437 assert(delta != NULL);
9438
9439 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9440 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9441 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9442 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9443
9444 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9445
9446 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9447 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9448 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9449 {
9450 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9451 *delta = 0.0;
9452 *alpha = 0.0;
9453 *beta = 0.0;
9454 *gamma_ = 0.0;
9455 return SCIP_OKAY;
9456 }
9457
9458 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9459 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9460 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9461 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9462 {
9463 SCIP_Real m[9];
9464 SCIP_Real rhs[3];
9465 SCIP_Real x[3];
9466 SCIP_Bool success;
9467
9468 /*
9469 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));
9470 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));
9471 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));
9472 */
9473
9474 /* initialize matrix column-wise */
9475 m[0] = a1;
9476 m[1] = b1;
9477 m[2] = c1;
9478 m[3] = a2;
9479 m[4] = b2;
9480 m[5] = c2;
9481 m[6] = a3;
9482 m[7] = b3;
9483 m[8] = c3;
9484
9485 rhs[0] = 1.0;
9486 rhs[1] = 1.0;
9487 rhs[2] = 1.0;
9488
9489 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9490
9491 /* solve the linear problem */
9492 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9493
9494 *delta = rhs[0];
9495 *alpha = x[0];
9496 *beta = x[1];
9497 *gamma_ = x[2];
9498
9499 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9500 * not add a cut to SCIP and that all assertions are trivially fulfilled
9501 */
9502 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9503 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9504 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9505 {
9506 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9507 *delta = 0.0;
9508 *alpha = 0.0;
9509 *beta = 0.0;
9510 *gamma_ = 0.0;
9511 }
9512 }
9513
9514 if( *gamma_ < 0.0 )
9515 {
9516 *alpha = -*alpha;
9517 *beta = -*beta;
9518 *gamma_ = -*gamma_;
9519 *delta = -*delta;
9520 }
9521
9522 return SCIP_OKAY;
9523}
9524
9525/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9526static
9528 SCIP* scip, /**< SCIP data structure */
9529 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9530 SCIP_Real p1[2], /**< first vertex of box */
9531 SCIP_Real p2[2], /**< second vertex of box */
9532 SCIP_Real p3[2], /**< third vertex of box */
9533 SCIP_Real p4[2], /**< forth vertex of box */
9534 SCIP_Real p1val, /**< value in p1 */
9535 SCIP_Real p2val, /**< value in p2 */
9536 SCIP_Real p3val, /**< value in p3 */
9537 SCIP_Real p4val, /**< value in p4 */
9538 SCIP_Real xstar[2], /**< point to be separated */
9539 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9540 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9541 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9542 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9543 )
9544{
9545 SCIP_Real alpha, beta, gamma_, delta;
9546 SCIP_Real xstarval, candxstarval = 0.0;
9547 int leaveout;
9548
9549 assert(scip != NULL);
9550 assert(success != NULL);
9551 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9552 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9553 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9554 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9555 assert(facetcoefs != NULL);
9556 assert(facetconstant != NULL);
9557
9558 *success = FALSE;
9559
9560 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9561 if( !overestimate )
9562 {
9563 p1val = -p1val;
9564 p2val = -p2val;
9565 p3val = -p3val;
9566 p4val = -p4val;
9567 targetvalue = -targetvalue;
9568 }
9569
9570 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9571 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9572 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9573 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9574
9575 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9576 * alpha*x + beta*y + gamma*z = delta
9577 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9578 * the fourth corner point lies below this hyperplane.
9579 * 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.,
9580 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9581 * or, equivalently,
9582 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9583 */
9584 for( leaveout = 1; leaveout <= 4; ++leaveout )
9585 {
9586 switch( leaveout)
9587 {
9588 case 1 :
9589 /* get hyperplane through p2, p3, p4 */
9590 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9591 &alpha, &beta, &gamma_, &delta) );
9592 /* if not underestimating in p1, then go to next candidate */
9593 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9594 continue;
9595 break;
9596
9597 case 2 :
9598 /* get hyperplane through p1, p3, p4 */
9599 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9600 &alpha, &beta, &gamma_, &delta) );
9601 /* if not underestimating in p2, then go to next candidate */
9602 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9603 continue;
9604 break;
9605
9606 case 3 :
9607 /* get hyperplane through p1, p2, p4 */
9608 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9609 &alpha, &beta, &gamma_, &delta) );
9610 /* if not underestimating in p3, then go to next candidate */
9611 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9612 continue;
9613 break;
9614
9615 case 4 :
9616 /* get hyperplane through p1, p2, p3 */
9617 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9618 &alpha, &beta, &gamma_, &delta) );
9619 /* if not underestimating in p4, then stop */
9620 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9621 continue;
9622 break;
9623
9624 default: /* only for lint */
9626 beta = SCIP_INVALID;
9627 gamma_ = SCIP_INVALID;
9628 delta = SCIP_INVALID;
9629 break;
9630 }
9631
9632 /* check if bad luck: should not happen if numerics are fine */
9633 if( SCIPisZero(scip, gamma_) )
9634 continue;
9635 assert(!SCIPisNegative(scip, gamma_));
9636
9637 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9638 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9639 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9640 continue;
9641
9642 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9643
9644 /* value of hyperplane candidate in xstar */
9645 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9646
9647 /* if reaching target and first or better than previous candidate, then update */
9648 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9649 {
9650 /* flip hyperplane */
9651 if( !overestimate )
9652 gamma_ = -gamma_;
9653
9654 facetcoefs[0] = -alpha/gamma_;
9655 facetcoefs[1] = -beta/gamma_;
9656 *facetconstant = delta/gamma_;
9657
9658 *success = TRUE;
9659 candxstarval = xstarval;
9660 }
9661 }
9662
9663 return SCIP_OKAY;
9664}
9665
9666/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9667 * graph yet) in an array
9668 */
9669static
9671 SCIP* scip, /**< SCIP pointer */
9672 int** openidx, /**< address of openidx array */
9673 int nelems, /**< number of elements that need to be stored */
9674 int* maxnelems /**< pointer to store maximum number that can be stored */
9675 )
9676{
9677 assert(scip != NULL);
9678 assert(openidx != NULL);
9679 assert(maxnelems != NULL);
9680
9681 if( nelems > *maxnelems )
9682 {
9683 int newsize;
9684
9685 newsize = SCIPcalcMemGrowSize(scip, nelems);
9686 assert(newsize >= nelems);
9687
9688 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9689
9690 *maxnelems = newsize;
9691 }
9692
9693 return SCIP_OKAY;
9694}
9695
9696/** ensures that we can store information about local variables in an array */
9697static
9699 SCIP* scip, /**< SCIP pointer */
9700 SCIP_VAR*** vars, /**< address of variable array */
9701 SCIP_Real** vals, /**< address of value array */
9702 int nelems, /**< number of elements that need to be stored */
9703 int* maxnelems /**< pointer to store maximum number that can be stored */
9704 )
9705{
9706 assert(scip != NULL);
9707 assert(vars != NULL);
9708 assert(vals != NULL);
9709 assert(maxnelems != NULL);
9710
9711 if( nelems > *maxnelems )
9712 {
9713 int newsize;
9714
9715 newsize = SCIPcalcMemGrowSize(scip, nelems);
9716 assert(newsize > *maxnelems);
9717
9719 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9720
9721 *maxnelems = newsize;
9722 }
9723
9724 return SCIP_OKAY;
9725}
9726
9727/** tries to add gadget for finding signed permutations of bilinear products
9728 *
9729 * If a product has exactly two children being variables, negating both simultanteoulsy
9730 * is a signed permutation.
9731 */
9732static
9734 SCIP* scip, /**< SCIP pointer */
9735 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9736 SCIP_CONS* cons, /**< constraint containing product expression */
9737 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9738 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9739 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9740 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9741 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9742 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9743 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9744 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9745 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9746 )
9747{
9748 SYM_EXPRDATA* symdata;
9749 SCIP_EXPR** children;
9750 SCIP_VAR* var1 = NULL;
9751 SCIP_VAR* var2 = NULL;
9752 SCIP_Real val1 = 0.0;
9753 SCIP_Real val2 = 0.0;
9754 SCIP_Real coef;
9755 SCIP_Real prodval;
9756 SCIP_Real constant;
9757 int nlocvars;
9758 int optype;
9759 int nchildren;
9760 int prodidx;
9761 int coefidx1;
9762 int coefidx2;
9763 int childidx;
9764
9765 assert(scip != NULL);
9766 assert(expr != NULL);
9768 assert(graph != NULL);
9769 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9770 assert(consvars != NULL);
9771 assert(consvals != NULL);
9772 assert(maxnconsvars != NULL);
9773 assert(*maxnconsvars > 0);
9774 assert(handledexprs != NULL);
9775 assert(success != NULL);
9776
9777 *success = FALSE;
9778
9779 /* we require exactly two children being variables */
9780 nchildren = SCIPexprGetNChildren(expr);
9781 if( nchildren != 2 )
9782 return SCIP_OKAY;
9783
9784 children = SCIPexprGetChildren(expr);
9785 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9786 return SCIP_OKAY;
9787
9788 /* check whether each child is not multi-aggregated and is not shifted */
9789 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9790
9791 for( childidx = 0; childidx < 2; ++childidx )
9792 {
9793 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9794 (*consvals)[0] = 1.0;
9795 nlocvars = 1;
9796 constant = 0.0;
9797
9798 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9799 &constant, SCIPconsIsTransformed(cons)) );
9800
9801 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9802 return SCIP_OKAY;
9803
9804 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9805 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9806 return SCIP_OKAY;
9807
9808 /* store information about variables */
9809 if( childidx == 0 )
9810 {
9811 var1 = (*consvars)[0];
9812 val1 = (*consvals)[0];
9813 }
9814 else
9815 {
9816 var2 = (*consvars)[0];
9817 val2 = (*consvals)[0];
9818 }
9819 }
9820 assert(var1 != NULL);
9821 assert(var2 != NULL);
9822
9823 /* store the we handle the children */
9824 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9825 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9826
9827 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9828 assert(symdata != NULL);
9829 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9830
9831 coef = SCIPgetSymExprdataConstants(symdata)[0];
9832
9833 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9834
9835 /* add gadget modeling the product
9836 *
9837 * Since the constants are 0, each variable is centered at the origin, which leads to
9838 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9839 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9840 * negate both variables simulataneously.
9841 */
9843 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9844 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9845
9846 prodval = coef * val1 * val2;
9847
9848 /* introduce nodes for the product value and its negation; since flipping both variables
9849 * simultaneously is a signed symmetry, assign both nodes the same value
9850 */
9851 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
9852 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
9853
9854 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
9855 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
9856 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
9857
9858 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9859 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9860 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9861 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9862 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9863 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9864 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9865 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9866
9867 *success = TRUE;
9868
9869 return SCIP_OKAY;
9870}
9871
9872/** returns whether an operator is even and, if yes, stores data about operator */
9873static
9875 SCIP* scip, /**< SCIP pointer */
9876 SCIP_EXPR* expr, /**< expression corresponding to operator */
9877 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
9878 * needed for symmetry computation */
9879 SCIP_Real* value /**< pointer to store value for symmetry computation */
9880 )
9881{
9882 SYM_EXPRDATA* symdata;
9883
9884 assert(scip != NULL);
9885 assert(expr != NULL);
9886 assert(hasvalue != NULL);
9887 assert(value != NULL);
9888
9889 /* check for different operators known to be even */
9890 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9891 {
9892 /* get remaining information needed for symmetry detection */
9893 if( SCIPisExprSignpower(scip, expr) )
9894 {
9895 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9896 assert(symdata != NULL);
9897 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9898
9899 *value = SCIPgetSymExprdataConstants(symdata)[0];
9900 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9901
9903 }
9904 else
9905 {
9906 assert(SCIPisExprCos(scip, expr));
9907 *hasvalue = FALSE;
9908 }
9909
9910 return TRUE;
9911 }
9912 else if( SCIPisExprPower(scip, expr) )
9913 {
9914 SCIP_Real exponent;
9915 int safeexponent;
9916
9917 /* only consider expressions corresponding to an even power */
9918 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9919 assert(symdata != NULL);
9920 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9921
9922 exponent = SCIPgetSymExprdataConstants(symdata)[0];
9924
9925 /* check whether the exponent is an even integer */
9926 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
9927 return FALSE;
9928
9929 /* deal with numerics */
9930 safeexponent = (int) (exponent + 0.5);
9931 if( safeexponent % 2 != 0 )
9932 return FALSE;
9933
9934 *hasvalue = TRUE;
9935 *value = exponent;
9936
9937 return TRUE;
9938 }
9939 else if( SCIPisExprAbs(scip, expr) )
9940 {
9941 *hasvalue = FALSE;
9942
9943 return TRUE;
9944 }
9945
9946 return FALSE;
9947}
9948
9949/** returns whether a variable is centered at 0 */
9950static
9952 SCIP* scip, /**< SCIP pointer */
9953 SCIP_VAR* var /**< variable to be checked */
9954 )
9955{
9956 assert(scip != NULL);
9957 assert(var != NULL);
9958
9960 return FALSE;
9961
9963 return TRUE;
9964
9966 return TRUE;
9967
9968 return FALSE;
9969}
9970
9971/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
9972static
9974 SCIP* scip, /**< SCIP pointer */
9975 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
9976 SCIP_EXPR* child, /**< child expression of evenopexpr */
9977 SCIP_CONS* cons, /**< constraint containing expression */
9978 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9979 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9980 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9981 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9982 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
9983 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
9984 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9985 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9986 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9987 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9988 )
9989{
9990 SCIP_VAR* var;
9991 SCIP_Real constant;
9992 SCIP_Real edgeweight;
9993 int nlocvars;
9994 int nodeidx;
9995 int optype;
9996 int thisopidx;
9997
9998 assert(scip != NULL);
9999 assert(evenopexpr != NULL);
10000 assert(child != NULL);
10001 assert(SCIPisExprVar(scip, child));
10002 assert(cons != NULL);
10003 assert(graph != NULL);
10004 assert(parentidx >= 0);
10005 assert(consvars != NULL);
10006 assert(consvals != NULL);
10007 assert(maxnconsvars != NULL);
10008 assert(success != NULL);
10009
10010 *success = FALSE;
10011
10012 /* check whether child variable is (multi-)aggregated */
10013 var = SCIPgetVarExprVar(child);
10014 (*consvars)[0] = var;
10015 (*consvals)[0] = 1.0;
10016 constant = 0.0;
10017 nlocvars = 1;
10018
10019 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10020 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10021 SCIPconsIsTransformed(cons)) );
10022
10023 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10024 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10025 return SCIP_OKAY;
10026
10027 if( !varIsCenteredAt0(scip, var) )
10028 return SCIP_OKAY;
10029
10030 /* store partial information for gadget */
10031 var = (*consvars)[0];
10032 edgeweight = (*consvals)[0];
10033
10034 /* add gadget to graph for even univariate expression */
10035 *success = TRUE;
10036
10038
10039 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10040 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10041
10043 TRUE, edgeweight) );
10045 TRUE, edgeweight) );
10046
10047 if( hassymval )
10048 {
10049 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10050 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10051 }
10052
10053 return SCIP_OKAY;
10054}
10055
10056/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10057static
10059 SCIP* scip, /**< SCIP pointer */
10060 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10061 SCIP_EXPR* child, /**< child expression of evenopexpr */
10062 SCIP_CONS* cons, /**< constraint containing expression */
10063 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10064 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10065 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10066 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10067 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10068 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10069 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10070 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10071 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10072 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10073 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10074 )
10075{
10076 SCIP_VAR* var;
10077 SCIP_Real constant;
10078 SCIP_Real weight;
10079 int nlocvars;
10080 int nodeidx;
10081 int optype;
10082 int thisopidx;
10083 int i;
10084
10085 assert(scip != NULL);
10086 assert(evenopexpr != NULL);
10087 assert(child != NULL);
10088 assert(SCIPisExprSum(scip, child));
10089 assert(cons != NULL);
10090 assert(graph != NULL);
10091 assert(parentidx >= 0);
10092 assert(consvars != NULL);
10093 assert(consvals != NULL);
10094 assert(maxnconsvars != NULL);
10095 assert(handledexprs != NULL);
10096 assert(success != NULL);
10097
10098 *success = FALSE;
10099
10100 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10101 nlocvars = SCIPexprGetNChildren(child);
10102
10103 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10104
10105 for( i = 0; i < nlocvars; ++i)
10106 {
10107 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10108 {
10109 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10110 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10111 }
10112 else
10113 return SCIP_OKAY;
10114 }
10115 constant = SCIPgetConstantExprSum(child);
10116
10117 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10118 SCIPconsIsTransformed(cons)) );
10119
10120 /* we can only handle the case without constant and two variables with domain centered at origin */
10121 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10122 return SCIP_OKAY;
10123 assert(nlocvars > 0);
10124
10125 var = (*consvars)[0];
10126 if( !varIsCenteredAt0(scip, var) )
10127 return SCIP_OKAY;
10128
10129 if( nlocvars == 2 )
10130 {
10131 var = (*consvars)[1];
10132 if( !varIsCenteredAt0(scip, var) )
10133 return SCIP_OKAY;
10134 }
10135
10136 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10137 *success = TRUE;
10138 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10139 {
10140 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10141 }
10142
10144
10145 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10146 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10147
10148 if( hassymval )
10149 {
10150 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10151 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10152 }
10153
10154 if( nlocvars == 1 )
10155 {
10156 var = (*consvars)[0];
10157 weight = (*consvals)[0];
10158
10160 TRUE, weight) );
10162 TRUE, weight) );
10163 }
10164 else
10165 {
10166 int dummyidx1;
10167 int dummyidx2;
10168
10169 /* add dummy nodes for gadget */
10170 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10171 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10172
10173 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10174 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10175 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10176
10177 /* connect dummy nodes with variables */
10178 for( i = 0; i < 2; ++i)
10179 {
10180 var = (*consvars)[i];
10181 weight = ABS((*consvals)[i]);
10182
10184 TRUE, weight) );
10186 TRUE, weight) );
10187 }
10188 }
10189
10190 return SCIP_OKAY;
10191}
10192
10193/** tries to add gadget for finding signed permutations of even univariate operators
10194 *
10195 * We handle two cases. First, if a univariate operator is even and has a variable
10196 * as child, negating the child is signed permutation. Second, the univariate operator
10197 * is even and has a weighted sum of two variables as child.
10198 */
10199static
10201 SCIP* scip, /**< SCIP pointer */
10202 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10203 SCIP_CONS* cons, /**< constraint containing expression */
10204 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10205 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10206 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10207 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10208 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10209 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10210 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10211 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10212 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10213 )
10214{
10215 SCIP_EXPR* child;
10216 SCIP_Real val = 0.0;
10217 SCIP_Bool hasval = FALSE;
10218
10219 assert(scip != NULL);
10220 assert(expr != NULL);
10221 assert(graph != NULL);
10222 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10223 assert(consvars != NULL);
10224 assert(consvals != NULL);
10225 assert(maxnconsvars != NULL);
10226 assert(*maxnconsvars > 0);
10227 assert(handledexprs != NULL);
10228 assert(success != NULL);
10229
10230 *success = FALSE;
10231
10232 /* ignore variable or value expressions */
10233 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10234 return SCIP_OKAY;
10235 assert(SCIPexprGetNChildren(expr) > 0);
10236
10237 /* ignore operators with too many children */
10238 if( SCIPexprGetNChildren(expr) > 1 )
10239 return SCIP_OKAY;
10240
10241 /* check whether operator is even */
10242 if( !isEvenOperator(scip, expr, &hasval, &val) )
10243 return SCIP_OKAY;
10244
10245 /* we can only treat the operator if its child is a variable or a sum */
10246 child = SCIPexprGetChildren(expr)[0];
10247 if( SCIPisExprVar(scip, child) )
10248 {
10249 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10250 hasval, val, consvars, consvals, maxnconsvars, success) );
10251 }
10252 else if( SCIPisExprSum(scip, child) )
10253 {
10254 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10255 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10256 }
10257
10258 if( *success )
10259 {
10260 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10261 }
10262
10263 return SCIP_OKAY;
10264}
10265
10266/** compares two variable pointers */
10267static
10269{ /*lint --e{715}*/
10270 SCIP_VAR** vars;
10271 SCIP_VAR* var1;
10272 SCIP_VAR* var2;
10273
10274 vars = (SCIP_VAR**) dataptr;
10275
10276 var1 = vars[ind1];
10277 var2 = vars[ind2];
10278 assert(var1 != NULL);
10279 assert(var2 != NULL);
10280
10281 /* sort variables by their unique index */
10282 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10283 return -1;
10284 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10285 return 1;
10286
10287 return 0;
10288}
10289
10290/** gets domain center of a variable which has not semi-infinite domain */
10291static
10293 SCIP* scip, /**< SCIP pointer */
10294 SCIP_VAR* var /**< variable */
10295 )
10296{
10297 SCIP_Real ub;
10298 SCIP_Real lb;
10299
10300 ub = SCIPvarGetUbGlobal(var);
10301 lb = SCIPvarGetLbGlobal(var);
10302
10303 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10304
10305 if ( SCIPisInfinity(scip, ub) )
10306 return 0.0;
10307
10308 return (ub + lb) / 2;
10309}
10310
10311/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10312static
10314 SCIP* scip, /**< SCIP pointer */
10315 SCIP_EXPR* sumexpr, /**< sum expression */
10316 SCIP_CONS* cons, /**< constraint containing the sum expression */
10317 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10318 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10319 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10320 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10321 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10322 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10323 )
10324{
10325 SYM_EXPRDATA* symdata;
10326 SCIP_EXPR** children;
10327 SCIP_EXPR** powexprs;
10328 SCIP_EXPR** prodexprs;
10329 SCIP_EXPR* child;
10330 SCIP_VAR** powvars;
10331 SCIP_VAR** prodvars;
10332 SCIP_VAR* actvar;
10333 SCIP_VAR* actvar2;
10334 SCIP_VAR* var;
10335 SCIP_VAR* var2;
10336 SCIP_Real* sumcoefs;
10337 SCIP_Real constant;
10338 SCIP_Real constant2;
10339 SCIP_Real val;
10340 SCIP_Real val2;
10341 SCIP_Bool* powexprused = NULL;
10342 int* powperm = NULL;
10343 int* prodperm = NULL;
10344 int nchildren;
10345 int nlocvars;
10346 int nodeidx;
10347 int coefnodeidx1;
10348 int coefnodeidx2;
10349 int cnt;
10350 int i;
10351 int j;
10352 int nterms;
10353 int npowexprs = 0;
10354 int nprodexprs = 0;
10355 int powcoef = 0;
10356
10357 assert(scip != NULL);
10358 assert(sumexpr != NULL);
10359 assert(cons != NULL);
10360 assert(SCIPisExprSum(scip, sumexpr));
10361 assert(consvars != NULL);
10362 assert(consvals != NULL);
10363 assert(maxnconsvars != NULL);
10364 assert(*maxnconsvars > 0);
10365 assert(handledexprs != NULL);
10366
10367 /* iterate over sum expression and extract all power and product expressions */
10368 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10369 children = SCIPexprGetChildren(sumexpr);
10370 nchildren = SCIPexprGetNChildren(sumexpr);
10371 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10372 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10373 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10374 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10375
10376 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10377 /** @todo make this work in a more general case */
10378 for( i = 0; i < nchildren; ++i )
10379 {
10380 if( SCIPisExprPower(scip, children[i]) )
10381 {
10382 SCIP_Real exponent;
10383
10384 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10385 if( powcoef == 0 )
10386 {
10387 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10388 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10389 }
10390 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10391 continue;
10392
10393 /* we only store power expressions if their child is a variable */
10394 assert(SCIPexprGetNChildren(children[i]) == 1);
10395 child = SCIPexprGetChildren(children[i])[0];
10396 if( !SCIPisExprVar(scip, child) )
10397 continue;
10398
10399 /* the power is required to be a 2 */
10400 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10401 assert(symdata != NULL);
10402 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10403
10404 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10405 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10406
10407 if( !SCIPisEQ(scip, exponent, 2.0) )
10408 continue;
10409
10410 /* we only store power expressions if the child is not multi-aggregated */
10411 var = SCIPgetVarExprVar(child);
10413 {
10414 powexprs[npowexprs] = children[i];
10415 powvars[npowexprs++] = var;
10416 }
10417 }
10418 else if( SCIPisExprProduct(scip, children[i]) )
10419 {
10420 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10421 if( powcoef == 0 )
10422 {
10423 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10424 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10425 }
10426 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10427 continue;
10428
10429 /* we only store power expressions if they have exactly two children being variables */
10430 if( SCIPexprGetNChildren(children[i]) != 2 )
10431 continue;
10432 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10433 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10434 continue;
10435
10436 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10437 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10438
10439 /* we only store product expressions if the children are not multi-aggregated */
10442 {
10443 prodexprs[nprodexprs] = children[i];
10444 prodvars[nprodexprs++] = var;
10445 prodexprs[nprodexprs] = children[i];
10446 prodvars[nprodexprs++] = var2;
10447 }
10448 }
10449 }
10450
10451 if( npowexprs == 0 || nprodexprs != npowexprs )
10452 goto FREEMEMORY;
10453
10454 /* check whether the power variables and product variables match */
10455 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10456 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10457
10458 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10459 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10460
10461 for( i = 0; i < npowexprs; ++i )
10462 {
10463 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10464 goto FREEMEMORY;
10465 }
10466
10467 /* if we reach this line, the variables match: we have found a potential norm constraint */
10468 assert(npowexprs % 2 == 0);
10469 nterms = npowexprs / 2;
10470 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10471
10472 /* add gadget of each squared difference term */
10473 cnt = 0;
10474 for( i = 0; i < nterms; ++i )
10475 {
10476 SCIP_Bool var1found = FALSE;
10477 SCIP_Bool var2found = FALSE;
10478
10479 (*consvals)[0] = 1.0;
10480 (*consvars)[0] = prodvars[cnt++];
10481 constant = 0.0;
10482 nlocvars = 1;
10483
10485 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10486
10487 if( nlocvars != 1 )
10488 {
10489 ++cnt;
10490 continue;
10491 }
10492 actvar = (*consvars)[0];
10493 val = (*consvals)[0];
10494
10495 (*consvals)[0] = 1.0;
10496 (*consvars)[0] = prodvars[cnt++];
10497 constant2 = 0.0;
10498 nlocvars = 1;
10499
10501 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10502
10503 if( nlocvars != 1 )
10504 continue;
10505 actvar2 = (*consvars)[0];
10506 val2 = (*consvals)[0];
10507
10508 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10509 * cannot be centered at the origin or they are not centered around the same point
10510 */
10511 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10515 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10516 continue;
10517
10518 /* add gadget */
10519 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10520 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10521 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10522
10523 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10524 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10525 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10526 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10527 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10528 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10529 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10530 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10531 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10532 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10533 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10534
10535 /* mark product expression as handled */
10536 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10537
10538 /* find corresponding unused power expressions and mark them as handled */
10539 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10540 {
10541 if( powexprused[j] )
10542 continue;
10543 assert(cnt >= 2);
10544
10545 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10546 {
10547 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10548 powexprused[j] = TRUE;
10549 var1found = TRUE;
10550 }
10551 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10552 {
10553 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10554 powexprused[j] = TRUE;
10555 var2found = TRUE;
10556 }
10557 }
10558 }
10559
10560 FREEMEMORY:
10561 SCIPfreeBufferArrayNull(scip, &powexprused);
10562 SCIPfreeBufferArrayNull(scip, &prodperm);
10563 SCIPfreeBufferArrayNull(scip, &powperm);
10564 SCIPfreeBufferArray(scip, &prodvars);
10565 SCIPfreeBufferArray(scip, &powvars);
10566 SCIPfreeBufferArray(scip, &prodexprs);
10567 SCIPfreeBufferArray(scip, &powexprs);
10568
10569 return SCIP_OKAY;
10570}
10571
10572/** adds symmetry information of constraint to a symmetry detection graph */
10573static
10575 SCIP* scip, /**< SCIP pointer */
10576 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10577 SCIP_CONS* cons, /**< constraint */
10578 SYM_GRAPH* graph, /**< symmetry detection graph */
10579 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10580 )
10581{ /*lint --e{850}*/
10582 SCIP_EXPRITER* it;
10583 SCIP_HASHSET* handledexprs;
10584 SCIP_EXPR* rootexpr;
10585 SCIP_EXPR* expr;
10586 SCIP_VAR** consvars;
10587 SCIP_Real* consvals;
10588 SCIP_Real constant;
10589 SCIP_Real parentcoef = 0.0;
10590 int* openidx;
10591 int maxnopenidx;
10592 int parentidx;
10593 int nconsvars;
10594 int maxnconsvars;
10595 int nlocvars;
10596 int nopenidx = 0;
10597 int consnodeidx;
10598 int nodeidx;
10599 int i;
10600 SCIP_Bool iscolored;
10601 SCIP_Bool hasparentcoef;
10602
10603 assert(scip != NULL);
10604 assert(cons != NULL);
10605 assert(graph != NULL);
10606 assert(success != NULL);
10607
10608 /* store lhs/rhs */
10610 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10611
10612 rootexpr = SCIPgetExprNonlinear(cons);
10613 assert(rootexpr != NULL);
10614
10615 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10616 expr = SCIPgetExprNonlinear(cons);
10617 assert(expr != NULL);
10618
10622
10623 /* find potential number of nodes in graph */
10624 maxnopenidx = 0;
10625 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10626 {
10628 continue;
10629
10630 ++maxnopenidx;
10631 }
10632
10633 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10634
10635 maxnconsvars = SCIPgetNVars(scip);
10636 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10637 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10638
10639 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10640 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10641
10642 /* iterate over expression tree and store nodes/edges */
10643 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10646
10647 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10648 {
10649 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10650 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10651 {
10652 SCIP_EXPR* baseexpr;
10653
10654 baseexpr = expr;
10655 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10656 expr = SCIPexpriterGetNext(it);
10657
10658 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10659
10660 /* leave the expression */
10661 continue;
10662 }
10663
10664 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10666 {
10667 --nopenidx;
10668 continue;
10669 }
10671
10672 /* find parentidx */
10673 if( expr == rootexpr )
10674 parentidx = consnodeidx;
10675 else
10676 {
10677 assert(nopenidx >= 1);
10678 parentidx = openidx[nopenidx - 1];
10679 }
10680
10681 /* possibly find a coefficient assigned to the expression by the parent */
10682 hasparentcoef = FALSE;
10683 if ( expr != rootexpr )
10684 {
10685 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10686 }
10687
10688 /* deal with different kinds of expressions and store them in the symmetry data structure */
10689 if( SCIPisExprVar(scip, expr) )
10690 {
10691 /* needed to correctly reset value when leaving expression */
10692 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10693
10694 openidx[nopenidx++] = -1;
10695
10696 assert(maxnconsvars > 0);
10697 assert(parentidx > 0);
10698
10699 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10700 if( hasparentcoef )
10701 {
10702 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10703
10704 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10705 parentidx = nodeidx;
10706 }
10707
10708 /* connect (aggregation of) variable expression with its parent */
10709 nconsvars = 1;
10710 consvars[0] = SCIPgetVarExprVar(expr);
10711 consvals[0] = 1.0;
10712 constant = 0.0;
10713
10714 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10715 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10716
10717 /* check whether variable is aggregated */
10718 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10719 {
10720 int thisidx;
10721
10722 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10723 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10724
10725 parentidx = thisidx;
10726 }
10727 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10728 nconsvars, constant) );
10729 }
10730 else if( SCIPisExprValue(scip, expr) )
10731 {
10732 assert(parentidx > 0);
10733
10734 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10735
10736 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10737
10738 /* needed to correctly reset value when leaving expression */
10739 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10740
10741 openidx[nopenidx++] = -1;
10742 }
10743 else
10744 {
10745 SCIP_Bool usedefaultgadget = TRUE;
10746
10747 assert(expr == rootexpr || parentidx > 0);
10748 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10749
10750 if( SCIPisExprSum(scip, expr) )
10751 {
10752 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10753 SCIP_EXPR** children;
10754 int sumidx;
10755 int optype;
10756 int childidx;
10757
10758 /* sums are handled by a special gadget */
10759 usedefaultgadget = FALSE;
10760
10761 /* extract all children being variables and compute the sum of active variables expression */
10762 nlocvars = 0;
10763 children = SCIPexprGetChildren(expr);
10764
10765 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10766
10767 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10768 {
10769 if( !SCIPisExprVar(scip, children[childidx]) )
10770 continue;
10771
10772 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10773 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10774
10775 /* store that we have already handled this expression */
10776 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10777 }
10778
10779 constant = SCIPgetConstantExprSum(expr);
10780
10781 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10782 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10783
10785
10786 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10787 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10788
10789 /* add the linear part of the sum */
10790 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10791
10792 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10793
10794 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10795 if( symtype == SYM_SYMTYPE_SIGNPERM )
10796 {
10797 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10798 &consvars, &consvals, &maxnconsvars, handledexprs) );
10799 }
10800
10801 /* store sumidx for children that have not been treated */
10802 openidx[nopenidx++] = sumidx;
10803 }
10804 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10805 {
10806 SCIP_Bool succ;
10807
10808 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10809 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10810
10811 if( succ )
10812 {
10813 usedefaultgadget = FALSE;
10814 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10815 }
10816 }
10817 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10818 {
10819 SCIP_Bool succ;
10820
10821 /* we can find more signed permutations for even univariate operators */
10822 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10823 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10824
10825 if( succ )
10826 {
10827 usedefaultgadget = FALSE;
10828 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10829 }
10830 }
10831
10832 if( usedefaultgadget )
10833 {
10834 int opidx;
10835 int optype;
10836
10838 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10839 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10840
10841 /* possibly add constants of expression */
10843 {
10844 SYM_EXPRDATA* symdata;
10845
10846 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10847 assert(symdata != NULL);
10848
10849 /* if expression has multiple constants, assign colors to edges to distinguish them */
10850 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
10851 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10852 {
10853 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
10854 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10855 }
10856
10857 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10858 }
10859
10860 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10861
10862 openidx[nopenidx++] = opidx;
10863 }
10864 }
10865 }
10866
10867 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
10868 SCIPfreeBufferArray(scip, &consvals);
10869 SCIPfreeBufferArray(scip, &consvars);
10870 SCIPfreeBufferArray(scip, &openidx);
10871 SCIPfreeExpriter(&it);
10872
10873 *success = TRUE;
10874
10875 return SCIP_OKAY;
10876}
10877
10878/*
10879 * Callback methods of constraint handler
10880 */
10881
10882/** copy method for constraint handler plugins (called when SCIP copies plugins) */
10883static
10884SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
10885{ /*lint --e{715}*/
10886 SCIP_CONSHDLR* targetconshdlr;
10887 SCIP_CONSHDLRDATA* sourceconshdlrdata;
10888 int i;
10889
10890 assert(scip != NULL);
10891 assert(conshdlr != NULL);
10892 assert(valid != NULL);
10893 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10894
10895 /* create basic data of constraint handler and include it to scip */
10897
10898 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10899 assert(targetconshdlr != NULL);
10900 assert(targetconshdlr != conshdlr);
10901
10902 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
10903 assert(sourceconshdlrdata != NULL);
10904
10905 /* copy nonlinear handlers */
10906 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10907 {
10908 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
10909 }
10910
10911 *valid = TRUE;
10912
10913 return SCIP_OKAY;
10914}
10915
10916/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10917static
10918SCIP_DECL_CONSFREE(consFreeNonlinear)
10919{ /*lint --e{715}*/
10920 SCIP_CONSHDLRDATA* conshdlrdata;
10921 int i;
10922
10923 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10924 assert(conshdlrdata != NULL);
10925
10926 /* free nonlinear handlers */
10927 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10928 {
10929 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
10930 assert(conshdlrdata->nlhdlrs[i] == NULL);
10931 }
10932 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
10933 conshdlrdata->nlhdlrssize = 0;
10934
10935 /* free upgrade functions */
10936 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
10937 {
10938 assert(conshdlrdata->consupgrades[i] != NULL);
10939 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
10940 }
10941 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
10942
10943 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
10944
10945 SCIPqueueFree(&conshdlrdata->reversepropqueue);
10946
10947 if( conshdlrdata->vp_randnumgen != NULL )
10948 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10949
10950 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10951 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10952 {
10953 if( conshdlrdata->vp_lp[i] != NULL )
10954 {
10955 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10956 }
10957 }
10958
10959 assert(conshdlrdata->branchrandnumgen == NULL);
10960
10961 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
10962 SCIPhashmapFree(&conshdlrdata->var2expr);
10963
10964 SCIPfreeBlockMemory(scip, &conshdlrdata);
10965 SCIPconshdlrSetData(conshdlr, NULL);
10966
10967 return SCIP_OKAY;
10968}
10969
10970
10971/** initialization method of constraint handler (called after problem was transformed) */
10972static
10973SCIP_DECL_CONSINIT(consInitNonlinear)
10974{ /*lint --e{715}*/
10975 SCIP_CONSHDLRDATA* conshdlrdata;
10976 int i;
10977
10978 conshdlrdata = SCIPconshdlrGetData(conshdlr);
10979 assert(conshdlrdata != NULL);
10980
10981 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
10982 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
10983 /* set to 1 so it is larger than initial value of lastenforound in exprs */
10984 conshdlrdata->enforound = 1;
10985 /* reset numbering for auxiliary variables */
10986 conshdlrdata->auxvarid = 0;
10987
10988 for( i = 0; i < nconss; ++i )
10989 {
10990 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
10991 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
10992 }
10993
10994 /* sort nonlinear handlers by detection priority, in decreasing order */
10995 if( conshdlrdata->nnlhdlrs > 1 )
10996 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
10997
10998 /* get heuristics for later use */
10999 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11000 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11001
11002 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11003 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11004 {
11005 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11006 }
11007
11008 /* reset statistics in constraint handler */
11009 conshdlrdata->nweaksepa = 0;
11010 conshdlrdata->ntightenlp = 0;
11011 conshdlrdata->ndesperatebranch = 0;
11012 conshdlrdata->ndesperatecutoff = 0;
11013 conshdlrdata->ndesperatetightenlp = 0;
11014 conshdlrdata->nforcelp = 0;
11015 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11016 conshdlrdata->ncanonicalizecalls = 0;
11017
11018#ifdef ENFOLOGFILE
11019 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11020#endif
11021
11022 return SCIP_OKAY;
11023}
11024
11025
11026/** deinitialization method of constraint handler (called before transformed problem is freed) */
11027static
11028SCIP_DECL_CONSEXIT(consExitNonlinear)
11029{ /*lint --e{715}*/
11030 SCIP_CONSHDLRDATA* conshdlrdata;
11031 SCIP_CONS** consssorted;
11032 int i;
11033
11034 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11035 assert(conshdlrdata != NULL);
11036
11037 if( nconss > 0 )
11038 {
11039 /* for better performance of dropVarEvents, we sort by index, descending */
11040 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11041 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11042
11043 for( i = 0; i < nconss; ++i )
11044 {
11045 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11046 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11047 }
11048
11049 SCIPfreeBufferArray(scip, &consssorted);
11050 }
11051
11052 conshdlrdata->subnlpheur = NULL;
11053 conshdlrdata->trysolheur = NULL;
11054
11055 if( conshdlrdata->vp_randnumgen != NULL )
11056 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11057
11058 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11059 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11060 {
11061 if( conshdlrdata->vp_lp[i] != NULL )
11062 {
11063 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11064 }
11065 }
11066
11067 if( conshdlrdata->branchrandnumgen != NULL )
11068 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11069
11070 /* deinitialize nonlinear handlers */
11071 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11072 {
11073 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11074 }
11075
11076 ENFOLOG(
11077 if( enfologfile != NULL )
11078 {
11079 fclose(enfologfile);
11080 enfologfile = NULL;
11081 })
11082
11083 return SCIP_OKAY;
11084}
11085
11086
11087/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11088#ifdef SCIP_DISABLED_CODE
11089static
11091{ /*lint --e{715}*/
11092 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11093 SCIPABORT(); /*lint --e{527}*/
11094
11095 return SCIP_OKAY;
11096}
11097#else
11098#define consInitpreNonlinear NULL
11099#endif
11100
11101
11102/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11103static
11104SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11105{ /*lint --e{715}*/
11106 SCIP_Bool infeasible;
11107
11108 if( nconss == 0 )
11109 return SCIP_OKAY;
11110
11111 /* skip some extra work if already known to be infeasible */
11113 return SCIP_OKAY;
11114
11115 /* simplify constraints and replace common subexpressions */
11116 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11117
11118 /* currently SCIP does not offer to communicate this,
11119 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11120 * or if a constraint expression became constant
11121 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11122 */
11123 /* assert(!infeasible); */
11124
11125 /* tell SCIP that we have something nonlinear */
11127
11128 return SCIP_OKAY;
11129}
11130
11131
11132/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11133static
11134SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11135{ /*lint --e{715}*/
11136 SCIP_CONSHDLRDATA* conshdlrdata;
11137 int i;
11138
11139 /* skip remaining initializations if we have solved already
11140 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11141 * assumes nonempty activities in expressions
11142 */
11143 switch( SCIPgetStatus(scip) )
11144 {
11149 return SCIP_OKAY;
11150 default: ;
11151 } /*lint !e788 */
11152
11153 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11154 assert(conshdlrdata != NULL);
11155
11156 /* reset one of the number of detections counter to count only current round */
11157 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11158 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11159
11160 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11161
11162 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11163 if( conshdlrdata->branchpscostweight > 0.0 )
11164 {
11165 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11166 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11167 {
11168 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11169 SCIPABORT();
11170 return SCIP_INVALIDDATA;
11171 }
11172 }
11173
11174 return SCIP_OKAY;
11175}
11176
11177
11178/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11179static
11180SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11181{ /*lint --e{715}*/
11182 SCIP_CONSHDLRDATA* conshdlrdata;
11183
11184 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11185
11186 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11187 assert(conshdlrdata != NULL);
11188
11189 /* free hash table for bilinear terms */
11190 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11191
11192 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11193 conshdlrdata->checkedvarlocks = FALSE;
11194
11195 /* drop catching new solution event, if catched before */
11196 if( conshdlrdata->newsoleventfilterpos >= 0 )
11197 {
11198 SCIP_EVENTHDLR* eventhdlr;
11199
11200 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11201 assert(eventhdlr != NULL);
11202
11203 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11204 conshdlrdata->newsoleventfilterpos = -1;
11205 }
11206
11207 return SCIP_OKAY;
11208}
11209
11210
11211/** frees specific constraint data */
11212static
11213SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11214{ /*lint --e{715}*/
11215 assert(consdata != NULL);
11216 assert(*consdata != NULL);
11217 assert((*consdata)->expr != NULL);
11218
11219 /* constraint locks should have been removed */
11220 assert((*consdata)->nlockspos == 0);
11221 assert((*consdata)->nlocksneg == 0);
11222
11223 /* free variable expressions */
11224 SCIP_CALL( freeVarExprs(scip, *consdata) );
11225
11226 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11227
11228 /* free nonlinear row representation */
11229 if( (*consdata)->nlrow != NULL )
11230 {
11231 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11232 }
11233
11234 SCIPfreeBlockMemory(scip, consdata);
11235
11236 return SCIP_OKAY;
11237}
11238
11239
11240/** transforms constraint data into data belonging to the transformed problem */
11241static
11242SCIP_DECL_CONSTRANS(consTransNonlinear)
11243{ /*lint --e{715}*/
11244 SCIP_EXPR* targetexpr;
11245 SCIP_CONSDATA* sourcedata;
11246
11247 sourcedata = SCIPconsGetData(sourcecons);
11248 assert(sourcedata != NULL);
11249
11250 /* get a copy of sourceexpr with transformed vars */
11251 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11252 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11253
11254 /* create transformed cons (only captures targetexpr, no need to copy again) */
11255 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11256 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11257 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11258 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11259 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11260 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11261
11262 /* release target expr */
11263 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11264
11265 return SCIP_OKAY;
11266}
11267
11268
11269/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11270static
11271SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11272{ /*lint --e{715}*/
11273 SCIP_CONSHDLRDATA* conshdlrdata;
11274
11275 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11276 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11277 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11278 * for now, there is an assert in detectNlhdlrs to require initial if separated
11279 */
11280 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11281
11282 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11283 assert(conshdlrdata != NULL);
11284
11285 /* catch new solution event */
11286 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11287 {
11288 SCIP_EVENTHDLR* eventhdlr;
11289
11290 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11291 assert(eventhdlr != NULL);
11292
11293 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11294 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11295 }
11296
11297 /* collect all bilinear terms for which an auxvar is present
11298 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11299 * addition (and removal?) of constraints during solve
11300 * this is typically the majority of constraints, but the method should be made more flexible
11301 */
11302 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11303
11304 return SCIP_OKAY;
11305}
11306
11307
11308/** separation method of constraint handler for LP solutions */
11309static
11310SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11311{ /*lint --e{715}*/
11312 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11313
11314 return SCIP_OKAY;
11315}
11316
11317
11318/** separation method of constraint handler for arbitrary primal solutions */
11319static
11320SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11321{ /*lint --e{715}*/
11322 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11323
11324 return SCIP_OKAY;
11325}
11326
11327
11328/** constraint enforcing method of constraint handler for LP solutions */
11329static
11330SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11331{ /*lint --e{715}*/
11332 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11333
11334 return SCIP_OKAY;
11335}
11336
11337
11338/** constraint enforcing method of constraint handler for relaxation solutions */
11339static
11340SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11341{ /*lint --e{715}*/
11342 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11343
11344 return SCIP_OKAY;
11345}
11346
11347
11348/** constraint enforcing method of constraint handler for pseudo solutions */
11349static
11350SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11351{ /*lint --e{715}*/
11352 SCIP_RESULT propresult;
11353 SCIP_Longint soltag;
11354 int nchgbds;
11355 int nnotify;
11356 int c;
11357
11358 soltag = SCIPgetExprNewSoltag(scip);
11359
11361 for( c = 0; c < nconss; ++c )
11362 {
11363 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11364
11365 if( isConsViolated(scip, conss[c]) )
11367 }
11368
11369 if( *result == SCIP_FEASIBLE )
11370 return SCIP_OKAY;
11371
11372 /* try to propagate
11373 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11374 */
11375 nchgbds = 0;
11376 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11377
11378 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11379 {
11380 *result = propresult;
11381 return SCIP_OKAY;
11382 }
11383
11384 /* register all unfixed variables in all violated constraints as branching candidates */
11385 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11386 if( nnotify > 0 )
11387 {
11388 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11389
11390 return SCIP_OKAY;
11391 }
11392
11393 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11395 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11396
11397 return SCIP_OKAY;
11398}
11399
11400
11401/** feasibility check method of constraint handler for integral solutions */
11402static
11403SCIP_DECL_CONSCHECK(consCheckNonlinear)
11404{ /*lint --e{715}*/
11405 SCIP_CONSHDLRDATA* conshdlrdata;
11406 SCIP_CONSDATA* consdata;
11407 SCIP_Real maxviol;
11408 SCIP_Bool maypropfeasible;
11409 SCIP_Longint soltag;
11410 int c;
11411
11412 assert(scip != NULL);
11413 assert(conshdlr != NULL);
11414 assert(conss != NULL || nconss == 0);
11415 assert(result != NULL);
11416
11417 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11418 assert(conshdlrdata != NULL);
11419
11421 soltag = SCIPgetExprNewSoltag(scip);
11422 maxviol = 0.0;
11423 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11425
11427 maypropfeasible = FALSE;
11428
11429 /* check nonlinear constraints for feasibility */
11430 for( c = 0; c < nconss; ++c )
11431 {
11432 assert(conss != NULL && conss[c] != NULL);
11433 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11434
11435 if( isConsViolated(scip, conss[c]) )
11436 {
11438 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11439
11440 consdata = SCIPconsGetData(conss[c]);
11441 assert(consdata != NULL);
11442
11443 /* print reason for infeasibility */
11444 if( printreason )
11445 {
11446 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11447 SCIPinfoMessage(scip, NULL, ";\n");
11448
11449 if( consdata->lhsviol > SCIPfeastol(scip) )
11450 {
11451 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11452 }
11453 if( consdata->rhsviol > SCIPfeastol(scip) )
11454 {
11455 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11456 }
11457 }
11458 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11459 {
11460 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11461 return SCIP_OKAY;
11462 }
11463
11464 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11465 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11466 maypropfeasible = FALSE;
11467
11468 if( maypropfeasible )
11469 {
11470 if( consdata->lhsviol > SCIPfeastol(scip) )
11471 {
11472 /* check if there is a variable which may help to get the left hand side satisfied
11473 * if there is no such variable, then we cannot get feasible
11474 */
11475 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11476 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11477 maypropfeasible = FALSE;
11478 }
11479 else
11480 {
11481 assert(consdata->rhsviol > SCIPfeastol(scip));
11482 /* check if there is a variable which may help to get the right hand side satisfied
11483 * if there is no such variable, then we cannot get feasible
11484 */
11485 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11486 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11487 maypropfeasible = FALSE;
11488 }
11489 }
11490 }
11491 }
11492
11493 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11494 {
11495 SCIP_Bool success;
11496
11497 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11498
11499 /* do not pass solution to NLP heuristic if we made it feasible this way */
11500 if( success )
11501 return SCIP_OKAY;
11502 }
11503
11504 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11505 {
11506 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11507 }
11508
11509 return SCIP_OKAY;
11510}
11511
11512
11513/** domain propagation method of constraint handler */
11514static
11515SCIP_DECL_CONSPROP(consPropNonlinear)
11516{ /*lint --e{715}*/
11517 int nchgbds = 0;
11518
11519 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11520 assert(nchgbds >= 0);
11521
11522 /* TODO would it make sense to check for redundant constraints? */
11523
11524 return SCIP_OKAY;
11525}
11526
11527
11528/** presolving method of constraint handler */
11529static
11530SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11531{ /*lint --e{715}*/
11532 SCIP_CONSHDLRDATA* conshdlrdata;
11533 SCIP_Bool infeasible;
11534 int c;
11535
11537
11538 if( nconss == 0 )
11539 {
11541 return SCIP_OKAY;
11542 }
11543
11544 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11545 assert(conshdlrdata != NULL);
11546
11547 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11548 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11549 if( infeasible )
11550 {
11552 return SCIP_OKAY;
11553 }
11554
11555 /* merge constraints with the same root expression */
11556 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11557 {
11558 SCIP_Bool success;
11559
11560 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11561 if( success )
11563 }
11564
11565 /* propagate constraints */
11566 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11567 if( *result == SCIP_CUTOFF )
11568 return SCIP_OKAY;
11569
11570 /* propagate function domains (TODO integrate with simplify?) */
11571 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11572 {
11573 SCIP_RESULT localresult;
11574 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11575 if( localresult == SCIP_CUTOFF )
11576 {
11578 return SCIP_OKAY;
11579 }
11580 if( localresult == SCIP_REDUCEDDOM )
11582 }
11583
11584 /* check for redundant constraints, remove constraints that are a value expression */
11585 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11586 if( infeasible )
11587 {
11589 return SCIP_OKAY;
11590 }
11591
11592 /* try to upgrade constraints */
11593 for( c = 0; c < nconss; ++c )
11594 {
11595 SCIP_Bool upgraded;
11596
11597 /* skip inactive and deleted constraints */
11598 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11599 continue;
11600
11601 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11602 }
11603
11604 /* try to change continuous variables that appear linearly to be implicit integer */
11605 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11606 {
11607 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11608
11609 if( infeasible )
11610 {
11611 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11613 return SCIP_OKAY;
11614 }
11615 }
11616
11617 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11619 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11620 {
11621 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11622 * constraints multiple times
11623 */
11624 conshdlrdata->checkedvarlocks = TRUE;
11625
11626 for( c = 0; c < nconss; ++c )
11627 {
11628 int tmpnchgvartypes = 0;
11629 int tmpnaddconss = 0;
11630
11631 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11632 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11633 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11634
11635 if( infeasible )
11636 {
11637 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11639 return SCIP_OKAY;
11640 }
11641
11642 (*nchgvartypes) += tmpnchgvartypes;
11643 (*naddconss) += tmpnaddconss;
11644 }
11645 }
11646
11647 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11649 else
11651
11652 return SCIP_OKAY;
11653}
11654
11655
11656/** propagation conflict resolving method of constraint handler */
11657#ifdef SCIP_DISABLED_CODE
11658static
11660{ /*lint --e{715}*/
11661 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11662 SCIPABORT(); /*lint --e{527}*/
11663
11664 return SCIP_OKAY;
11665}
11666#else
11667#define consRespropNonlinear NULL
11668#endif
11669
11670
11671/** variable rounding lock method of constraint handler */
11672static
11673SCIP_DECL_CONSLOCK(consLockNonlinear)
11674{ /*lint --e{715}*/
11675 SCIP_CONSDATA* consdata;
11676 SCIP_EXPR_OWNERDATA* ownerdata;
11677 SCIP_Bool reinitsolve = FALSE;
11678
11679 assert(conshdlr != NULL);
11680 assert(cons != NULL);
11681
11682 consdata = SCIPconsGetData(cons);
11683 assert(consdata != NULL);
11684 assert(consdata->expr != NULL);
11685
11686 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11687
11688 /* check whether we need to initSolve again because
11689 * - we have enfo initialized (nenfos >= 0)
11690 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11691 */
11692 if( ownerdata->nenfos >= 0 )
11693 {
11694 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11695 reinitsolve = TRUE;
11696 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11697 reinitsolve = TRUE;
11698 }
11699
11700 if( reinitsolve )
11701 {
11702 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11703 }
11704
11705 /* add locks */
11706 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11707
11708 if( reinitsolve )
11709 {
11710 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11711 }
11712
11713 return SCIP_OKAY;
11714}
11715
11716
11717/** constraint activation notification method of constraint handler */
11718static
11719SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11720{ /*lint --e{715}*/
11721 SCIP_CONSDATA* consdata;
11722 SCIP_Bool infeasible = FALSE;
11723
11724 consdata = SCIPconsGetData(cons);
11725 assert(consdata != NULL);
11726
11727 /* simplify root expression if the constraint has been added after presolving */
11729 {
11730 SCIP_Bool replacedroot;
11731
11732 if( !consdata->issimplified )
11733 {
11734 SCIP_EXPR* simplified;
11735 SCIP_Bool changed;
11736
11737 /* simplify constraint */
11738 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11739 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11740 assert(simplified != NULL);
11741 consdata->expr = simplified;
11742 consdata->issimplified = TRUE;
11743 }
11744
11745 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11746 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11747 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11748
11749 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11750 {
11751 SCIP_CONSHDLRDATA* conshdlrdata;
11752 SCIP_EXPRITER* it;
11753 SCIP_EXPR* expr;
11754
11755 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11756 assert(conshdlrdata != NULL);
11757
11759 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11761 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11762 {
11763 SCIP_EXPR* child;
11764 SCIP_EXPR* hashmapexpr;
11765
11766 child = SCIPexpriterGetChildExprDFS(it);
11767 if( !SCIPisExprVar(scip, child) )
11768 continue;
11769
11770 /* check which expression is stored in the hashmap for the var of child */
11771 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11772 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11773 if( hashmapexpr != NULL && hashmapexpr != child )
11774 {
11776 }
11777 }
11778 SCIPfreeExpriter(&it);
11779 }
11780 }
11781
11782 /* store variable expressions */
11784 {
11785 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11786 }
11787
11788 /* add manually locks to constraints that are not checked for feasibility */
11789 if( !SCIPconsIsChecked(cons) )
11790 {
11791 assert(consdata->nlockspos == 0);
11792 assert(consdata->nlocksneg == 0);
11793
11794 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11795 }
11796
11797 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11798 {
11799 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11800 }
11801
11802 /* TODO deal with infeasibility */
11803 assert(!infeasible);
11804
11805 return SCIP_OKAY;
11806}
11807
11808
11809/** constraint deactivation notification method of constraint handler */
11810static
11811SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11812{ /*lint --e{715}*/
11813 SCIP_CONSHDLRDATA* conshdlrdata;
11814
11815 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11816 assert(conshdlrdata != NULL);
11817
11819 {
11820 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11821 }
11822
11824 {
11825 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11827 }
11828
11829 /* remove locks that have been added in consActiveExpr() */
11830 if( !SCIPconsIsChecked(cons) )
11831 {
11832 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11833
11834 assert(SCIPconsGetData(cons)->nlockspos == 0);
11835 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11836 }
11837
11838 return SCIP_OKAY;
11839}
11840
11841
11842/** constraint enabling notification method of constraint handler */
11843static
11844SCIP_DECL_CONSENABLE(consEnableNonlinear)
11845{ /*lint --e{715}*/
11846 SCIP_CONSHDLRDATA* conshdlrdata;
11847
11848 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11849 assert(conshdlrdata != NULL);
11850
11852 {
11853 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11854 }
11855
11856 return SCIP_OKAY;
11857}
11858
11859
11860/** constraint disabling notification method of constraint handler */
11861static
11862SCIP_DECL_CONSDISABLE(consDisableNonlinear)
11863{ /*lint --e{715}*/
11864 SCIP_CONSHDLRDATA* conshdlrdata;
11865
11866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11867 assert(conshdlrdata != NULL);
11868
11870 {
11871 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11872 }
11873
11874 return SCIP_OKAY;
11875}
11876
11877/** variable deletion of constraint handler */
11878#ifdef SCIP_DISABLED_CODE
11879static
11881{ /*lint --e{715}*/
11882 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11883 SCIPABORT(); /*lint --e{527}*/
11884
11885 return SCIP_OKAY;
11886}
11887#else
11888#define consDelvarsNonlinear NULL
11889#endif
11890
11891
11892/** constraint display method of constraint handler */
11893static
11894SCIP_DECL_CONSPRINT(consPrintNonlinear)
11895{ /*lint --e{715}*/
11896 SCIP_CONSDATA* consdata;
11897
11898 consdata = SCIPconsGetData(cons);
11899 assert(consdata != NULL);
11900 assert(consdata->expr != NULL);
11901
11902 /* print left hand side for ranged constraints */
11903 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11904 {
11905 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11906 }
11907
11908 /* print expression */
11909 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11910
11911 /* print right hand side */
11912 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11913 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11914 else if( !SCIPisInfinity(scip, consdata->rhs) )
11915 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11916 else if( !SCIPisInfinity(scip, -consdata->lhs) )
11917 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11918 else
11919 SCIPinfoMessage(scip, file, " [free]");
11920
11921 return SCIP_OKAY;
11922}
11923
11924
11925/** constraint copying method of constraint handler */
11926static
11927SCIP_DECL_CONSCOPY(consCopyNonlinear)
11928{ /*lint --e{715}*/
11929 SCIP_CONSHDLR* targetconshdlr;
11930 SCIP_EXPR* targetexpr = NULL;
11931 SCIP_CONSDATA* sourcedata;
11932
11933 assert(cons != NULL);
11934
11935 sourcedata = SCIPconsGetData(sourcecons);
11936 assert(sourcedata != NULL);
11937
11938 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11939 assert(targetconshdlr != NULL);
11940
11941 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
11942
11943 if( targetexpr == NULL )
11944 *valid = FALSE;
11945
11946 *cons = NULL;
11947 if( *valid )
11948 {
11949 /* create copy (only capture targetexpr, no need to copy again) */
11950 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
11951 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11952 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11953 }
11954
11955 if( targetexpr != NULL )
11956 {
11957 /* release target expr */
11958 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11959 }
11960
11961 return SCIP_OKAY;
11962}
11963
11964
11965/** constraint parsing method of constraint handler */
11966static
11967SCIP_DECL_CONSPARSE(consParseNonlinear)
11968{ /*lint --e{715}*/
11969 SCIP_Real lhs;
11970 SCIP_Real rhs;
11971 char* endptr;
11972 SCIP_EXPR* consexprtree;
11973
11974 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
11975
11976 assert(scip != NULL);
11977 assert(success != NULL);
11978 assert(str != NULL);
11979 assert(name != NULL);
11980 assert(cons != NULL);
11981
11982 *success = FALSE;
11983
11984 /* return if string empty */
11985 if( !*str )
11986 return SCIP_OKAY;
11987
11988 endptr = (char*)str;
11989
11990 /* set left and right hand side to their default values */
11991 lhs = -SCIPinfinity(scip);
11992 rhs = SCIPinfinity(scip);
11993
11994 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
11995
11996 /* check for left hand side */
11997 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11998 {
11999 /* there is a number coming, maybe it is a left-hand-side */
12000 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12001 {
12002 SCIPerrorMessage("error parsing number from <%s>\n", str);
12003 return SCIP_READERROR;
12004 }
12005
12006 /* ignore whitespace */
12007 SCIP_CALL( SCIPskipSpace(&endptr) );
12008
12009 if( endptr[0] != '<' || endptr[1] != '=' )
12010 {
12011 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12012 lhs = -SCIPinfinity(scip);
12013 }
12014 else
12015 {
12016 /* it was indeed a left-hand-side, so continue parsing after it */
12017 str = endptr + 2;
12018
12019 /* ignore whitespace */
12020 SCIP_CALL( SCIPskipSpace((char**)&str) );
12021 }
12022 }
12023
12024 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12025
12026 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12027 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12028
12029 /* check for left or right hand side */
12030 SCIP_CALL( SCIPskipSpace((char**)&str) );
12031
12032 /* check for free constraint */
12033 if( strncmp(str, "[free]", 6) == 0 )
12034 {
12035 if( !SCIPisInfinity(scip, -lhs) )
12036 {
12037 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12038 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12039 return SCIP_OKAY;
12040 }
12041 *success = TRUE;
12042 }
12043 else
12044 {
12045 switch( *str )
12046 {
12047 case '<':
12048 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12049 break;
12050 case '=':
12051 if( !SCIPisInfinity(scip, -lhs) )
12052 {
12053 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12054 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12055 return SCIP_OKAY;
12056 }
12057 else
12058 {
12059 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12060 lhs = rhs;
12061 }
12062 break;
12063 case '>':
12064 if( !SCIPisInfinity(scip, -lhs) )
12065 {
12066 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12067 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12068 return SCIP_OKAY;
12069 }
12070 else
12071 {
12072 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12073 break;
12074 }
12075 case '\0':
12076 *success = TRUE;
12077 break;
12078 default:
12079 SCIPerrorMessage("unexpected character %c\n", *str);
12080 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12081 return SCIP_OKAY;
12082 }
12083 }
12084
12085 /* create constraint */
12086 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12087 consexprtree, lhs, rhs, FALSE,
12088 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12089 assert(*cons != NULL);
12090
12091 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12092
12093 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12094
12095 return SCIP_OKAY;
12096}
12097
12098
12099/** constraint method of constraint handler which returns the variables (if possible) */
12100static
12101SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12102{ /*lint --e{715}*/
12103 SCIP_CONSDATA* consdata;
12104 int i;
12105
12106 consdata = SCIPconsGetData(cons);
12107 assert(consdata != NULL);
12108
12109 /* store variable expressions if not done so far */
12110 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12111
12112 /* check whether array is too small in order to store all variables */
12113 if( varssize < consdata->nvarexprs )
12114 {
12115 *success = FALSE;
12116 return SCIP_OKAY;
12117 }
12118
12119 for( i = 0; i < consdata->nvarexprs; ++i )
12120 {
12121 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12122 assert(vars[i] != NULL);
12123 }
12124
12125 *success = TRUE;
12126
12127 return SCIP_OKAY;
12128}
12129
12130/** constraint method of constraint handler which returns the number of variables (if possible) */
12131static
12132SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12133{ /*lint --e{715}*/
12134 SCIP_CONSDATA* consdata;
12135
12136 consdata = SCIPconsGetData(cons);
12137 assert(consdata != NULL);
12138
12139 /* store variable expressions if not done so far */
12140 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12141
12142 *nvars = consdata->nvarexprs;
12143 *success = TRUE;
12144
12145 return SCIP_OKAY;
12146}
12147
12148/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12149#ifdef SCIP_DISABLED_CODE
12150static
12152{ /*lint --e{715}*/
12153 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12154 SCIPABORT(); /*lint --e{527}*/
12155
12156 return SCIP_OKAY;
12157}
12158#else
12159#define consGetDiveBdChgsNonlinear NULL
12160#endif
12161
12162/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12163static
12164SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12165{ /*lint --e{715}*/
12166 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12167
12168 return SCIP_OKAY;
12169}
12170
12171/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12172static
12173SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12174{ /*lint --e{715}*/
12175 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12176
12177 return SCIP_OKAY;
12178}
12179
12180/** output method of statistics table to output file stream 'file' */
12181static
12182SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12183{ /*lint --e{715}*/
12184 SCIP_CONSHDLR* conshdlr;
12185 SCIP_CONSHDLRDATA* conshdlrdata;
12186
12187 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12188 assert(conshdlr != NULL);
12189
12190 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12191 assert(conshdlrdata != NULL);
12192
12193 /* print statistics for constraint handler */
12194 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12195 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12196 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12197 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12198 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12199 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12200 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12201 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12202 SCIPinfoMessage(scip, file, "\n");
12203 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12204 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12205 SCIPinfoMessage(scip, file, "\n");
12206
12207 return SCIP_OKAY;
12208}
12209
12210/** output method of statistics table to output file stream 'file' */
12211static
12212SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12213{ /*lint --e{715}*/
12214 SCIP_CONSHDLR* conshdlr;
12215 SCIP_CONSHDLRDATA* conshdlrdata;
12216
12217 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12218 assert(conshdlr != NULL);
12219
12220 /* skip nlhdlr table if there never were active nonlinear constraints */
12221 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12222 return SCIP_OKAY;
12223
12224 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12225 assert(conshdlrdata != NULL);
12226
12227 /* print statistics for nonlinear handlers */
12228 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12229
12230 return SCIP_OKAY;
12231}
12232
12233/** execution method of display nlhdlrs dialog */
12234static
12235SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12236{ /*lint --e{715}*/
12237 SCIP_CONSHDLR* conshdlr;
12238 SCIP_CONSHDLRDATA* conshdlrdata;
12239 int i;
12240
12241 /* add dialog to history of dialogs that have been executed */
12242 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12243
12244 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12245 assert(conshdlr != NULL);
12246
12247 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12248 assert(conshdlrdata != NULL);
12249
12250 /* display list of nonlinear handler */
12251 SCIPdialogMessage(scip, NULL, "\n");
12252 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12253 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12254 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12255 {
12256 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12257 assert(nlhdlr != NULL);
12258
12259 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12260 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12263 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12264 SCIPdialogMessage(scip, NULL, "\n");
12265 }
12266 SCIPdialogMessage(scip, NULL, "\n");
12267
12268 /* next dialog will be root dialog again */
12269 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12270
12271 return SCIP_OKAY;
12272}
12273
12274/*
12275 * constraint handler specific interface methods
12276 */
12277
12278/** creates the handler for nonlinear constraints and includes it in SCIP */
12280 SCIP* scip /**< SCIP data structure */
12281 )
12282{
12283 SCIP_CONSHDLRDATA* conshdlrdata;
12284 SCIP_DIALOG* parentdialog;
12285
12286 /* create nonlinear constraint handler data */
12287 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12288 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12289 conshdlrdata->curboundstag = 1;
12290 conshdlrdata->lastboundrelax = 1;
12291 conshdlrdata->curpropboundstag = 1;
12292 conshdlrdata->newsoleventfilterpos = -1;
12293 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12294 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12295 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12296
12297 /* include constraint handler */
12303 conshdlrCopyNonlinear,
12304 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12305 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12306 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12307 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12308 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12309 consActiveNonlinear, consDeactiveNonlinear,
12310 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12311 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12312 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12313 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12314
12315 /* add nonlinear constraint handler parameters */
12316 /* TODO organize into more subcategories */
12317 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12318 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12319 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12320
12321 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12322 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12323 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12324
12325 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12326 "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",
12327 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12328
12329 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12330 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12331 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12332
12333 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12334 "by how much to relax constraint sides during bound tightening",
12335 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12336
12337 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12338 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12339 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12340
12341 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12342 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12343 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12344
12345 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12346 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12347 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12348
12349 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12350 "maximal number of auxiliary expressions per bilinear term",
12351 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12352
12353 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12354 "whether to reformulate products of binary variables during presolving",
12355 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12356
12357 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12358 "whether to use the AND constraint handler for reformulating binary products",
12359 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12360
12361 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12362 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12363 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12364
12365 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12366 "whether to forbid multiaggregation of nonlinear variables",
12367 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12368
12369 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12370 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12371 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12372
12373 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12374 "whether to (re)run propagation in enforcement",
12375 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12376
12377 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12378 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12379 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12380
12381 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12382 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12383 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12384
12385 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12386 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12387 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12388
12389 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12390 "whether to force \"strong\" cuts in enforcement",
12391 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12392
12393 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12394 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12395 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12396
12397 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12398 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12399 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12400
12401 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12402 "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",
12403 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12404
12405 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12406 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12407 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12408
12409 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12410 "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)",
12411 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12412
12413 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12414 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12415 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12416
12417 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12418 "whether to use external branching candidates and branching rules for branching",
12419 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12420
12421 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12422 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12423 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12424
12425 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12426 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12427 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12428
12429 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12430 "weight by how much to consider the violation assigned to a variable for its branching score",
12431 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12432
12433 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12434 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12435 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12436
12437 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12438 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12439 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12440
12441 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12442 "weight by how much to consider the pseudo cost of a variable for its branching score",
12443 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12444
12445 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12446 "weight by how much to consider the domain width in branching score",
12447 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12448
12449 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12450 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12451 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12452
12453 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12454 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12455 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12456
12457 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12458 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12459 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12460
12461 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12462 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12463 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12464
12465 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12466 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12467 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12468
12469 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12470 "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)",
12471 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12472
12473 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12474 "whether to assume that any constraint is convex",
12475 &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
12476
12477 /* include handler for bound change events */
12478 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12479 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12480 assert(conshdlrdata->eventhdlr != NULL);
12481
12482 /* include tables for statistics */
12485 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
12487
12490 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
12492
12493 /* create, include, and release display nlhdlrs dialog */
12494 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12495 {
12496 SCIP_DIALOG* dialog;
12497
12498 assert(parentdialog != NULL);
12499 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12500
12502 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12504 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12505 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12506 }
12507
12508 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12509 processNewSolutionEvent, NULL) );
12510
12511 return SCIP_OKAY;
12512}
12513
12514/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12516 SCIP* scip, /**< SCIP data structure */
12517 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12518 int priority, /**< priority of upgrading method */
12519 SCIP_Bool active, /**< should the upgrading method by active by default? */
12520 const char* conshdlrname /**< name of the constraint handler */
12521 )
12522{
12523 SCIP_CONSHDLR* conshdlr;
12524 SCIP_CONSHDLRDATA* conshdlrdata;
12525 CONSUPGRADE* consupgrade;
12527 char paramdesc[SCIP_MAXSTRLEN];
12528 int i;
12529
12530 assert(conshdlrname != NULL );
12531 assert(nlconsupgd != NULL);
12532
12533 /* find the nonlinear constraint handler */
12534 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12535 if( conshdlr == NULL )
12536 {
12537 SCIPerrorMessage("nonlinear constraint handler not found\n");
12538 return SCIP_PLUGINNOTFOUND;
12539 }
12540
12541 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12542 assert(conshdlrdata != NULL);
12543
12544 /* check whether upgrade method exists already */
12545 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12546 {
12547 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12548 {
12549#ifdef SCIP_DEBUG
12550 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12551#endif
12552 return SCIP_OKAY;
12553 }
12554 }
12555
12556 /* create a nonlinear constraint upgrade data object */
12557 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12558 consupgrade->consupgd = nlconsupgd;
12559 consupgrade->priority = priority;
12560 consupgrade->active = active;
12561
12562 /* insert nonlinear constraint upgrade method into constraint handler data */
12563 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12564 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12565
12566 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12567 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12568 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12569 conshdlrdata->consupgrades[i] = consupgrade;
12570 conshdlrdata->nconsupgrades++;
12571
12572 /* adds parameter to turn on and off the upgrading step */
12573 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12574 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12576 paramname, paramdesc,
12577 &consupgrade->active, FALSE, active, NULL, NULL) );
12578
12579 return SCIP_OKAY;
12580}
12581
12582/** creates and captures a nonlinear constraint
12583 *
12584 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12585 */
12587 SCIP* scip, /**< SCIP data structure */
12588 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12589 const char* name, /**< name of constraint */
12590 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12591 SCIP_Real lhs, /**< left hand side of constraint */
12592 SCIP_Real rhs, /**< right hand side of constraint */
12593 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12594 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12595 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12596 * Usually set to TRUE. */
12597 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12598 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12599 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12600 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12601 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12602 * Usually set to TRUE. */
12603 SCIP_Bool local, /**< is constraint only valid locally?
12604 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12605 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12606 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12607 * adds coefficients to this constraint. */
12608 SCIP_Bool dynamic, /**< is constraint subject to aging?
12609 * Usually set to FALSE. Set to TRUE for own cuts which
12610 * are separated as constraints. */
12611 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12612 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12613 )
12614{
12615 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12616 SCIP_CONSHDLR* conshdlr;
12617
12618 /* find the nonlinear constraint handler */
12619 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12620 if( conshdlr == NULL )
12621 {
12622 SCIPerrorMessage("nonlinear constraint handler not found\n");
12623 return SCIP_PLUGINNOTFOUND;
12624 }
12625
12626 /* create constraint */
12627 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12628 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12629
12630 return SCIP_OKAY;
12631}
12632
12633/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12634 *
12635 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12636 *
12637 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12638 *
12639 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12640 */
12642 SCIP* scip, /**< SCIP data structure */
12643 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12644 const char* name, /**< name of constraint */
12645 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12646 SCIP_Real lhs, /**< left hand side of constraint */
12647 SCIP_Real rhs /**< right hand side of constraint */
12648 )
12649{
12650 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12652
12653 return SCIP_OKAY;
12654}
12655
12656/** creates and captures a quadratic nonlinear constraint
12657 *
12658 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12659 */
12661 SCIP* scip, /**< SCIP data structure */
12662 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12663 const char* name, /**< name of constraint */
12664 int nlinvars, /**< number of linear terms */
12665 SCIP_VAR** linvars, /**< array with variables in linear part */
12666 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12667 int nquadterms, /**< number of quadratic terms */
12668 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12669 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12670 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12671 SCIP_Real lhs, /**< left hand side of quadratic equation */
12672 SCIP_Real rhs, /**< right hand side of quadratic equation */
12673 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12674 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12675 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12676 * Usually set to TRUE. */
12677 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12678 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12679 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12680 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12681 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12682 * Usually set to TRUE. */
12683 SCIP_Bool local, /**< is constraint only valid locally?
12684 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12685 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12686 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12687 * adds coefficients to this constraint. */
12688 SCIP_Bool dynamic, /**< is constraint subject to aging?
12689 * Usually set to FALSE. Set to TRUE for own cuts which
12690 * are separated as constraints. */
12691 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12692 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12693 )
12694{
12695 SCIP_CONSHDLR* conshdlr;
12696 SCIP_EXPR* expr;
12697
12698 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12699 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12700
12701 /* get nonlinear constraint handler */
12702 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12703 if( conshdlr == NULL )
12704 {
12705 SCIPerrorMessage("nonlinear constraint handler not found\n");
12706 return SCIP_PLUGINNOTFOUND;
12707 }
12708
12709 /* create quadratic expression */
12710 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12711 assert(expr != NULL);
12712
12713 /* create nonlinear constraint */
12714 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12715 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12716
12717 /* release quadratic expression (captured by constraint now) */
12718 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12719
12720 return SCIP_OKAY;
12721}
12722
12723/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12724 *
12725 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12726 *
12727 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12728 *
12729 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12730 */
12732 SCIP* scip, /**< SCIP data structure */
12733 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12734 const char* name, /**< name of constraint */
12735 int nlinvars, /**< number of linear terms */
12736 SCIP_VAR** linvars, /**< array with variables in linear part */
12737 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12738 int nquadterms, /**< number of quadratic terms */
12739 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12740 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12741 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12742 SCIP_Real lhs, /**< left hand side of quadratic equation */
12743 SCIP_Real rhs /**< right hand side of quadratic equation */
12744 )
12745{
12746 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12748
12749 return SCIP_OKAY;
12750}
12751
12752/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12753 *
12754 * \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$
12755 *
12756 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12757 */
12759 SCIP* scip, /**< SCIP data structure */
12760 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12761 const char* name, /**< name of constraint */
12762 int nvars, /**< number of variables on left hand side of constraint (n) */
12763 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12764 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12765 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12766 SCIP_Real constant, /**< constant on left hand side (gamma) */
12767 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12768 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12769 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12770 )
12771{
12772 SCIP_EXPR* expr;
12773 SCIP_EXPR* lhssum;
12774 SCIP_EXPR* terms[2];
12775 SCIP_Real termcoefs[2];
12776 int i;
12777
12778 assert(vars != NULL || nvars == 0);
12779
12780 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
12781 for( i = 0; i < nvars; ++i )
12782 {
12783 SCIP_EXPR* varexpr;
12784 SCIP_EXPR* powexpr;
12785
12786 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
12787 if( offsets != NULL && offsets[i] != 0.0 )
12788 {
12789 SCIP_EXPR* sum;
12790 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
12791 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
12792 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12793 }
12794 else
12795 {
12796 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
12797 }
12798
12799 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
12800 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12801 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
12802 }
12803
12804 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
12805 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
12806 termcoefs[0] = 1.0;
12807
12808 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
12809 termcoefs[1] = -rhscoeff;
12810
12811 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
12812
12813 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12814 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12815
12816 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
12817
12818 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12819
12820 return SCIP_OKAY;
12821}
12822
12823/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12824 *
12825 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12826 *
12827 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12828 */
12830 SCIP* scip, /**< SCIP data structure */
12831 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12832 const char* name, /**< name of constraint */
12833 SCIP_VAR* x, /**< nonlinear variable x in constraint */
12834 SCIP_VAR* z, /**< linear variable z in constraint */
12835 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
12836 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
12837 SCIP_Real zcoef, /**< coefficient of z in constraint */
12838 SCIP_Real lhs, /**< left hand side of constraint */
12839 SCIP_Real rhs /**< right hand side of constraint */
12840 )
12841{
12842 SCIP_EXPR* xexpr;
12843 SCIP_EXPR* terms[2];
12844 SCIP_Real coefs[2];
12845 SCIP_EXPR* sumexpr;
12846
12847 assert(x != NULL);
12848 assert(z != NULL);
12849
12850 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
12851 if( xoffset != 0.0 )
12852 {
12853 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12854 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12855
12856 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12857 }
12858 else
12859 {
12860 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
12861 }
12862 coefs[0] = 1.0;
12863
12864 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
12865 coefs[1] = zcoef;
12866
12867 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
12868
12869 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12870
12871 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12872 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12873 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12874 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
12875
12876 return SCIP_OKAY;
12877}
12878
12879/** gets tag indicating current local variable bounds */
12881 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12882 )
12883{
12884 SCIP_CONSHDLRDATA* conshdlrdata;
12885
12886 assert(conshdlr != NULL);
12887 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12888
12889 return conshdlrdata->curboundstag;
12890}
12891
12892/** gets the `curboundstag` from the last time where variable bounds were relaxed */
12894 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12895 )
12896{
12897 SCIP_CONSHDLRDATA* conshdlrdata;
12898
12899 assert(conshdlr != NULL);
12900 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12901
12902 return conshdlrdata->lastboundrelax;
12903}
12904
12905/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12906 *
12907 * @attention This method is not intended for normal use.
12908 * These tags are maintained by the event handler for variable bound change events.
12909 * This method is used by some unittests.
12910 */
12912 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12913 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12914 )
12915{
12916 SCIP_CONSHDLRDATA* conshdlrdata;
12917
12918 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12919 assert(conshdlrdata != NULL);
12920
12921 ++conshdlrdata->curboundstag;
12922 assert(conshdlrdata->curboundstag > 0);
12923
12924 if( boundrelax )
12925 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
12926}
12927
12928/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
12930 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12931 )
12932{
12933 assert(conshdlr != NULL);
12934
12935 return SCIPconshdlrGetData(conshdlr)->var2expr;
12936}
12937
12938/** processes a rowprep for cut addition and maybe report branchscores */
12940 SCIP* scip, /**< SCIP data structure */
12941 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
12942 SCIP_CONS* cons, /**< nonlinear constraint */
12943 SCIP_EXPR* expr, /**< expression */
12944 SCIP_ROWPREP* rowprep, /**< cut to be added */
12945 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
12946 SCIP_VAR* auxvar, /**< auxiliary variable */
12947 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
12948 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
12949 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
12950 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
12951 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
12952 SCIP_RESULT* result /**< pointer to store the result */
12953 )
12954{
12955 SCIP_Real cutviol;
12956 SCIP_CONSHDLRDATA* conshdlrdata;
12957 SCIP_Real auxvarvalue = SCIP_INVALID;
12958 SCIP_Bool sepasuccess;
12959 SCIP_Real estimateval = SCIP_INVALID;
12960 SCIP_Real mincutviolation;
12961
12962 assert(nlhdlr != NULL);
12963 assert(cons != NULL);
12964 assert(expr != NULL);
12965 assert(rowprep != NULL);
12966 assert(auxvar != NULL);
12967 assert(result != NULL);
12968
12969 /* decide on minimal violation of cut */
12970 if( sol == NULL )
12971 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
12972 else
12973 mincutviolation = SCIPfeastol(scip);
12974
12975 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
12976 assert(conshdlrdata != NULL);
12977
12978 sepasuccess = TRUE;
12979
12980 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
12981 if( cutviol > 0.0 )
12982 {
12983 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
12984
12985 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
12986 if( !allowweakcuts && auxvalue != SCIP_INVALID )
12987 {
12988 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
12989 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
12990 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
12991 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
12992 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
12993 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
12994 *
12995 * if we are overestimating, we have z >= c'x-b >= f(x)
12996 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
12997 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
12998 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
12999 *
13000 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13001 */
13002 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13003 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13004 {
13005 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13006 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13007 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13008 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13009 sepasuccess = FALSE;
13010 }
13011 }
13012
13013 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13014 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13015 }
13016 else
13017 {
13018 sepasuccess = FALSE;
13019 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13020 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13021 }
13022
13023 /* clean up estimator */
13024 if( sepasuccess )
13025 {
13026 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13027 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13028 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13029 SCIPprintRowprep(scip, rowprep, enfologfile); )
13030
13031 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13032 * instead, may even scale them down, that is, scale so that max coef is close to 1
13033 */
13034 if( !allowweakcuts )
13035 {
13036 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13037
13038 if( !sepasuccess )
13039 {
13040 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13041 }
13042 else
13043 {
13044 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13045 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13046 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13047 if( sepasuccess )
13048 sepasuccess = cutviol > mincutviolation;
13049 }
13050
13051 if( sepasuccess && auxvalue != SCIP_INVALID )
13052 {
13053 /* check whether cut is weak now
13054 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13055 * reconstructing estimateval from cutviol (TODO improve or remove?)
13056 */
13057 SCIP_Real auxvarcoef = 0.0;
13058 int i;
13059
13060 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13061 * it should be...
13062 */
13063 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13064 {
13065 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13066 {
13067 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13068 break;
13069 }
13070 }
13071
13072 if( auxvarcoef == 0.0 ||
13073 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13074 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13075 {
13076 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13077 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13078 sepasuccess = FALSE;
13079 }
13080 }
13081 }
13082 else
13083 {
13084 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13085
13086 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13087 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13088 */
13089 if( !branchscoresuccess )
13091
13092 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13093
13094 if( !sepasuccess )
13095 {
13096 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13097 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13098 }
13099
13100 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13101 * changed
13102 */
13103 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13104 {
13105 SCIP_Real violscore;
13106
13107#ifdef BRSCORE_ABSVIOL
13108 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13109#else
13110 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13111#endif
13112 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13113
13114 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13115 * - were fixed,
13116 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13117 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13118 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13119 * so I'm disabling the assert for now
13120 */
13121 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13122 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13123 }
13124 }
13125 }
13126
13127 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13128 if( sepasuccess )
13129 {
13130 SCIP_ROW* row;
13131
13132 if( conshdlrdata->branchdualweight > 0.0 )
13133 {
13134 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13135 * skip if gap is zero
13136 */
13137 if( auxvalue == SCIP_INVALID )
13138 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13139 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13140 {
13141 char gap[40];
13142 /* coverity[secure_coding] */
13143 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13144 strcat(SCIProwprepGetName(rowprep), gap);
13145 }
13146 }
13147
13148 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13149
13150 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13151 {
13152 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13154 }
13155 else if( !SCIPisCutApplicable(scip, row) )
13156 {
13157 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13158 }
13159 else
13160 {
13161 SCIP_Bool infeasible;
13162
13163 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13164 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13165
13166 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13167 * if we haven't found strong cuts before)
13168 */
13169 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13170
13171 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13172 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13174
13175 if( infeasible )
13176 {
13179 }
13180 else
13181 {
13184 }
13185 }
13186
13187 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13188 }
13189 else if( branchscoresuccess )
13190 {
13191 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13192 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13193
13194 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13195 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13196 */
13198 }
13199 else
13200 {
13201 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13202 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13203 " (!)" : ""); )
13204 }
13205
13206 return SCIP_OKAY;
13207}
13208
13209/** returns whether all nonlinear constraints are assumed to be convex */
13211 SCIP_CONSHDLR* conshdlr
13212 )
13213{
13214 SCIP_CONSHDLRDATA* conshdlrdata;
13215
13216 assert(conshdlr != NULL);
13217
13218 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13219 assert(conshdlrdata != NULL);
13220
13221 return conshdlrdata->assumeconvex;
13222}
13223
13224/** collects all bilinear terms for a given set of constraints
13225 *
13226 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13227 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13228 */
13230 SCIP* scip, /**< SCIP data structure */
13231 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13232 SCIP_CONS** conss, /**< nonlinear constraints */
13233 int nconss /**< total number of nonlinear constraints */
13234 )
13235{
13236 assert(conshdlr != NULL);
13237 assert(conss != NULL || nconss == 0);
13238
13239 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13240
13241 return SCIP_OKAY;
13242}
13243
13244/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13245 *
13246 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13247 */
13249 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13250 )
13251{
13252 SCIP_CONSHDLRDATA* conshdlrdata;
13253
13254 assert(conshdlr != NULL);
13255
13256 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13257 assert(conshdlrdata != NULL);
13258
13259 return conshdlrdata->nbilinterms;
13260}
13261
13262/** returns all bilinear terms that are contained in all nonlinear constraints
13263 *
13264 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13265 * @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.
13266 */
13268 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13269 )
13270{
13271 SCIP_CONSHDLRDATA* conshdlrdata;
13272
13273 assert(conshdlr != NULL);
13274
13275 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13276 assert(conshdlrdata != NULL);
13277
13278 return conshdlrdata->bilinterms;
13279}
13280
13281/** returns the index of the bilinear term representing the product of the two given variables
13282 *
13283 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13284 * @return The method returns -1 if the variables do not appear bilinearly.
13285 */
13287 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13288 SCIP_VAR* x, /**< first variable */
13289 SCIP_VAR* y /**< second variable */
13290 )
13291{
13292 SCIP_CONSHDLRDATA* conshdlrdata;
13294 int idx;
13295
13296 assert(conshdlr != NULL);
13297 assert(x != NULL);
13298 assert(y != NULL);
13299
13300 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13301 assert(conshdlrdata != NULL);
13302
13303 if( conshdlrdata->bilinhashtable == NULL )
13304 {
13305 return -1;
13306 }
13307
13308 /* ensure that x.index <= y.index */
13309 if( SCIPvarCompare(x, y) == 1 )
13310 {
13311 SCIPswapPointers((void**)&x, (void**)&y);
13312 }
13313 assert(SCIPvarCompare(x, y) < 1);
13314
13315 /* use a new entry to find the image in the bilinear hash table */
13316 entry.x = x;
13317 entry.y = y;
13318 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13319 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13320 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13321 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13322
13323 return idx;
13324}
13325
13326/** returns the bilinear term that represents the product of two given variables
13327 *
13328 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13329 * @return The method returns NULL if the variables do not appear bilinearly.
13330 */
13332 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13333 SCIP_VAR* x, /**< first variable */
13334 SCIP_VAR* y /**< second variable */
13335 )
13336{
13337 SCIP_CONSHDLRDATA* conshdlrdata;
13338 int idx;
13339
13340 assert(conshdlr != NULL);
13341 assert(x != NULL);
13342 assert(y != NULL);
13343
13344 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13345 assert(conshdlrdata != NULL);
13346
13347 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13348 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13349
13350 if( idx >= 0 )
13351 {
13352 return &conshdlrdata->bilinterms[idx];
13353 }
13354
13355 return NULL;
13356}
13357
13358/** evaluates an auxiliary expression for a bilinear term */
13360 SCIP* scip, /**< SCIP data structure */
13361 SCIP_VAR* x, /**< first variable of the bilinear term */
13362 SCIP_VAR* y, /**< second variable of the bilinear term */
13363 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13364 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13365 )
13366{
13367 assert(scip != NULL);
13368 assert(x != NULL);
13369 assert(y != NULL);
13370 assert(auxexpr != NULL);
13371 assert(auxexpr->auxvar != NULL);
13372
13373 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13374 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13375}
13376
13377/** stores the variables of a bilinear term in the data of the constraint handler */
13379 SCIP* scip, /**< SCIP data structure */
13380 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13381 SCIP_VAR* x, /**< first variable */
13382 SCIP_VAR* y, /**< second variable */
13383 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13384 int nlockspos, /**< number of positive expression locks */
13385 int nlocksneg /**< number of negative expression locks */
13386 )
13387{
13388 SCIP_CONSHDLRDATA* conshdlrdata;
13390 int idx;
13391
13392 assert(conshdlr != NULL);
13393
13394 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13395 assert(conshdlrdata != NULL);
13396
13397 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13398
13399 term = &conshdlrdata->bilinterms[idx];
13400 assert(term != NULL);
13401 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13402 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) */
13403
13404 /* store and capture auxiliary variable */
13405 if( auxvar != NULL )
13406 {
13407 term->aux.var = auxvar;
13408 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13409 }
13410
13411 return SCIP_OKAY;
13412}
13413
13414/** stores the variables of a bilinear term in the data of the constraint handler */
13416 SCIP* scip, /**< SCIP data structure */
13417 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13418 SCIP_VAR* x, /**< first variable */
13419 SCIP_VAR* y, /**< second variable */
13420 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13421 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13422 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13423 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13424 SCIP_Real cst, /**< constant of the auxiliary expression */
13425 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13426 )
13427{
13428 SCIP_CONSHDLRDATA* conshdlrdata;
13431 int idx;
13432 int nlockspos;
13433 int nlocksneg;
13434 SCIP_Bool added;
13435
13436 assert(conshdlr != NULL);
13437
13438 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13439 assert(conshdlrdata != NULL);
13440
13441 nlockspos = overestimate ? 1 : 0;
13442 nlocksneg = overestimate ? 0 : 1;
13443
13444 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13445
13446 term = &conshdlrdata->bilinterms[idx];
13447 assert(term != NULL);
13448 assert(SCIPvarCompare(term->x, term->y) < 1);
13449
13450 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13451 {
13452 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13453 /* this is the case where we are adding an implicitly defined relation for a product that has already
13454 * been explicitly defined; convert auxvar into an auxexpr */
13455
13456 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13457 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13458 return SCIP_OKAY;
13459
13460 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13461 auxvarexpr->cst = 0.0;
13462 auxvarexpr->coefs[0] = 1.0;
13463 auxvarexpr->coefs[1] = 0.0;
13464 auxvarexpr->coefs[2] = 0.0;
13465 auxvarexpr->auxvar = term->aux.var;
13466 auxvarexpr->underestimate = term->nlocksneg > 0;
13467 auxvarexpr->overestimate = term->nlockspos > 0;
13468
13469 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13470 term->aux.exprs = NULL;
13471
13472 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13473
13474 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13475 assert(added);
13476 }
13477
13478 /* create and add auxexpr */
13479 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13480 auxexpr->underestimate = !overestimate;
13481 auxexpr->overestimate = overestimate;
13482 auxexpr->auxvar = auxvar;
13483 auxexpr->coefs[0] = coefaux;
13484 if( term->x == x )
13485 {
13486 assert(term->y == y);
13487 auxexpr->coefs[1] = coefx;
13488 auxexpr->coefs[2] = coefy;
13489 }
13490 else
13491 {
13492 assert(term->x == y);
13493 assert(term->y == x);
13494 auxexpr->coefs[1] = coefy;
13495 auxexpr->coefs[2] = coefx;
13496 }
13497 auxexpr->cst = cst;
13498 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13499
13500 if( !added )
13501 {
13502 SCIPfreeBlockMemory(scip, &auxexpr);
13503 }
13504 else if( auxvar != NULL )
13505 { /* capture auxiliary variable */
13506 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13507 }
13508
13509 return SCIP_OKAY;
13510}
13511
13512/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13514 SCIP* scip, /**< SCIP data structure */
13515 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13516 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13517 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13518 void* fundata, /**< data for function evaluation (can be NULL) */
13519 SCIP_Real* xstar, /**< point to be separated */
13520 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13521 int nallvars, /**< half of the length of box */
13522 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13523 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13524 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13525 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13526 )
13527{
13528 SCIP_Real* corner;
13529 SCIP_Real* funvals;
13530 int* nonfixedpos;
13531 SCIP_Real maxfaceterror;
13532 int nvars; /* number of nonfixed variables */
13533 unsigned int ncorners;
13534 unsigned int i;
13535 int j;
13536
13537 assert(scip != NULL);
13538 assert(conshdlr != NULL);
13539 assert(function != NULL);
13540 assert(xstar != NULL);
13541 assert(box != NULL);
13542 assert(success != NULL);
13543 assert(facetcoefs != NULL);
13544 assert(facetconstant != NULL);
13545
13546 *success = FALSE;
13547
13548 /* identify fixed variables */
13549 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13550 nvars = 0;
13551 for( j = 0; j < nallvars; ++j )
13552 {
13553 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13554 continue;
13555 nonfixedpos[nvars] = j;
13556 nvars++;
13557 }
13558
13559 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13560 * if too many variables are not fixed, then we do nothing currently
13561 */
13562 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13563 {
13564 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13565 SCIPfreeBufferArray(scip, &nonfixedpos);
13566 return SCIP_OKAY;
13567 }
13568
13569 /* compute f(v^i) for each corner v^i of [l,u] */
13570 ncorners = POWEROFTWO(nvars);
13571 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13572 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13573 for( j = 0; j < nallvars; ++j )
13574 {
13575 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13576 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13577 }
13578 for( i = 0; i < ncorners; ++i )
13579 {
13580 SCIPdebugMsg(scip, "corner %u: ", i);
13581 for( j = 0; j < nvars; ++j )
13582 {
13583 int varpos = nonfixedpos[j];
13584 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13585 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13586 */
13587 if( (i >> j) & 0x1 )
13588 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13589 else
13590 corner[varpos] = box[2 * varpos ]; /* lb of var */
13591 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13592 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13593 }
13594
13595 funvals[i] = function(corner, nallvars, fundata);
13596
13597 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13598
13599 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13600 {
13601 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13602 goto CLEANUP;
13603 }
13604 }
13605
13606 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13607 BMSclearMemoryArray(facetcoefs, nallvars);
13608
13609 if( nvars == 1 )
13610 {
13611 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13612
13613 /* check whether target has been missed */
13614 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13615 {
13616 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13617 *success = FALSE;
13618 }
13619 }
13620 else if( nvars == 2 && SCIPlapackIsAvailable() )
13621 {
13622 int idx1 = nonfixedpos[0];
13623 int idx2 = nonfixedpos[1];
13624 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13625 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13626 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13627 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13628 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13629 SCIP_Real coefs[2] = { 0.0, 0.0 };
13630
13631 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13632
13633 facetcoefs[idx1] = coefs[0];
13634 facetcoefs[idx2] = coefs[1];
13635 }
13636 else
13637 {
13638 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13639 }
13640 if( !*success )
13641 {
13642 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13643 goto CLEANUP;
13644 }
13645
13646 /*
13647 * check and adjust facet with the algorithm of Rikun et al.
13648 */
13649
13650 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13651
13652 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13653 if( maxfaceterror > 0.0 )
13654 {
13655 SCIP_CONSHDLRDATA* conshdlrdata;
13656 SCIP_Real midval;
13657 SCIP_Real feastol;
13658
13660
13661 /* evaluate function in middle point to get some idea for a scaling */
13662 for( j = 0; j < nvars; ++j )
13663 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13664 midval = function(corner, nallvars, fundata);
13665 if( midval == SCIP_INVALID )
13666 midval = 1.0;
13667
13668 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13669 assert(conshdlrdata != NULL);
13670
13671 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13672 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13673 {
13674 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13675 *success = FALSE;
13676 goto CLEANUP;
13677 }
13678
13679 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13680
13681 if( overestimate )
13682 *facetconstant += maxfaceterror;
13683 else
13684 *facetconstant -= maxfaceterror;
13685 }
13686
13687 /* if we made it until here, then we have a nice facet */
13688 assert(*success);
13689
13690CLEANUP:
13691 /* free allocated memory */
13692 SCIPfreeBufferArray(scip, &corner);
13693 SCIPfreeBufferArray(scip, &funvals);
13694 SCIPfreeBufferArray(scip, &nonfixedpos);
13695
13696 return SCIP_OKAY;
13697}
13698
13699/*
13700 * constraint specific interface methods
13701 */
13702
13703/** returns the expression of the given nonlinear constraint */
13705 SCIP_CONS* cons /**< constraint data */
13706 )
13707{
13708 SCIP_CONSDATA* consdata;
13709
13710 assert(cons != NULL);
13712
13713 consdata = SCIPconsGetData(cons);
13714 assert(consdata != NULL);
13715
13716 return consdata->expr;
13717}
13718
13719/** gets the left hand side of a nonlinear constraint */
13721 SCIP_CONS* cons /**< constraint data */
13722 )
13723{
13724 SCIP_CONSDATA* consdata;
13725
13726 assert(cons != NULL);
13728
13729 consdata = SCIPconsGetData(cons);
13730 assert(consdata != NULL);
13731
13732 return consdata->lhs;
13733}
13734
13735/** gets the right hand side of a nonlinear constraint */
13737 SCIP_CONS* cons /**< constraint data */
13738 )
13739{
13740 SCIP_CONSDATA* consdata;
13741
13742 assert(cons != NULL);
13744
13745 consdata = SCIPconsGetData(cons);
13746 assert(consdata != NULL);
13747
13748 return consdata->rhs;
13749}
13750
13751/** gets the nonlinear constraint as a nonlinear row representation. */
13753 SCIP* scip, /**< SCIP data structure */
13754 SCIP_CONS* cons, /**< constraint */
13755 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13756 )
13757{
13758 SCIP_CONSDATA* consdata;
13759
13760 assert(cons != NULL);
13761 assert(nlrow != NULL);
13763
13764 consdata = SCIPconsGetData(cons);
13765 assert(consdata != NULL);
13766
13767 if( consdata->nlrow == NULL )
13768 {
13769 SCIP_CALL( createNlRow(scip, cons) );
13770 }
13771 assert(consdata->nlrow != NULL);
13772 *nlrow = consdata->nlrow;
13773
13774 return SCIP_OKAY;
13775}
13776
13777/** returns the curvature of the expression of a given nonlinear constraint
13778 *
13779 * @note The curvature information is computed during CONSINITSOL.
13780 */
13782 SCIP_CONS* cons /**< constraint data */
13783 )
13784{
13785 SCIP_CONSDATA* consdata;
13786
13787 assert(cons != NULL);
13789
13790 consdata = SCIPconsGetData(cons);
13791 assert(consdata != NULL);
13792
13793 return consdata->curv;
13794}
13795
13796/** checks whether expression of constraint can be represented as quadratic form
13797 *
13798 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13799 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13800 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13801 */
13803 SCIP* scip, /**< SCIP data structure */
13804 SCIP_CONS* cons, /**< constraint data */
13805 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
13806 )
13807{
13808 SCIP_CONSDATA* consdata;
13809
13810 assert(scip != NULL);
13811 assert(cons != NULL);
13812 assert(isquadratic != NULL);
13814
13815 consdata = SCIPconsGetData(cons);
13816 assert(consdata != NULL);
13817 assert(consdata->expr != NULL);
13818
13819 /* check whether constraint expression is quadratic in extended formulation */
13820 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13821
13822 /* if not quadratic in non-extended formulation, then do indicate quadratic */
13823 if( *isquadratic )
13824 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
13825
13826 return SCIP_OKAY;
13827}
13828
13829/** changes left-hand-side of a nonlinear constraint
13830 *
13831 * @attention This method can only be called in the problem stage.
13832 */
13834 SCIP* scip, /**< SCIP data structure */
13835 SCIP_CONS* cons, /**< constraint data */
13836 SCIP_Real lhs /**< new left-hand-side */
13837 )
13838{
13839 SCIP_CONSDATA* consdata;
13840
13841 assert(scip != NULL);
13842 assert(cons != NULL);
13844
13846 {
13847 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13848 return SCIP_INVALIDCALL;
13849 }
13850
13851 /* we should have an original constraint */
13853
13854 consdata = SCIPconsGetData(cons);
13855 assert(consdata != NULL);
13856
13857 if( consdata->lhs == lhs )
13858 return SCIP_OKAY;
13859
13860 consdata->lhs = lhs;
13861
13862 /* not sure we care about any of these flags for original constraints */
13863 consdata->ispropagated = FALSE;
13864
13865 return SCIP_OKAY;
13866}
13867
13868/** changes right-hand-side of a nonlinear constraint
13869 *
13870 * @attention This method can only be called in the problem stage.
13871 */
13873 SCIP* scip, /**< SCIP data structure */
13874 SCIP_CONS* cons, /**< constraint data */
13875 SCIP_Real rhs /**< new right-hand-side */
13876 )
13877{
13878 SCIP_CONSDATA* consdata;
13879
13880 assert(scip != NULL);
13881 assert(cons != NULL);
13883
13885 {
13886 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13887 return SCIP_INVALIDCALL;
13888 }
13889
13890 /* we should have an original constraint */
13892
13893 consdata = SCIPconsGetData(cons);
13894 assert(consdata != NULL);
13895
13896 if( consdata->rhs == rhs )
13897 return SCIP_OKAY;
13898
13899 consdata->rhs = rhs;
13900
13901 /* not sure we care about any of these flags for original constraints */
13902 consdata->ispropagated = FALSE;
13903
13904 return SCIP_OKAY;
13905}
13906
13907/** changes expression of a nonlinear constraint
13908 *
13909 * @attention This method can only be called in the problem stage.
13910 */
13912 SCIP* scip, /**< SCIP data structure */
13913 SCIP_CONS* cons, /**< constraint data */
13914 SCIP_EXPR* expr /**< new expression */
13915 )
13916{
13917 SCIP_CONSHDLR* conshdlr;
13918 SCIP_CONSDATA* consdata;
13919
13920 assert(scip != NULL);
13921 assert(cons != NULL);
13922 assert(expr != NULL);
13923
13925 {
13926 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
13927 return SCIP_INVALIDCALL;
13928 }
13929
13930 /* we should have an original constraint */
13932
13933 conshdlr = SCIPconsGetHdlr(cons);
13934 assert(conshdlr != NULL);
13935 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13936
13937 consdata = SCIPconsGetData(cons);
13938 assert(consdata != NULL);
13939 assert(consdata->expr != NULL);
13940
13941 /* we should not have collected additional data for the expr
13942 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13943 */
13944 assert(consdata->nvarexprs == 0);
13945 assert(consdata->varexprs == NULL);
13946 assert(!consdata->catchedevents);
13947
13948 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
13949
13950 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13951 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13952
13953 /* not sure we care about any of these flags for original constraints */
13954 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
13955 consdata->issimplified = FALSE;
13956 consdata->ispropagated = FALSE;
13957
13958 return SCIP_OKAY;
13959}
13960
13961/** adds coef * var to nonlinear constraint
13962 *
13963 * @attention This method can only be called in the problem stage.
13964 */
13966 SCIP* scip, /**< SCIP data structure */
13967 SCIP_CONS* cons, /**< constraint data */
13968 SCIP_VAR* var, /**< variable */
13969 SCIP_Real coef /**< coefficient */
13970 )
13971{
13972 SCIP_CONSHDLR* conshdlr;
13973 SCIP_CONSDATA* consdata;
13974 SCIP_EXPR* varexpr;
13975
13976 assert(scip != NULL);
13977 assert(cons != NULL);
13978
13980 {
13981 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13982 return SCIP_INVALIDCALL;
13983 }
13984
13985 /* we should have an original constraint */
13987
13988 if( coef == 0.0 )
13989 return SCIP_OKAY;
13990
13991 conshdlr = SCIPconsGetHdlr(cons);
13992 assert(conshdlr != NULL);
13993 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13994
13995 consdata = SCIPconsGetData(cons);
13996 assert(consdata != NULL);
13997 assert(consdata->expr != NULL);
13998
13999 /* we should not have collected additional data for it
14000 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14001 */
14002 assert(consdata->nvarexprs == 0);
14003 assert(consdata->varexprs == NULL);
14004 assert(!consdata->catchedevents);
14005
14006 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14007
14008 /* append to sum, if consdata->expr is sum and not used anywhere else */
14009 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14010 {
14011 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14012 }
14013 else
14014 {
14015 /* create new expression = 1 * consdata->expr + coef * var */
14016 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14017 SCIP_Real coefs[2] = { 1.0, coef };
14018
14019 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14020
14021 /* release old root expr */
14022 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14023 }
14024
14025 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14026
14027 /* not sure we care about any of these flags for original constraints */
14028 consdata->issimplified = FALSE;
14029 consdata->ispropagated = FALSE;
14030
14031 return SCIP_OKAY;
14032}
14033
14034/** adds coef * expr to nonlinear constraint
14035 *
14036 * @attention This method can only be called in the problem stage.
14037 */
14039 SCIP* scip, /**< SCIP data structure */
14040 SCIP_CONS* cons, /**< nonlinear constraint */
14041 SCIP_EXPR* expr, /**< expression */
14042 SCIP_Real coef /**< coefficient */
14043 )
14044{
14045 SCIP_CONSHDLR* conshdlr;
14046 SCIP_CONSDATA* consdata;
14047 SCIP_EXPR* exprowned;
14048
14049 assert(scip != NULL);
14050 assert(cons != NULL);
14051
14053 {
14054 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14055 return SCIP_INVALIDCALL;
14056 }
14057
14058 /* we should have an original constraint */
14060
14061 if( coef == 0.0 )
14062 return SCIP_OKAY;
14063
14064 conshdlr = SCIPconsGetHdlr(cons);
14065 assert(conshdlr != NULL);
14066 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14067
14068 consdata = SCIPconsGetData(cons);
14069 assert(consdata != NULL);
14070 assert(consdata->expr != NULL);
14071
14072 /* we should not have collected additional data for it
14073 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14074 */
14075 assert(consdata->nvarexprs == 0);
14076 assert(consdata->varexprs == NULL);
14077 assert(!consdata->catchedevents);
14078
14079 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14080 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14081
14082 /* append to sum, if consdata->expr is sum and not used anywhere else */
14083 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14084 {
14085 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14086 }
14087 else
14088 {
14089 /* create new expression = 1 * consdata->expr + coef * var */
14090 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14091 SCIP_Real coefs[2] = { 1.0, coef };
14092
14093 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14094
14095 /* release old root expr */
14096 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14097 }
14098
14099 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14100
14101 /* not sure we care about any of these flags for original constraints */
14102 consdata->issimplified = FALSE;
14103 consdata->ispropagated = FALSE;
14104
14105 return SCIP_OKAY;
14106}
14107
14108/** computes value of constraint expression in a given solution
14109 *
14110 * Stores value of constraint expression in sol in activity.
14111 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14112 */
14114 SCIP* scip, /**< SCIP data structure */
14115 SCIP_CONS* cons, /**< constraint */
14116 SCIP_SOL* sol, /**< solution */
14117 SCIP_Real* activity /**< buffer to store computed activity */
14118 )
14119{
14120 SCIP_CONSDATA* consdata;
14121
14122 assert(cons != NULL);
14123 assert(activity != NULL);
14124
14125 consdata = SCIPconsGetData(cons);
14126 assert(consdata != NULL);
14127
14128 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14129 *activity = SCIPexprGetEvalValue(consdata->expr);
14130
14131 return SCIP_OKAY;
14132}
14133
14134/** gets absolute violation of nonlinear constraint
14135 *
14136 * This function evaluates the constraints in the given solution.
14137 *
14138 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14139 */
14141 SCIP* scip, /**< SCIP data structure */
14142 SCIP_CONS* cons, /**< constraint */
14143 SCIP_SOL* sol, /**< solution to check */
14144 SCIP_Real* viol /**< buffer to store computed violation */
14145 )
14146{
14147 assert(cons != NULL);
14148 assert(viol != NULL);
14149
14150 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14151 *viol = getConsAbsViolation(cons);
14152
14153 return SCIP_OKAY;
14154}
14155
14156/** gets scaled violation of nonlinear constraint
14157 *
14158 * This function evaluates the constraints in the given solution.
14159 *
14160 * The scaling that is applied to the absolute violation of the constraint
14161 * depends on the setting of parameter constraints/nonlinear/violscale.
14162 */
14164 SCIP* scip, /**< SCIP data structure */
14165 SCIP_CONS* cons, /**< constraint */
14166 SCIP_SOL* sol, /**< solution to check */
14167 SCIP_Real* viol /**< buffer to store computed violation */
14168 )
14169{
14170 assert(cons != NULL);
14171 assert(viol != NULL);
14172
14173 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14174 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14175
14176 return SCIP_OKAY;
14177}
14178
14179/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14181 SCIP* scip, /**< SCIP data structure */
14182 SCIP_CONS* cons, /**< nonlinear constraint */
14183 SCIP_VAR** var, /**< pointer to store the variable */
14184 SCIP_Real* coef /**< pointer to store the coefficient */
14185 )
14186{
14187 SCIP_CONSDATA* consdata;
14188
14189 assert(cons != NULL);
14190 assert(var != NULL);
14191 assert(coef != NULL);
14192
14193 /* check for a linear variable that can be increased or decreased without harming feasibility */
14195
14196 consdata = SCIPconsGetData(cons);
14197 assert(consdata != NULL);
14198
14199 *var = consdata->linvardecr;
14200 *coef = consdata->linvardecrcoef;
14201}
14202
14203/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14205 SCIP* scip, /**< SCIP data structure */
14206 SCIP_CONS* cons, /**< nonlinear constraint */
14207 SCIP_VAR** var, /**< pointer to store the variable */
14208 SCIP_Real* coef /**< pointer to store the coefficient */
14209 )
14210{
14211 SCIP_CONSDATA* consdata;
14212
14213 assert(cons != NULL);
14214 assert(var != NULL);
14215 assert(coef != NULL);
14216
14217 /* check for a linear variable that can be increased or decreased without harming feasibility */
14219
14220 consdata = SCIPconsGetData(cons);
14221 assert(consdata != NULL);
14222
14223 *var = consdata->linvarincr;
14224 *coef = consdata->linvarincrcoef;
14225}
14226
14227
14228/*
14229 * Methods for Expressions in Nonlinear Constraints
14230 */
14231
14232/** returns the number of positive rounding locks of an expression */
14234 SCIP_EXPR* expr /**< expression */
14235 )
14236{
14237 assert(expr != NULL);
14239
14240 return SCIPexprGetOwnerData(expr)->nlockspos;
14241}
14242
14243/** returns the number of negative rounding locks of an expression */
14245 SCIP_EXPR* expr /**< expression */
14246 )
14247{
14248 assert(expr != NULL);
14250
14251 return SCIPexprGetOwnerData(expr)->nlocksneg;
14252}
14253
14254/** returns the variable used for linearizing a given expression (return value might be NULL)
14255 *
14256 * @note for variable expression it returns the corresponding variable
14257 */
14259 SCIP_EXPR* expr /**< expression */
14260 )
14261{
14262 SCIP_EXPR_OWNERDATA* ownerdata;
14263
14264 assert(expr != NULL);
14265
14266 ownerdata = SCIPexprGetOwnerData(expr);
14267 assert(ownerdata != NULL);
14268
14269 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14270}
14271
14272/** returns the number of enforcements for an expression */
14274 SCIP_EXPR* expr /**< expression */
14275 )
14276{
14277 assert(expr != NULL);
14279
14280 return SCIPexprGetOwnerData(expr)->nenfos;
14281}
14282
14283/** returns the data for one of the enforcements of an expression */
14285 SCIP_EXPR* expr, /**< expression */
14286 int idx, /**< position of enforcement in enfos array */
14287 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14288 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14289 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14290 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14291 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14292 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14293 )
14294{
14295 SCIP_EXPR_OWNERDATA* ownerdata;
14296
14297 assert(expr != NULL);
14298
14299 ownerdata = SCIPexprGetOwnerData(expr);
14300 assert(ownerdata != NULL);
14301 assert(idx >= 0);
14302 assert(idx < ownerdata->nenfos);
14303 assert(ownerdata->enfos[idx] != NULL);
14304 assert(nlhdlr != NULL);
14305
14306 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14307
14308 if( nlhdlrexprdata != NULL )
14309 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14310
14311 if( nlhdlrparticipation != NULL )
14312 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14313
14314 if( sepabelowusesactivity != NULL )
14315 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14316
14317 if( sepaaboveusesactivity != NULL )
14318 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14319
14320 if( auxvalue != NULL )
14321 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14322}
14323
14324/** sets the auxiliary value of expression for one of the enforcements of an expression */
14326 SCIP_EXPR* expr, /**< expression */
14327 int idx, /**< position of enforcement in enfos array */
14328 SCIP_Real auxvalue /**< the new value of auxval */
14329 )
14330{
14331 SCIP_EXPR_OWNERDATA* ownerdata;
14332
14333 assert(expr != NULL);
14334
14335 ownerdata = SCIPexprGetOwnerData(expr);
14336 assert(ownerdata != NULL);
14337
14338 assert(idx >= 0);
14339 assert(idx < ownerdata->nenfos);
14340 assert(ownerdata->enfos[idx] != NULL);
14341
14342 ownerdata->enfos[idx]->auxvalue = auxvalue;
14343}
14344
14345/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14346 *
14347 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14348 */
14350 SCIP_EXPR* expr /**< expression */
14351 )
14352{
14353 assert(expr != NULL);
14355
14356 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14357}
14358
14359/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14360 *
14361 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14362 */
14364 SCIP_EXPR* expr /**< expression */
14365 )
14366{
14367 assert(expr != NULL);
14369
14370 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14371}
14372
14373/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14374 *
14375 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14376 */
14378 SCIP_EXPR* expr /**< expression */
14379 )
14380{
14381 assert(expr != NULL);
14383
14384 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14385}
14386
14387/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14388 *
14389 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14390 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14391 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14392 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14393 * and also increments this count for all variables in the expression.
14394 *
14395 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14396 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14397 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14398 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14399 */
14401 SCIP* scip, /**< SCIP data structure */
14402 SCIP_EXPR* expr, /**< expression */
14403 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14404 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14405 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14406 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14407 )
14408{
14409 SCIP_EXPR_OWNERDATA* ownerdata;
14410
14411 assert(expr != NULL);
14412
14413 ownerdata = SCIPexprGetOwnerData(expr);
14414 assert(ownerdata != NULL);
14415
14416 /* do not store auxvar request for variable expressions */
14417 if( useauxvar && SCIPisExprVar(scip, expr) )
14418 useauxvar = FALSE;
14419
14420 if( ownerdata->nenfos >= 0 &&
14421 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14422 (ownerdata->nauxvaruses == 0 && useauxvar)
14423 ) )
14424 {
14425 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14426 * we require additional enforcement methods, that is,
14427 * - activity of expr was not used before but will be used now, or
14428 * - auxiliary variable of expr was not required before but will be used now
14429 */
14430 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14431 }
14432
14433 if( useauxvar )
14434 ++ownerdata->nauxvaruses;
14435
14436 if( useactivityforprop )
14437 ++ownerdata->nactivityusesprop;
14438
14439 if( useactivityforsepabelow || useactivityforsepaabove )
14440 ++ownerdata->nactivityusessepa;
14441
14442 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14443 * information is used in detectNlhdlr()
14444 */
14445 if( useactivityforsepabelow )
14446 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14447 if( useactivityforsepaabove )
14448 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14449
14450 if( useactivityforprop )
14451 {
14452 /* if activity will be used for propagation, then make sure there is a valid activity
14453 * this way, we can do a reversepropcall after detectNlhdlr
14454 */
14456 }
14457
14458 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14459 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14460 {
14461 SCIP_EXPRITER* it;
14462
14463 /* create and initialize iterator */
14466
14467 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14468 if( SCIPisExprVar(scip, expr) )
14469 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14470
14471 /* free iterator */
14472 SCIPfreeExpriter(&it);
14473 }
14474
14475 return SCIP_OKAY;
14476}
14477
14478/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14479 *
14480 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14481 * Assume that f(x) is associated with auxiliary variable z.
14482 *
14483 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14484 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14485 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14486 *
14487 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14488 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14489 */
14491 SCIP* scip, /**< SCIP data structure */
14492 SCIP_EXPR* expr, /**< expression */
14493 SCIP_SOL* sol, /**< solution */
14494 SCIP_Longint soltag, /**< tag of solution */
14495 SCIP_Real* viol, /**< buffer to store computed violation */
14496 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14497 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14498 )
14499{
14500 assert(scip != NULL);
14501 assert(expr != NULL);
14502 assert(viol != NULL);
14503
14504 /* make sure expression has been evaluated */
14505 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14506
14507 /* get violation from internal method */
14508 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14509
14510 return SCIP_OKAY;
14511}
14512
14513/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14514 *
14515 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14516 * Assume that f(w) is associated with auxiliary variable z.
14517 *
14518 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14519 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14520 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14521 *
14522 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14523 * both `violover` and `violunder` are set to TRUE.
14524 */
14526 SCIP* scip, /**< SCIP data structure */
14527 SCIP_EXPR* expr, /**< expression */
14528 SCIP_Real auxvalue, /**< the value of f(w) */
14529 SCIP_SOL* sol, /**< solution that has been evaluated */
14530 SCIP_Real* viol, /**< buffer to store computed violation */
14531 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14532 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14533 )
14534{
14535 assert(scip != NULL);
14536 assert(expr != NULL);
14537 assert(viol != NULL);
14538
14539 /* get violation from internal method */
14540 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14541
14542 return SCIP_OKAY;
14543}
14544
14545
14546/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14547 *
14548 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14549 * Assume that f(w) is associated with auxiliary variable z.
14550 *
14551 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14552 * the absolute violation divided by max(1,|f(w)|).
14553 *
14554 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14555 * both `violover` and `violunder` are set to TRUE.
14556 */
14558 SCIP* scip, /**< SCIP data structure */
14559 SCIP_EXPR* expr, /**< expression */
14560 SCIP_Real auxvalue, /**< the value of f(w) */
14561 SCIP_SOL* sol, /**< solution that has been evaluated */
14562 SCIP_Real* viol, /**< buffer to store computed violation */
14563 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14564 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14565 )
14566{
14567 assert(scip != NULL);
14568 assert(expr != NULL);
14569 assert(viol != NULL);
14570
14571 /* get violation from internal method */
14572 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14573
14574 if( !SCIPisInfinity(scip, *viol) )
14575 {
14576 assert(auxvalue != SCIP_INVALID);
14577 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14578 *viol /= MAX(1.0, REALABS(auxvalue));
14579 }
14580
14581 return SCIP_OKAY;
14582}
14583
14584/** returns bounds on the expression
14585 *
14586 * This gives an intersection of bounds from
14587 * - activity calculation (SCIPexprGetActivity()), if valid,
14588 * - auxiliary variable, if present,
14589 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14590 *
14591 * @note The returned interval can be empty!
14592 */
14594 SCIP* scip, /**< SCIP data structure */
14595 SCIP_EXPR* expr /**< expression */
14596 )
14597{
14598 SCIP_EXPR_OWNERDATA* ownerdata;
14599 SCIP_CONSHDLRDATA* conshdlrdata;
14600 SCIP_INTERVAL bounds;
14601
14602 assert(scip != NULL);
14603 assert(expr != NULL);
14604
14605 ownerdata = SCIPexprGetOwnerData(expr);
14606 assert(ownerdata != NULL);
14607
14608 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14609 assert(conshdlrdata != NULL);
14610
14611 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14612
14613 /* start with propbounds if they belong to current propagation */
14614 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14615 {
14616 bounds = ownerdata->propbounds;
14617 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14618 }
14619 else
14621
14622 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14623 {
14624 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14625 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14627 }
14628
14629 if( ownerdata->auxvar != NULL )
14630 {
14631 /* apply auxiliary variable bounds to bounds */
14632 SCIP_INTERVAL auxvarbounds;
14633
14634 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14635 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14636 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14637 }
14638
14639 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14640
14641 return bounds;
14642}
14643
14644/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14645 * corresponding (auxiliary) variable (if any)
14646 *
14647 * @attention this function should only be called during domain propagation in cons_nonlinear
14648 */
14650 SCIP* scip, /**< SCIP data structure */
14651 SCIP_EXPR* expr, /**< expression to be tightened */
14652 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14653 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14654 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14655 )
14656{
14657 SCIP_EXPR_OWNERDATA* ownerdata;
14658 SCIP_CONSHDLRDATA* conshdlrdata;
14659
14660 assert(scip != NULL);
14661 assert(expr != NULL);
14662 assert(cutoff != NULL);
14663
14664 ownerdata = SCIPexprGetOwnerData(expr);
14665 assert(ownerdata != NULL);
14666 assert(ownerdata->conshdlr != NULL);
14667
14668 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14669 assert(conshdlrdata != NULL);
14670
14671 /* the code below assumes that current activity is valid
14672 * if it turns out that we cannot ensure that, then we should change code
14673 */
14674 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14676
14677 *cutoff = FALSE;
14678
14679#ifdef DEBUG_PROP
14680 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14681 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14682 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14683#endif
14684
14685 if( SCIPexprIsIntegral(expr) )
14686 {
14687 /* apply integrality to new bounds
14688 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14689 */
14690 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14691 newbounds.inf = SCIPceil(scip, newbounds.inf);
14692 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14693 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14694#ifdef DEBUG_PROP
14695 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14696#endif
14697 }
14698
14700 {
14701 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14702
14703 *cutoff = TRUE;
14704 return SCIP_OKAY;
14705 }
14706
14707 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14708 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14709 {
14710 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14711
14712 *cutoff = TRUE;
14713 return SCIP_OKAY;
14714 }
14715
14716 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14717 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14718 {
14719 /* if already having propbounds in expr, then tighten newbounds by propbounds */
14720 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14721 }
14722 else
14723 {
14724 /* first time we have propbounds for expr in this propagation rounds:
14725 * intersect with activity (though don't let it become empty if very close intervals)
14726 */
14727 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
14728 }
14729#ifdef DEBUG_PROP
14730 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14731#endif
14732
14733 /* check if the new bounds lead to an empty interval */
14735 {
14736 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14737
14738 *cutoff = TRUE;
14739 return SCIP_OKAY;
14740 }
14741
14742 /* if expr is not constant or variable, then store newbounds in expr->propbounds
14743 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14744 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14745 */
14746 if( SCIPexprGetNChildren(expr) > 0 )
14747 {
14748 ownerdata->propbounds = newbounds;
14749 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14750 }
14751
14752 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14753 * propagation or update of auxvar bounds
14754 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14755 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14756 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14757 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14758 * one or should we not even update propbounds to newbounds if the update is small?
14759 */
14760 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14761 {
14762#ifdef DEBUG_PROP
14763 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);
14764#endif
14765 return SCIP_OKAY;
14766 }
14767
14768 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14769 {
14770 /* add expression to propagation queue if not there yet and not var or constant and
14771 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14772 */
14773#ifdef DEBUG_PROP
14774 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14775#endif
14776 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14777 ownerdata->inpropqueue = TRUE;
14778 }
14779
14780 /* update bounds on variable or auxiliary variable */
14781 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14782
14783 return SCIP_OKAY;
14784}
14785
14786/** mark constraints that include this expression to be propagated again
14787 *
14788 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14789 * a change of variable bounds, e.g., because new information on the expression is available
14790 * that could potentially lead to tighter expression activity values.
14791 *
14792 * Note, that this call marks also constraints for propagation which only share some variable
14793 * with this expression.
14794 */
14796 SCIP* scip, /**< SCIP data structure */
14797 SCIP_EXPR* expr /**< expression to propagate again */
14798 )
14799{
14800 SCIP_EXPRITER* it;
14801 SCIP_CONSDATA* consdata;
14802 SCIP_EXPR_OWNERDATA* ownerdata;
14803 int c;
14804
14805 assert(scip != NULL);
14806 assert(expr != NULL);
14807
14808 ownerdata = SCIPexprGetOwnerData(expr);
14809 assert(ownerdata != NULL);
14810
14811 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14812
14815
14816 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14817 {
14818 if( !SCIPisExprVar(scip, expr) )
14819 continue;
14820
14821 ownerdata = SCIPexprGetOwnerData(expr);
14822 assert(ownerdata != NULL);
14823
14824 for( c = 0; c < ownerdata->nconss; ++c )
14825 {
14826 consdata = SCIPconsGetData(ownerdata->conss[c]);
14827 assert(consdata != NULL);
14828 consdata->ispropagated = FALSE;
14829 }
14830 }
14831
14832 SCIPfreeExpriter(&it);
14833
14834 return SCIP_OKAY;
14835}
14836
14837/** adds violation-branching score to an expression
14838 *
14839 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14840 * The expression must either be a variable expression or have an aux-variable.
14841 * In the latter case, branching on auxiliary variables must have been enabled.
14842 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14843 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14844 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14845 *
14846 * @see SCIPaddExprsViolScoreNonlinear()
14847 */
14849 SCIP* scip, /**< SCIP data structure */
14850 SCIP_EXPR* expr, /**< expression where to add branching score */
14851 SCIP_Real violscore /**< violation score to add to expression */
14852 )
14853{
14854 SCIP_EXPR_OWNERDATA* ownerdata;
14855 SCIP_CONSHDLRDATA* conshdlrdata;
14856
14857 assert(scip != NULL);
14858 assert(expr != NULL);
14859 assert(violscore >= 0.0);
14860
14861 ownerdata = SCIPexprGetOwnerData(expr);
14862 assert(ownerdata != NULL);
14863
14864 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14865 assert(conshdlrdata != NULL);
14866
14867 /* if not allowing to branch on auxvars, then expr must be a var-expr */
14868 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14869 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14870 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14871
14872 /* reset branching score if we are in a different enfo round */
14873 if( ownerdata->violscoretag != conshdlrdata->enforound )
14874 {
14875 ownerdata->violscoresum = violscore;
14876 ownerdata->violscoremax = violscore;
14877 ownerdata->nviolscores = 1;
14878 ownerdata->violscoretag = conshdlrdata->enforound;
14879 return;
14880 }
14881
14882 ownerdata->violscoresum += violscore;
14883 if( violscore > ownerdata->violscoremax )
14884 ownerdata->violscoremax = violscore;
14885 ++ownerdata->nviolscores;
14886}
14887
14888/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14889 *
14890 * Each expression must either be a variable expression or have an aux-variable.
14891 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14892 * variables present in `exprs`.
14893 */
14895 SCIP* scip, /**< SCIP data structure */
14896 SCIP_EXPR** exprs, /**< expressions where to add branching score */
14897 int nexprs, /**< number of expressions */
14898 SCIP_Real violscore, /**< violation score to add to expression */
14899 SCIP_SOL* sol, /**< current solution */
14900 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
14901 )
14902{
14903 SCIP_EXPRITER* it;
14904 SCIP_EXPR** varexprs;
14905 SCIP_EXPR* e;
14906 int nvars;
14907 int varssize;
14908 int i;
14909
14910 assert(exprs != NULL || nexprs == 0);
14911 assert(success != NULL);
14912
14913 if( nexprs == 0 )
14914 {
14915 *success = FALSE;
14916 return SCIP_OKAY;
14917 }
14918
14919 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
14920 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
14921 {
14922 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
14923 return SCIP_OKAY;
14924 }
14925
14926 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
14927 nvars = 0;
14928 varssize = 5;
14929 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
14930
14933
14934 for( i = 0; i < nexprs; ++i )
14935 {
14936 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
14937 {
14938 assert(e != NULL);
14939
14940 if( SCIPisExprVar(scip, e) )
14941 {
14942 /* add variable expression to vars array */
14943 if( varssize == nvars )
14944 {
14945 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
14946 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
14947 }
14948 assert(varssize > nvars);
14949
14950 varexprs[nvars++] = e;
14951 }
14952 }
14953 }
14954
14955 SCIPfreeExpriter(&it);
14956
14957 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
14958
14959 SCIPfreeBufferArray(scip, &varexprs);
14960
14961 return SCIP_OKAY;
14962}
14963
14964/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
14966 SCIP_EXPR* expr /**< expression */
14967 )
14968{
14969 SCIP_EXPR_OWNERDATA* ownerdata;
14970 SCIP_CONSHDLRDATA* conshdlrdata;
14971
14972 assert(expr != NULL);
14973
14974 ownerdata = SCIPexprGetOwnerData(expr);
14975 assert(ownerdata != NULL);
14976
14977 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14978 assert(conshdlrdata != NULL);
14979
14980 if( conshdlrdata->enforound != ownerdata->violscoretag )
14981 return 0.0;
14982
14983 if( ownerdata->nviolscores == 0 )
14984 return 0.0;
14985
14986 switch( conshdlrdata->branchscoreagg )
14987 {
14988 case 'a' :
14989 /* average */
14990 return ownerdata->violscoresum / ownerdata->nviolscores;
14991
14992 case 'm' :
14993 /* maximum */
14994 return ownerdata->violscoremax;
14995
14996 case 's' :
14997 /* sum */
14998 return ownerdata->violscoresum;
14999
15000 default:
15001 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15002 SCIPABORT();
15003 return SCIP_INVALID;
15004 }
15005}
15006
15007/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15008 *
15009 * @see SCIPexprGetDerivative()
15010 */
15012 SCIP* scip, /**< SCIP data structure */
15013 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15014 SCIP_VAR* var /**< variable (needs to be in the expression) */
15015 )
15016{
15017 SCIP_EXPR_OWNERDATA* ownerdata;
15018 SCIP_CONSHDLRDATA* conshdlrdata;
15019 SCIP_EXPR* varexpr;
15020
15021 assert(scip != NULL);
15022 assert(expr != NULL);
15023 assert(var != NULL);
15024
15025 /* return 0.0 for value expression */
15026 if( SCIPisExprValue(scip, expr) )
15027 {
15028 assert(SCIPexprGetDerivative(expr) == 0.0);
15029 return 0.0;
15030 }
15031
15032 /* check if an error occurred during the last SCIPevalExprGradient() call */
15033 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15034 return SCIP_INVALID;
15035
15036 ownerdata = SCIPexprGetOwnerData(expr);
15037 assert(ownerdata != NULL);
15038
15039 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15040 assert(conshdlrdata != NULL);
15041
15042 /* use variable to expressions mapping which is stored in the constraint handler data */
15043 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15044
15045 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15046 assert(varexpr != NULL);
15047 assert(SCIPisExprVar(scip, varexpr));
15048
15049 /* use difftag to decide whether the variable belongs to the expression */
15050 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15051}
15052
15053/** 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)
15054 *
15055 * @see SCIPexprGetBardot()
15056 */
15058 SCIP* scip, /**< SCIP data structure */
15059 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15060 SCIP_VAR* var /**< variable (needs to be in the expression) */
15061 )
15062{
15063 SCIP_EXPR_OWNERDATA* ownerdata;
15064 SCIP_CONSHDLRDATA* conshdlrdata;
15065 SCIP_EXPR* varexpr;
15066
15067 assert(scip != NULL);
15068 assert(expr != NULL);
15069 assert(var != NULL);
15070
15071 /* return 0.0 for value expression */
15072 if( SCIPisExprValue(scip, expr) )
15073 return 0.0;
15074
15075 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15076 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15077 return SCIP_INVALID;
15078
15079 ownerdata = SCIPexprGetOwnerData(expr);
15080 assert(ownerdata != NULL);
15081
15082 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15083 assert(conshdlrdata != NULL);
15084
15085 /* use variable to expressions mapping which is stored in the constraint handler data;
15086 * if this fails it means that we are asking for the var's component of H*u for a var
15087 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15088 */
15089 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15090
15091 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15092 assert(varexpr != NULL);
15093 assert(SCIPisExprVar(scip, varexpr));
15094
15095 /* use difftag to decide whether the variable belongs to the expression */
15096 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15097}
15098
15099/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15100 *
15101 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15102 */
15104 SCIP* scip, /**< SCIP data structure */
15105 SCIP_EXPR* expr, /**< quadratic expression */
15106 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15107 )
15108{
15109 SCIP_Real auxvalue;
15110 int nlinexprs;
15111 SCIP_Real* lincoefs;
15112 SCIP_EXPR** linexprs;
15113 int nquadexprs;
15114 int nbilinexprs;
15115 int i;
15116
15117 assert(scip != NULL);
15118 assert(expr != NULL);
15119
15120 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15121
15122 /* linear terms */
15123 for( i = 0; i < nlinexprs; ++i )
15124 {
15125 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15126 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15127 }
15128
15129 /* quadratic terms */
15130 for( i = 0; i < nquadexprs; ++i )
15131 {
15132 SCIP_EXPR* quadexprterm;
15133 SCIP_Real lincoef;
15134 SCIP_Real sqrcoef;
15135 SCIP_Real solval;
15136
15137 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15138
15139 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15140
15141 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15142 auxvalue += (lincoef + sqrcoef * solval) * solval;
15143 }
15144
15145 /* bilinear terms */
15146 for( i = 0; i < nbilinexprs; ++i )
15147 {
15148 SCIP_EXPR* expr1;
15149 SCIP_EXPR* expr2;
15150 SCIP_Real coef;
15151
15152 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15153
15157 }
15158
15159 return auxvalue;
15160}
15161
15162/**@addtogroup PublicNlhdlrInterfaceMethods
15163 * @{
15164 */
15165
15166/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15168 SCIP* scip, /**< SCIP data structure */
15169 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15170 const char* name, /**< name of nonlinear handler (must not be NULL) */
15171 const char* desc, /**< description of nonlinear handler (can be NULL) */
15172 int detectpriority, /**< detection priority of nonlinear handler */
15173 int enfopriority, /**< enforcement priority of nonlinear handler */
15174 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15175 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15176 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15177 )
15178{
15179 SCIP_CONSHDLR* conshdlr;
15180 SCIP_CONSHDLRDATA* conshdlrdata;
15181
15182 assert(scip != NULL);
15183 assert(nlhdlr != NULL);
15184 assert(detect != NULL);
15185
15186 /* find myself */
15187 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15188 if( conshdlr == NULL )
15189 {
15190 SCIPerrorMessage("nonlinear constraint handler not found");
15191 return SCIP_PLUGINNOTFOUND;
15192 }
15193
15194 /* create nlhdlr */
15195 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15196
15197 /* include into constraint handler */
15198 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15199 assert(conshdlrdata != NULL);
15200
15201 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15202
15203 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15204 ++conshdlrdata->nnlhdlrs;
15205
15206 /* sort nonlinear handlers by detection priority, in decreasing order
15207 * will happen in INIT, so only do when called late
15208 */
15209 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15210 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15211
15212 return SCIP_OKAY;
15213}
15214
15215/** get number of nonlinear handler */
15217 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15218 )
15219{
15220 SCIP_CONSHDLRDATA* conshdlrdata;
15221
15222 assert(conshdlr != NULL);
15223
15224 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15225 assert(conshdlrdata != NULL);
15226
15227 return conshdlrdata->nnlhdlrs;
15228}
15229
15230/** get nonlinear handlers */
15232 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15233 )
15234{
15235 SCIP_CONSHDLRDATA* conshdlrdata;
15236
15237 assert(conshdlr != NULL);
15238
15239 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15240 assert(conshdlrdata != NULL);
15241
15242 return conshdlrdata->nlhdlrs;
15243}
15244
15245/** returns a nonlinear handler of a given name (or NULL if not found) */
15247 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15248 const char* name /**< name of nonlinear handler */
15249 )
15250{
15251 SCIP_CONSHDLRDATA* conshdlrdata;
15252 int h;
15253
15254 assert(conshdlr != NULL);
15255 assert(name != NULL);
15256
15257 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15258 assert(conshdlrdata != NULL);
15259
15260 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15261 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15262 return conshdlrdata->nlhdlrs[h];
15263
15264 return NULL;
15265}
15266
15267/** gives expression data that a given nonlinear handler stored in an expression
15268 *
15269 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15270 */
15272 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15273 SCIP_EXPR* expr /**< expression */
15274 )
15275{
15276 SCIP_EXPR_OWNERDATA* ownerdata;
15277 int e;
15278
15279 assert(nlhdlr != NULL);
15280 assert(expr != NULL);
15281
15282 ownerdata = SCIPexprGetOwnerData(expr);
15283 assert(ownerdata != NULL);
15284
15285 for( e = 0; e < ownerdata->nenfos; ++e )
15286 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15287 return ownerdata->enfos[e]->nlhdlrexprdata;
15288
15289 return NULL;
15290}
15291
15292/** @} */
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)
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_Bool branchcandonly, SCIP_RESULT *result, SCIP_Bool *success)
#define ENFOLOG(x)
static SCIP_Bool branchingIntegralFirst(SCIP *scip, SCIP_CONSHDLR *conshdlr)
#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 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_Bool branchcandonly, SCIP_RESULT *result)
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 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)
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol)
#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 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)
#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)
#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 selectBranchingCandidate(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, BRANCHCAND **selected)
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_Bool branchcandonly, SCIP_RESULT *result)
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)
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
#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 SCIP_RETCODE branchingIntegralOrNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Longint soltag, SCIP_Real maxrelconsviol, SCIP_Bool *branchintegral, SCIP_Bool *cutoff)
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 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)
SCIP_RETCODE SCIPgetExprActivityNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
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:5180
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_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
int SCIPgetNLPBranchCands(SCIP *scip)
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:7490
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_Real SCIPgetAvgPseudocostCount(SCIP *scip, SCIP_BRANCHDIR dir)
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_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
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_Real SCIPfeasFloor(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:5202
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition scip_var.c:4316
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:8949
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:5319
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:1247
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition scip_var.c:4644
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition scip_var.c:8813
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition scip_var.c:4612
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:8175
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:8714
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:1438
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1213
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 nlpcands
int r
SCIP_Real obj
SCIP_VAR ** lpcands
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
SCIP_Real * lpcandsfrac
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:752
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_VAR * var
SCIP_Real fractionality
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_CONSNONLINEAR_AUXEXPR ** exprs
union SCIP_ConsNonlinear_BilinTerm::@4 aux
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