Scippy

SCIP

Solving Constraint Integer Programs

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 assert(!consdata->catchedevents);
817
818 /* release variable expressions */
819 for( i = 0; i < consdata->nvarexprs; ++i )
820 {
821 assert(consdata->varexprs[i] != NULL);
822 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
823 assert(consdata->varexprs[i] == NULL);
824 }
825
826 /* free variable expressions */
827 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
828 consdata->varexprs = NULL;
829 consdata->nvarexprs = 0;
830
831 return SCIP_OKAY;
832}
833
834/** interval evaluation of variables as used in bound tightening
835 *
836 * Returns slightly relaxed local variable bounds of a variable as interval.
837 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
838 */
839static
840SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
841{
842 SCIP_INTERVAL interval;
843 SCIP_CONSHDLRDATA* conshdlrdata;
844 SCIP_Real lb;
845 SCIP_Real ub;
846
847 assert(scip != NULL);
848 assert(var != NULL);
849
850 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
851 assert(conshdlrdata != NULL);
852
853 if( conshdlrdata->globalbounds )
854 {
855 lb = SCIPvarGetLbGlobal(var);
856 ub = SCIPvarGetUbGlobal(var);
857 }
858 else
859 {
860 lb = SCIPvarGetLbLocal(var);
861 ub = SCIPvarGetUbLocal(var);
862 }
863 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
864
865 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
867 {
868 lb = EPSROUND(lb, 0.0); /*lint !e835*/
869 ub = EPSROUND(ub, 0.0); /*lint !e835*/
870 }
871
872 /* integer variables should always have integral bounds in SCIP */
873 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
874 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
875
876 switch( conshdlrdata->varboundrelax )
877 {
878 case 'n' : /* no relaxation */
879 break;
880
881 case 'a' : /* relax by absolute value */
882 {
883 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
884 if( SCIPvarIsIntegral(var) )
885 break;
886
887 if( !SCIPisInfinity(scip, -lb) )
888 {
889 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
890 SCIP_Real bnd = floor(lb);
891 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
892 }
893
894 if( !SCIPisInfinity(scip, ub) )
895 {
896 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
897 SCIP_Real bnd = ceil(ub);
898 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
899 }
900
901 break;
902 }
903
904 case 'b' : /* relax always by absolute value */
905 {
906 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
907 if( SCIPvarIsIntegral(var) )
908 break;
909
910 if( !SCIPisInfinity(scip, -lb) )
911 lb -= conshdlrdata->varboundrelaxamount;
912
913 if( !SCIPisInfinity(scip, ub) )
914 ub += conshdlrdata->varboundrelaxamount;
915
916 break;
917 }
918
919 case 'r' : /* relax by relative value */
920 {
921 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
922 if( SCIPvarIsIntegral(var) )
923 break;
924
925 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
926 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
927 * further, do not relax beyond next integer value
928 */
929 if( !SCIPisInfinity(scip, -lb) )
930 {
931 SCIP_Real bnd = floor(lb);
932 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
933 }
934
935 if( !SCIPisInfinity(scip, ub) )
936 {
937 SCIP_Real bnd = ceil(ub);
938 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
939 }
940
941 break;
942 }
943
944 default :
945 {
946 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
947 SCIPABORT();
948 break;
949 }
950 }
951
952 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
955 assert(lb <= ub);
956
957 SCIPintervalSetBounds(&interval, lb, ub);
958
959 return interval;
960}
961
962/** compares two nonlinear constraints by its index
963 *
964 * Usable as compare operator in array sort functions.
965 */
966static
967SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
968{
969 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
970 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
971
972 assert(consdata1 != NULL);
973 assert(consdata2 != NULL);
974
975 return consdata1->consindex - consdata2->consindex;
976}
977
978/** processes variable fixing or bound change event */
979static
980SCIP_DECL_EVENTEXEC(processVarEvent)
981{ /*lint --e{715}*/
982 SCIP_EVENTTYPE eventtype;
983 SCIP_EXPR* expr;
984 SCIP_EXPR_OWNERDATA* ownerdata;
985 SCIP_Bool boundtightened = FALSE;
986
987 eventtype = SCIPeventGetType(event);
989
990 assert(eventdata != NULL);
991 expr = (SCIP_EXPR*) eventdata;
992 assert(SCIPisExprVar(scip, expr));
993
994 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
998
999 ownerdata = SCIPexprGetOwnerData(expr);
1000 assert(ownerdata != NULL);
1001 /* we only catch varevents for variables in constraints, so there should be constraints */
1002 assert(ownerdata->nconss > 0);
1003 assert(ownerdata->conss != NULL);
1004
1005 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1006 boundtightened = TRUE;
1007
1008 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1009 * however, if the boundchange is smaller than epsilon, such an event will be omitted
1010 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1011 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1012 * as a boundtightening (and usually it is, I would think)
1013 */
1014 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1015 boundtightened = TRUE;
1016
1017 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1018 * because we will round the bounds and no longer consider relaxing them
1019 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1020 * (mainly to avoid a failing assert, see github issue #70)
1021 * 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
1022 */
1023 if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1024 (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1025 boundtightened = TRUE;
1026
1027 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1028 * - propagation can only find something new if a bound was tightened
1029 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1030 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1031 */
1032 if( boundtightened )
1033 {
1034 SCIP_CONSDATA* consdata;
1035 int c;
1036
1037 for( c = 0; c < ownerdata->nconss; ++c )
1038 {
1039 assert(ownerdata->conss[c] != NULL);
1040 consdata = SCIPconsGetData(ownerdata->conss[c]);
1041
1042 /* if bound tightening, then mark constraints to be propagated again
1043 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1044 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1045 * the locks don't help since they are not available separately for each constraint
1046 */
1047 consdata->ispropagated = FALSE;
1048 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1049
1050 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1052 {
1053 consdata->issimplified = FALSE;
1054 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1055 }
1056 }
1057 }
1058
1059 /* update curboundstag, lastboundrelax, and expr activity */
1060 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1061 {
1062 SCIP_CONSHDLRDATA* conshdlrdata;
1063 SCIP_INTERVAL activity;
1064
1065 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1066 assert(conshdlrdata != NULL);
1067
1068 /* increase tag on bounds */
1069 ++conshdlrdata->curboundstag;
1070 assert(conshdlrdata->curboundstag > 0);
1071
1072 /* remember also if we relaxed bounds now */
1073 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1074 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1075
1076 /* update the activity of the var-expr here immediately
1077 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1078 */
1079 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1080 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1081#ifdef DEBUG_PROP
1082 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1083#endif
1084 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1085 }
1086
1087 return SCIP_OKAY;
1088}
1089
1090/** registers event handler to catch variable events on variable
1091 *
1092 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1093 * When an event occurs, all stored constraints are notified.
1094 */
1095static
1097 SCIP* scip, /**< SCIP data structure */
1098 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1099 SCIP_EXPR* expr, /**< variable expression */
1100 SCIP_CONS* cons /**< nonlinear constraint */
1101 )
1102{
1103 SCIP_EXPR_OWNERDATA* ownerdata;
1104
1105 assert(eventhdlr != NULL);
1106 assert(expr != NULL);
1107 assert(SCIPisExprVar(scip, expr));
1108 assert(cons != NULL);
1109
1110 ownerdata = SCIPexprGetOwnerData(expr);
1111 assert(ownerdata != NULL);
1112
1113#ifndef NDEBUG
1114 /* assert that constraint does not double-catch variable */
1115 {
1116 int i;
1117 for( i = 0; i < ownerdata->nconss; ++i )
1118 assert(ownerdata->conss[i] != cons);
1119 }
1120#endif
1121
1122 /* append cons to ownerdata->conss */
1123 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1124 ownerdata->conss[ownerdata->nconss++] = cons;
1125 /* we're not capturing the constraint here to avoid circular references */
1126
1127 /* updated sorted flag */
1128 if( ownerdata->nconss <= 1 )
1129 ownerdata->consssorted = TRUE;
1130 else if( ownerdata->consssorted )
1131 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1132
1133 /* catch variable events, if not done so yet (first constraint) */
1134 if( ownerdata->filterpos < 0 )
1135 {
1136 SCIP_EVENTTYPE eventtype;
1137
1138 assert(ownerdata->nconss == 1);
1139
1141
1142 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1143 assert(ownerdata->filterpos >= 0);
1144 }
1145
1146 return SCIP_OKAY;
1147}
1148
1149/** catch variable events */
1150static
1152 SCIP* scip, /**< SCIP data structure */
1153 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1154 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1155 )
1156{
1157 SCIP_CONSHDLRDATA* conshdlrdata;
1158 SCIP_CONSDATA* consdata;
1159 SCIP_EXPR* expr;
1160 int i;
1161
1162 assert(eventhdlr != NULL);
1163 assert(cons != NULL);
1164
1165 consdata = SCIPconsGetData(cons);
1166 assert(consdata != NULL);
1167 assert(consdata->varexprs != NULL);
1168 assert(consdata->nvarexprs >= 0);
1169
1170 /* check if we have catched variable events already */
1171 if( consdata->catchedevents )
1172 return SCIP_OKAY;
1173
1174 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1175 assert(conshdlrdata != NULL);
1176#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1177 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1178#endif
1179
1180 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1181
1182 for( i = 0; i < consdata->nvarexprs; ++i )
1183 {
1184 expr = consdata->varexprs[i];
1185
1186 assert(expr != NULL);
1187 assert(SCIPisExprVar(scip, expr));
1188
1189 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1190
1191 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1192 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1193 */
1194 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1195 {
1196 SCIP_INTERVAL activity;
1197 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1198 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1199 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1200#ifdef DEBUG_PROP
1201 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1202#endif
1203 }
1204 }
1205
1206 consdata->catchedevents = TRUE;
1207
1208 return SCIP_OKAY;
1209}
1210
1211/** unregisters event handler to catch variable events on variable
1212 *
1213 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1214 * If this was the last constraint, then the event handler is unregistered for this variable.
1215 */
1216static
1218 SCIP* scip, /**< SCIP data structure */
1219 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1220 SCIP_EXPR* expr, /**< variable expression */
1221 SCIP_CONS* cons /**< expr constraint */
1222 )
1223{
1224 SCIP_EXPR_OWNERDATA* ownerdata;
1225 int pos;
1226
1227 assert(eventhdlr != NULL);
1228 assert(expr != NULL);
1229 assert(SCIPisExprVar(scip, expr));
1230 assert(cons != NULL);
1231
1232 ownerdata = SCIPexprGetOwnerData(expr);
1233 assert(ownerdata != NULL);
1234 assert(ownerdata->nconss > 0);
1235
1236 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1237 {
1238 pos = ownerdata->nconss-1;
1239 }
1240 else
1241 {
1242 if( !ownerdata->consssorted )
1243 {
1244 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1245 ownerdata->consssorted = TRUE;
1246 }
1247
1248 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1249 {
1250 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1251 return SCIP_ERROR;
1252 }
1253 assert(pos >= 0 && pos < ownerdata->nconss);
1254 }
1255 assert(ownerdata->conss[pos] == cons);
1256
1257 /* move last constraint into position of removed constraint */
1258 if( pos < ownerdata->nconss-1 )
1259 {
1260 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1261 ownerdata->consssorted = FALSE;
1262 }
1263 --ownerdata->nconss;
1264
1265 /* drop variable events if that was the last constraint */
1266 if( ownerdata->nconss == 0 )
1267 {
1268 SCIP_EVENTTYPE eventtype;
1269
1270 assert(ownerdata->filterpos >= 0);
1271
1273
1274 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1275 ownerdata->filterpos = -1;
1276 }
1277
1278 return SCIP_OKAY;
1279}
1280
1281/** drop variable events */
1282static
1284 SCIP* scip, /**< SCIP data structure */
1285 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1286 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1287 )
1288{
1289 SCIP_CONSDATA* consdata;
1290 int i;
1291
1292 assert(eventhdlr != NULL);
1293 assert(cons != NULL);
1294
1295 consdata = SCIPconsGetData(cons);
1296 assert(consdata != NULL);
1297
1298 /* check if we have catched variable events already */
1299 if( !consdata->catchedevents )
1300 return SCIP_OKAY;
1301
1302 assert(consdata->varexprs != NULL);
1303 assert(consdata->nvarexprs >= 0);
1304
1305 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1306
1307 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1308 {
1309 assert(consdata->varexprs[i] != NULL);
1310
1311 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1312 }
1313
1314 consdata->catchedevents = FALSE;
1315
1316 return SCIP_OKAY;
1317}
1318
1319/** creates and captures a nonlinear constraint
1320 *
1321 * @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
1322 */
1323static
1325 SCIP* scip, /**< SCIP data structure */
1326 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1327 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1328 const char* name, /**< name of constraint */
1329 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1330 SCIP_Real lhs, /**< left hand side of constraint */
1331 SCIP_Real rhs, /**< right hand side of constraint */
1332 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1333 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1334 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1335 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1336 * Usually set to TRUE. */
1337 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1338 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1339 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1340 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1341 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1342 * Usually set to TRUE. */
1343 SCIP_Bool local, /**< is constraint only valid locally?
1344 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1345 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1346 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1347 * adds coefficients to this constraint. */
1348 SCIP_Bool dynamic, /**< is constraint subject to aging?
1349 * Usually set to FALSE. Set to TRUE for own cuts which
1350 * are separated as constraints. */
1351 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1352 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1353 )
1354{
1355 SCIP_CONSHDLRDATA* conshdlrdata;
1356 SCIP_CONSDATA* consdata;
1357
1358 assert(conshdlr != NULL);
1359 assert(expr != NULL);
1360
1361 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1362 assert(conshdlrdata != NULL);
1363
1364 if( local && SCIPgetDepth(scip) != 0 )
1365 {
1366 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1367 return SCIP_INVALIDCALL;
1368 }
1369
1370 /* TODO we should allow for non-initial nonlinear constraints */
1371 if( !initial )
1372 {
1373 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1374 return SCIP_INVALIDCALL;
1375 }
1376
1377 /* create constraint data */
1379
1380 if( copyexpr )
1381 {
1382 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1383 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1384 }
1385 else
1386 {
1387 consdata->expr = expr;
1388 SCIPcaptureExpr(consdata->expr);
1389 }
1390 consdata->lhs = lhs;
1391 consdata->rhs = rhs;
1392 consdata->consindex = conshdlrdata->lastconsindex++;
1393 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1394
1395 /* create constraint */
1396 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1397 local, modifiable, dynamic, removable, FALSE) );
1398
1399 return SCIP_OKAY;
1400}
1401
1402/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1403 *
1404 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1405 * Assume that f(x) is associated with auxiliary variable z.
1406 *
1407 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1408 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1409 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1410 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1411 *
1412 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1413 */
1414static
1416 SCIP* scip, /**< SCIP data structure */
1417 SCIP_EXPR* expr, /**< expression */
1418 SCIP_SOL* sol, /**< solution that has been evaluated */
1419 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1420 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1421 )
1422{
1423 SCIP_EXPR_OWNERDATA* ownerdata;
1424 SCIP_Real auxvarvalue;
1425
1426 assert(expr != NULL);
1427
1428 ownerdata = SCIPexprGetOwnerData(expr);
1429 assert(ownerdata != NULL);
1430 assert(ownerdata->auxvar != NULL);
1431
1432 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1433 {
1434 if( violunder != NULL )
1435 *violunder = TRUE;
1436 if( violover != NULL )
1437 *violover = TRUE;
1438 return SCIPinfinity(scip);
1439 }
1440
1441 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1442
1443 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1444 {
1445 if( violunder != NULL )
1446 *violunder = FALSE;
1447 if( violover != NULL )
1448 *violover = TRUE;
1449 return auxvarvalue - SCIPexprGetEvalValue(expr);
1450 }
1451
1452 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1453 {
1454 if( violunder != NULL )
1455 *violunder = TRUE;
1456 if( violover != NULL )
1457 *violover = FALSE;
1458 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1459 }
1460
1461 if( violunder != NULL )
1462 *violunder = FALSE;
1463 if( violover != NULL )
1464 *violover = FALSE;
1465 return 0.0;
1466}
1467
1468/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1469 *
1470 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1471 * Assume that f(w) is associated with auxiliary variable z.
1472 *
1473 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1474 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1475 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1476 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1477 *
1478 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1479 */
1480static
1482 SCIP* scip, /**< SCIP data structure */
1483 SCIP_EXPR* expr, /**< expression */
1484 SCIP_Real auxvalue, /**< value of f(w) */
1485 SCIP_SOL* sol, /**< solution that has been evaluated */
1486 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1487 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1488 )
1489{
1490 SCIP_EXPR_OWNERDATA* ownerdata;
1491 SCIP_Real auxvarvalue;
1492
1493 assert(expr != NULL);
1494
1495 ownerdata = SCIPexprGetOwnerData(expr);
1496 assert(ownerdata != NULL);
1497 assert(ownerdata->auxvar != NULL);
1498
1499 if( auxvalue == SCIP_INVALID )
1500 {
1501 if( violunder != NULL )
1502 *violunder = TRUE;
1503 if( violover != NULL )
1504 *violover = TRUE;
1505 return SCIPinfinity(scip);
1506 }
1507
1508 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1509
1510 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1511 {
1512 if( violunder != NULL )
1513 *violunder = FALSE;
1514 if( violover != NULL )
1515 *violover = TRUE;
1516 return auxvarvalue - auxvalue;
1517 }
1518
1519 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1520 {
1521 if( violunder != NULL )
1522 *violunder = TRUE;
1523 if( violover != NULL )
1524 *violover = FALSE;
1525 return auxvalue - auxvarvalue;
1526 }
1527
1528 if( violunder != NULL )
1529 *violunder = FALSE;
1530 if( violover != NULL )
1531 *violover = FALSE;
1532
1533 return 0.0;
1534}
1535
1536/** computes violation of a constraint */
1537static
1539 SCIP* scip, /**< SCIP data structure */
1540 SCIP_CONS* cons, /**< constraint */
1541 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1542 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1543 )
1544{
1545 SCIP_CONSDATA* consdata;
1546 SCIP_Real activity;
1547
1548 assert(scip != NULL);
1549 assert(cons != NULL);
1550
1551 consdata = SCIPconsGetData(cons);
1552 assert(consdata != NULL);
1553
1554 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1555 activity = SCIPexprGetEvalValue(consdata->expr);
1556
1557 /* consider constraint as violated if it is undefined in the current point */
1558 if( activity == SCIP_INVALID )
1559 {
1560 consdata->lhsviol = SCIPinfinity(scip);
1561 consdata->rhsviol = SCIPinfinity(scip);
1562 return SCIP_OKAY;
1563 }
1564
1565 /* compute violations */
1566 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1567 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1568
1569 return SCIP_OKAY;
1570}
1571
1572/** returns absolute violation of a constraint
1573 *
1574 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1575 */
1576static
1578 SCIP_CONS* cons /**< constraint */
1579 )
1580{
1581 SCIP_CONSDATA* consdata;
1582
1583 assert(cons != NULL);
1584
1585 consdata = SCIPconsGetData(cons);
1586 assert(consdata != NULL);
1587
1588 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1589}
1590
1591/** computes relative violation of a constraint
1592 *
1593 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1594 */
1595static
1597 SCIP* scip, /**< SCIP data structure */
1598 SCIP_CONS* cons, /**< constraint */
1599 SCIP_Real* viol, /**< buffer to store violation */
1600 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1601 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1602 )
1603{
1604 SCIP_CONSHDLR* conshdlr;
1605 SCIP_CONSHDLRDATA* conshdlrdata;
1606 SCIP_CONSDATA* consdata;
1607 SCIP_Real scale;
1608
1609 assert(cons != NULL);
1610 assert(viol != NULL);
1611
1612 conshdlr = SCIPconsGetHdlr(cons);
1613 assert(conshdlr != NULL);
1614
1615 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1616 assert(conshdlrdata != NULL);
1617
1618 *viol = getConsAbsViolation(cons);
1619
1620 if( conshdlrdata->violscale == 'n' )
1621 return SCIP_OKAY;
1622
1623 if( SCIPisInfinity(scip, *viol) )
1624 return SCIP_OKAY;
1625
1626 consdata = SCIPconsGetData(cons);
1627 assert(consdata != NULL);
1628
1629 if( conshdlrdata->violscale == 'a' )
1630 {
1631 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1632
1633 /* consider value of side that is violated for scaling, too */
1634 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1635 {
1636 assert(!SCIPisInfinity(scip, -consdata->lhs));
1637 scale = REALABS(consdata->lhs);
1638 }
1639 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1640 {
1641 assert(!SCIPisInfinity(scip, consdata->rhs));
1642 scale = REALABS(consdata->rhs);
1643 }
1644
1645 *viol /= scale;
1646 return SCIP_OKAY;
1647 }
1648
1649 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1650 assert(conshdlrdata->violscale == 'g');
1651 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1652 {
1653 /* we need the varexprs to conveniently access the gradient */
1654 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1655
1656 /* update cached value of norm of gradient */
1657 consdata->gradnorm = 0.0;
1658
1659 /* compute gradient */
1660 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1661
1662 /* gradient evaluation error -> no scaling */
1663 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1664 {
1665 int i;
1666 for( i = 0; i < consdata->nvarexprs; ++i )
1667 {
1668 SCIP_Real deriv;
1669
1670 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1671 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1672 if( deriv == SCIP_INVALID )
1673 {
1674 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1675 consdata->gradnorm = 0.0;
1676 break;
1677 }
1678
1679 consdata->gradnorm += deriv*deriv;
1680 }
1681 }
1682 consdata->gradnorm = sqrt(consdata->gradnorm);
1683 consdata->gradnormsoltag = soltag;
1684 }
1685
1686 *viol /= MAX(1.0, consdata->gradnorm);
1687
1688 return SCIP_OKAY;
1689}
1690
1691/** returns whether constraint is currently violated
1692 *
1693 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1694 */
1695static
1697 SCIP* scip, /**< SCIP data structure */
1698 SCIP_CONS* cons /**< constraint */
1699 )
1700{
1701 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1702}
1703
1704/** checks for a linear variable that can be increased or decreased without harming feasibility */
1705static
1707 SCIP* scip, /**< SCIP data structure */
1708 SCIP_CONS* cons /**< constraint */
1709 )
1710{
1711 SCIP_CONSDATA* consdata;
1712 int poslock;
1713 int neglock;
1714 int i;
1715
1716 assert(cons != NULL);
1717
1718 consdata = SCIPconsGetData(cons);
1719 assert(consdata != NULL);
1720
1721 consdata->linvarincr = NULL;
1722 consdata->linvardecr = NULL;
1723 consdata->linvarincrcoef = 0.0;
1724 consdata->linvardecrcoef = 0.0;
1725
1726 /* root expression is not a sum -> no unlocked linear variable available */
1727 if( !SCIPisExprSum(scip, consdata->expr) )
1728 return;
1729
1730 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1731 {
1732 SCIP_EXPR* child;
1733
1734 child = SCIPexprGetChildren(consdata->expr)[i];
1735 assert(child != NULL);
1736
1737 /* check whether the child is a variable expression */
1738 if( SCIPisExprVar(scip, child) )
1739 {
1740 SCIP_VAR* var = SCIPgetVarExprVar(child);
1741 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1742
1743 if( coef > 0.0 )
1744 {
1745 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1746 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1747 }
1748 else
1749 {
1750 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1751 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1752 }
1754
1755 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1756 {
1757 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1758 * if we have already one candidate, then take the one where the loss in the objective function is less
1759 */
1760 if( (consdata->linvardecr == NULL) ||
1761 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1762 {
1763 consdata->linvardecr = var;
1764 consdata->linvardecrcoef = coef;
1765 }
1766 }
1767
1768 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1769 {
1770 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1771 * if we have already one candidate, then take the one where the loss in the objective function is less
1772 */
1773 if( (consdata->linvarincr == NULL) ||
1774 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1775 {
1776 consdata->linvarincr = var;
1777 consdata->linvarincrcoef = coef;
1778 }
1779 }
1780 }
1781 }
1782
1783 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1784 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1785
1786 if( consdata->linvarincr != NULL )
1787 {
1788 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1789 }
1790 if( consdata->linvardecr != NULL )
1791 {
1792 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1793 }
1794}
1795
1796/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1797 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1798 *
1799 * The method assumes that this is always possible and that not all constraints are feasible already.
1800 */
1801static
1803 SCIP* scip, /**< SCIP data structure */
1804 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1805 SCIP_CONS** conss, /**< constraints to process */
1806 int nconss, /**< number of constraints */
1807 SCIP_SOL* sol, /**< solution to process */
1808 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1809 )
1810{
1811 SCIP_CONSHDLRDATA* conshdlrdata;
1812 SCIP_SOL* newsol;
1813 int c;
1814
1815 assert(scip != NULL);
1816 assert(conshdlr != NULL);
1817 assert(conss != NULL || nconss == 0);
1818 assert(success != NULL);
1819
1820 *success = FALSE;
1821
1822 /* don't propose new solutions if not in presolve or solving */
1824 return SCIP_OKAY;
1825
1826 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1827 assert(conshdlrdata != NULL);
1828
1829 if( sol != NULL )
1830 {
1831 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1832 }
1833 else
1834 {
1835 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1836 }
1837 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1838 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1839 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1840
1841 for( c = 0; c < nconss; ++c )
1842 {
1843 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1844 SCIP_Real viol = 0.0;
1845 SCIP_Real delta;
1846 SCIP_Real gap;
1847
1848 assert(consdata != NULL);
1849
1850 /* get absolute violation and sign */
1851 if( consdata->lhsviol > SCIPfeastol(scip) )
1852 viol = consdata->lhsviol; /* lhs - activity */
1853 else if( consdata->rhsviol > SCIPfeastol(scip) )
1854 viol = -consdata->rhsviol; /* rhs - activity */
1855 else
1856 continue; /* constraint is satisfied */
1857
1858 if( consdata->linvarincr != NULL &&
1859 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1860 {
1861 SCIP_VAR* var = consdata->linvarincr;
1862
1863 /* compute how much we would like to increase var */
1864 delta = viol / consdata->linvarincrcoef;
1865 assert(delta > 0.0);
1866
1867 /* if var has an upper bound, may need to reduce delta */
1869 {
1870 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1871 delta = MIN(MAX(0.0, gap), delta);
1872 }
1873 if( SCIPisPositive(scip, delta) )
1874 {
1875 /* if variable is integral, round delta up so that it will still have an integer value */
1876 if( SCIPvarIsIntegral(var) )
1877 delta = SCIPceil(scip, delta);
1878
1879 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1880 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1881 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1882
1883 /* adjust constraint violation, if satisfied go on to next constraint */
1884 viol -= consdata->linvarincrcoef * delta;
1885 if( SCIPisZero(scip, viol) )
1886 continue;
1887 }
1888 }
1889
1890 assert(viol != 0.0);
1891 if( consdata->linvardecr != NULL &&
1892 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1893 {
1894 SCIP_VAR* var = consdata->linvardecr;
1895
1896 /* compute how much we would like to decrease var */
1897 delta = viol / consdata->linvardecrcoef;
1898 assert(delta < 0.0);
1899
1900 /* if var has a lower bound, may need to reduce delta */
1902 {
1903 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1904 delta = MAX(MIN(0.0, gap), delta);
1905 }
1906 if( SCIPisNegative(scip, delta) )
1907 {
1908 /* if variable is integral, round delta down so that it will still have an integer value */
1909 if( SCIPvarIsIntegral(var) )
1910 delta = SCIPfloor(scip, delta);
1911 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1912 /*lint --e{613} */
1913 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1914 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1915
1916 /* adjust constraint violation, if satisfied go on to next constraint */
1917 viol -= consdata->linvardecrcoef * delta;
1918 if( SCIPisZero(scip, viol) )
1919 continue;
1920 }
1921 }
1922
1923 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1924 break;
1925 }
1926
1927 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1928 * then pass it to the trysol heuristic
1929 */
1931 {
1932 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1933
1934 assert(conshdlrdata->trysolheur != NULL);
1935 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1936
1937 *success = TRUE;
1938 }
1939
1940 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1941
1942 return SCIP_OKAY;
1943}
1944
1945/** notify nonlinear handlers to add linearization in new solution that has been found
1946 *
1947 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1948 *
1949 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1950 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1951 * cut that is valid and supporting in the given solution.
1952 * For example, for convex constraints, we achieve this by linearizing.
1953 * For SOC, we also linearize, but on a a convex reformulation.
1954 *
1955 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1956 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1957 */
1958static
1960 SCIP* scip, /**< SCIP data structure */
1961 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1962 SCIP_CONS** conss, /**< constraints */
1963 int nconss, /**< number of constraints */
1964 SCIP_SOL* sol, /**< reference point where to estimate */
1965 SCIP_Bool solisbest /**< whether solution is best */
1966 )
1967{
1968 SCIP_CONSDATA* consdata;
1969 SCIP_Longint soltag;
1970 SCIP_EXPRITER* it;
1971 SCIP_EXPR* expr;
1972 int c, e;
1973
1974 assert(scip != NULL);
1975 assert(conshdlr != NULL);
1976 assert(conss != NULL || nconss == 0);
1977
1978 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1979
1980 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1981 * would be nice to recognize this and skip reevaluating
1982 */
1983 soltag = SCIPgetExprNewSoltag(scip);
1984
1988
1989 for( c = 0; c < nconss; ++c )
1990 {
1991 /* skip constraints that are not enabled or deleted or have separation disabled */
1992 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
1993 continue;
1994 assert(SCIPconsIsActive(conss[c]));
1995
1996 consdata = SCIPconsGetData(conss[c]);
1997 assert(consdata != NULL);
1998
1999 ENFOLOG(
2000 {
2001 int i;
2002 SCIPinfoMessage(scip, enfologfile, " constraint ");
2003 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2004 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2005 for( i = 0; i < consdata->nvarexprs; ++i )
2006 {
2007 SCIP_VAR* var;
2008 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2009 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2010 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2011 }
2012 })
2013
2014 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2015 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2016
2017 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2018 {
2019 SCIP_EXPR_OWNERDATA* ownerdata;
2020
2021 ownerdata = SCIPexprGetOwnerData(expr);
2022 assert(ownerdata != NULL);
2023
2024 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2025 assert(SCIPexprGetEvalTag(expr) == soltag);
2026 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2027 if( ownerdata->auxvar != NULL )
2028 {
2029 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2030 }
2031
2032 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2033 for( e = 0; e < ownerdata->nenfos; ++e )
2034 {
2035 /* call sollinearize callback, if implemented by nlhdlr */
2036 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2037 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2038 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2039 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2040 }
2041 }
2042 }
2043
2044 SCIPfreeExpriter(&it);
2045
2046 return SCIP_OKAY;
2047}
2048
2049/** processes the event that a new primal solution has been found */
2050static
2051SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2052{
2053 SCIP_CONSHDLR* conshdlr;
2054 SCIP_CONSHDLRDATA* conshdlrdata;
2055 SCIP_SOL* sol;
2056
2057 assert(scip != NULL);
2058 assert(event != NULL);
2059 assert(eventdata != NULL);
2060 assert(eventhdlr != NULL);
2062
2063 conshdlr = (SCIP_CONSHDLR*)eventdata;
2064
2065 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2066 return SCIP_OKAY;
2067
2068 sol = SCIPeventGetSol(event);
2069 assert(sol != NULL);
2070
2071 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2072 assert(conshdlrdata != NULL);
2073
2074 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2075 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2076 * from the tree, but postprocessed via proposeFeasibleSolution
2077 */
2078 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2079 return SCIP_OKAY;
2080
2081 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2082
2084
2085 return SCIP_OKAY;
2086}
2087
2088/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2089 *
2090 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2091 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2092 *
2093 * Nothing will happen if SCIP is not in presolve or solve.
2094 */
2095static
2097 SCIP* scip, /**< SCIP data structure */
2098 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2099 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2100 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2101 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2102 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2103 )
2104{
2105 SCIP_VAR* var;
2106 SCIP_Bool tightenedlb;
2107 SCIP_Bool tightenedub;
2108 SCIP_Bool force;
2109
2110 assert(scip != NULL);
2111 assert(conshdlr != NULL);
2112 assert(expr != NULL);
2113 assert(cutoff != NULL);
2114
2115 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2117
2118 *cutoff = FALSE;
2119
2120 var = SCIPgetExprAuxVarNonlinear(expr);
2121 if( var == NULL )
2122 return SCIP_OKAY;
2123
2124 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2125 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2126
2127 /* try to tighten lower bound of (auxiliary) variable */
2128 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2129 if( tightenedlb )
2130 {
2131 if( ntightenings != NULL )
2132 ++*ntightenings;
2133 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2134 }
2135 if( *cutoff )
2136 {
2137 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2138 return SCIP_OKAY;
2139 }
2140
2141 /* try to tighten upper bound of (auxiliary) variable */
2142 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2143 if( tightenedub )
2144 {
2145 if( ntightenings != NULL )
2146 ++*ntightenings;
2147 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2148 }
2149 if( *cutoff )
2150 {
2151 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2152 return SCIP_OKAY;
2153 }
2154
2155 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2156 * that seems unnecessary and we could easily undo this here, e.g.,
2157 * if( tightenedlb ) expr->activity.inf = bounds.inf
2158 */
2159
2160 return SCIP_OKAY;
2161}
2162
2163/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2164 * and tries to tighten the bounds of the auxiliary variables accordingly
2165 */
2166static
2168 SCIP* scip, /**< SCIP data structure */
2169 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2170 SCIP_EXPR* rootexpr, /**< expression */
2171 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2172 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2173 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2174 )
2175{
2176 SCIP_EXPRITER* it;
2177 SCIP_EXPR* expr;
2178 SCIP_EXPR_OWNERDATA* ownerdata;
2179 SCIP_CONSHDLRDATA* conshdlrdata;
2180
2181 assert(scip != NULL);
2182 assert(rootexpr != NULL);
2183
2184 if( infeasible != NULL )
2185 *infeasible = FALSE;
2186 if( ntightenings != NULL )
2187 *ntightenings = 0;
2188
2189 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2190 assert(conshdlrdata != NULL);
2191
2192 /* if value is valid and empty, then we cannot improve, so do nothing */
2193 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2194 {
2195 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2196
2197 if( infeasible != NULL )
2198 *infeasible = TRUE;
2199
2200 /* just update tag to curboundstag */
2201 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2202
2203 return SCIP_OKAY;
2204 }
2205
2206 /* if value is up-to-date, then nothing to do */
2207 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2208 {
2209 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2210
2211 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2212
2213 return SCIP_OKAY;
2214 }
2215
2216 ownerdata = SCIPexprGetOwnerData(rootexpr);
2217 assert(ownerdata != NULL);
2218
2219 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2220 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2221 * during detect, we are in some in-between state where we may want to eval activity
2222 * on exprs that we did not notify about their activity usage
2223 */
2224 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2225 {
2226#ifdef DEBUG_PROP
2227 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2228#endif
2229 SCIPABORT();
2230 return SCIP_OKAY;
2231 }
2232
2236
2237 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2238 {
2239 switch( SCIPexpriterGetStageDFS(it) )
2240 {
2242 {
2243 /* skip child if it has been evaluated already */
2244 SCIP_EXPR* child;
2245
2246 child = SCIPexpriterGetChildExprDFS(it);
2247 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2248 {
2250 *infeasible = TRUE;
2251
2252 expr = SCIPexpriterSkipDFS(it);
2253 continue;
2254 }
2255
2256 break;
2257 }
2258
2260 {
2261 SCIP_INTERVAL activity;
2262
2263 /* we should not have entered this expression if its activity was already up to date */
2264 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2265
2266 ownerdata = SCIPexprGetOwnerData(expr);
2267 assert(ownerdata != NULL);
2268
2269 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2270 * so we can assume that the activity is up to date for all these variables
2271 * UNLESS we changed the method used to evaluate activity of variable expressions
2272 * or we currently use global bounds (varevents are catched for local bound changes only)
2273 */
2274 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2275 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2276 {
2277#ifndef NDEBUG
2278 SCIP_INTERVAL exprhdlrinterval;
2279
2280 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2281 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2282 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2283#endif
2284#ifdef DEBUG_PROP
2285 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2286#endif
2287 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2288
2289 break;
2290 }
2291
2292 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2293 {
2294 /* start with entire activity if current one is invalid */
2296 }
2298 {
2299 /* If already empty, then don't try to compute even better activity.
2300 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2301 * so an assert(infeasible == NULL || *infeasible) should work here.
2302 * However, after reporting a cutoff due to expr->activity being empty,
2303 * SCIP may wander to a different node and call propagation again.
2304 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2305 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2306 * we will still have expr->activity being empty, but will have forgotten
2307 * that we found infeasibility here before (!2221#note_134120).
2308 * Therefore we just set *infeasibility=TRUE here and stop.
2309 */
2310 if( infeasible != NULL )
2311 *infeasible = TRUE;
2312 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2313 break;
2314 }
2315 else
2316 {
2317 /* start with current activity, since it is valid */
2318 activity = SCIPexprGetActivity(expr);
2319 }
2320
2321 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2322 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2323 {
2324#ifdef DEBUG_PROP
2325 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2326#endif
2327 break;
2328 }
2329
2330#ifdef DEBUG_PROP
2331 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2332 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2333 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2334#endif
2335
2336 /* run interval eval of nonlinear handlers or expression handler */
2337 if( ownerdata->nenfos > 0 )
2338 {
2339 SCIP_NLHDLR* nlhdlr;
2340 SCIP_INTERVAL nlhdlrinterval;
2341 int e;
2342
2343 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2344 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2345 {
2346 /* skip nlhdlr if it does not want to participate in activity computation */
2347 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2348 continue;
2349
2350 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2351 assert(nlhdlr != NULL);
2352
2353 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2354 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2355 continue;
2356
2357 /* let nlhdlr evaluate current expression */
2358 nlhdlrinterval = activity;
2359 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2360 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2361#ifdef DEBUG_PROP
2362 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2363#endif
2364
2365 /* update activity by intersecting with computed activity */
2366 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2367#ifdef DEBUG_PROP
2368 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2369#endif
2370 }
2371 }
2372 else
2373 {
2374 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2375 SCIP_INTERVAL exprhdlrinterval = activity;
2376 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2377#ifdef DEBUG_PROP
2378 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2379#endif
2380
2381 /* update expr->activity by intersecting with computed activity */
2382 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2383#ifdef DEBUG_PROP
2384 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2385#endif
2386 }
2387
2388 /* if expression is integral, then we try to tighten the interval bounds a bit
2389 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2390 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2391 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2392 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2393 * (constants should be ok, too)
2394 */
2395 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2396 {
2397 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2398 activity.inf = SCIPceil(scip, activity.inf);
2399 if( activity.sup < SCIP_INTERVAL_INFINITY )
2400 activity.sup = SCIPfloor(scip, activity.sup);
2401#ifdef DEBUG_PROP
2402 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2403#endif
2404 }
2405
2406 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2407 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2408 */
2409 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2410 {
2411 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2412 SCIPintervalSetEmpty(&activity);
2413 }
2414
2415 /* now finally store activity in expr */
2416 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2417
2419 {
2420 if( infeasible != NULL )
2421 *infeasible = TRUE;
2422 }
2423 else if( tightenauxvars && ownerdata->auxvar != NULL )
2424 {
2425 SCIP_Bool tighteninfeasible;
2426
2427 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2428 if( tighteninfeasible )
2429 {
2430 if( infeasible != NULL )
2431 *infeasible = TRUE;
2432 SCIPintervalSetEmpty(&activity);
2433 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2434 }
2435 }
2436
2437 break;
2438 }
2439
2440 default:
2441 /* you should never be here */
2442 SCIPerrorMessage("unexpected iterator stage\n");
2443 SCIPABORT();
2444 break;
2445 }
2446
2447 expr = SCIPexpriterGetNext(it);
2448 }
2449
2450 SCIPfreeExpriter(&it);
2451
2452 return SCIP_OKAY;
2453}
2454
2455/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2456 *
2457 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2458 *
2459 * If `subsetsufficient` is FALSE, then we require
2460 * - a change from an unbounded interval to a bounded one, or
2461 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2462 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2463 */
2464static
2466 SCIP* scip, /**< SCIP data structure */
2467 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2468 SCIP_INTERVAL newinterval, /**< new interval */
2469 SCIP_INTERVAL oldinterval /**< old interval */
2470 )
2471{
2472 assert(scip != NULL);
2473 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2474 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2475
2476 if( subsetsufficient )
2477 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2478 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2479
2480 /* check whether lower bound of interval becomes finite */
2481 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2482 return TRUE;
2483
2484 /* check whether upper bound of interval becomes finite */
2485 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2486 return TRUE;
2487
2488 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2489 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2490 return TRUE;
2491
2492 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2493 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2494 return TRUE;
2495
2496 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2497 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2498 return TRUE;
2499
2500 return FALSE;
2501}
2502
2503/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2504 *
2505 * The expression will be traversed in breadth first search by using this queue.
2506 *
2507 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2508 * forwardPropExpr() before calling this function.
2509 *
2510 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2511 */
2512static
2514 SCIP* scip, /**< SCIP data structure */
2515 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2516 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2517 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2518 )
2519{
2520 SCIP_CONSHDLRDATA* conshdlrdata;
2521 SCIP_EXPR* expr;
2522 SCIP_EXPR_OWNERDATA* ownerdata;
2523
2524 assert(infeasible != NULL);
2525 assert(ntightenings != NULL);
2526
2527 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2528 assert(conshdlrdata != NULL);
2529
2530 *ntightenings = 0;
2531
2532 /* main loop that calls reverse propagation for expressions on the queue
2533 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2534 */
2535 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2536 {
2537 SCIP_INTERVAL propbounds;
2538 int e;
2539
2540 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2541 assert(expr != NULL);
2542
2543 ownerdata = SCIPexprGetOwnerData(expr);
2544 assert(ownerdata != NULL);
2545
2546 assert(ownerdata->inpropqueue);
2547 /* mark that the expression is not in the queue anymore */
2548 ownerdata->inpropqueue = FALSE;
2549
2550 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2551 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2552 */
2553 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2554 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2555 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2556
2557 /* this intersects propbounds with activity and auxvar bounds
2558 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2559 * auxvar bounds separately, so disabling this for now
2560 */
2561#ifdef SCIP_DISABLED_CODE
2562 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2564 {
2565 *infeasible = TRUE;
2566 break;
2567 }
2568#else
2569 propbounds = ownerdata->propbounds;
2570#endif
2571
2572 if( ownerdata->nenfos > 0 )
2573 {
2574 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2575 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2576 {
2577 SCIP_NLHDLR* nlhdlr;
2578 int nreds;
2579
2580 /* skip nlhdlr if it does not want to participate in activity computation */
2581 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2582 continue;
2583
2584 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2585 assert(nlhdlr != NULL);
2586
2587 /* call the reverseprop of the nlhdlr */
2588#ifdef SCIP_DEBUG
2589 SCIPdebugMsg(scip, "call reverse propagation for ");
2590 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2591 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2592#endif
2593
2594 nreds = 0;
2595 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2596 assert(nreds >= 0);
2597 *ntightenings += nreds;
2598 }
2599 }
2601 {
2602 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2603 SCIP_INTERVAL* childrenbounds;
2604 int c;
2605
2606#ifdef SCIP_DEBUG
2607 SCIPdebugMsg(scip, "call reverse propagation for ");
2608 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2609 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2610#endif
2611
2612 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2613 * been initialized in detectNlhdlr yet (nenfos < 0)
2614 */
2615 assert(ownerdata->nenfos < 0);
2616
2617 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2618 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2619 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2620
2621 /* call the reverseprop of the exprhdlr */
2622 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2623
2624 if( !*infeasible )
2625 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2626 {
2627 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2628 }
2629
2630 SCIPfreeBufferArray(scip, &childrenbounds);
2631 }
2632 }
2633
2634 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2635 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2636 {
2637 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2638 assert(expr != NULL);
2639
2640 ownerdata = SCIPexprGetOwnerData(expr);
2641 assert(ownerdata != NULL);
2642
2643 /* mark that the expression is not in the queue anymore */
2644 ownerdata->inpropqueue = FALSE;
2645 }
2646
2647 return SCIP_OKAY;
2648}
2649
2650/** calls domain propagation for a given set of constraints
2651 *
2652 * The algorithm alternates calls of forward and reverse propagation.
2653 * Forward propagation ensures that activity of expressions is up to date.
2654 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2655 * [lhs,rhs] interval as starting point.
2656 *
2657 * The propagation algorithm works as follows:
2658 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2659 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2660 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2661 * provide tighter bounds
2662 * 3. apply reverse propagation to all collected expressions; don't explore
2663 * sub-expressions which have not changed since the beginning of the propagation loop
2664 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2665 *
2666 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2667 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2668 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2669 *
2670 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2671 * e.g., try less to propagate on convex constraints?
2672 */
2673static
2675 SCIP* scip, /**< SCIP data structure */
2676 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2677 SCIP_CONS** conss, /**< constraints to propagate */
2678 int nconss, /**< total number of constraints */
2679 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2680 SCIP_RESULT* result, /**< pointer to store the result */
2681 int* nchgbds /**< buffer to add the number of changed bounds */
2682 )
2683{
2684 SCIP_CONSHDLRDATA* conshdlrdata;
2685 SCIP_CONSDATA* consdata;
2686 SCIP_EXPR_OWNERDATA* ownerdata;
2687 SCIP_Bool cutoff = FALSE;
2688 SCIP_INTERVAL conssides;
2689 int ntightenings;
2690 int roundnr;
2691 SCIP_EXPRITER* revpropcollectit = NULL;
2692 int i;
2693
2694 assert(scip != NULL);
2695 assert(conshdlr != NULL);
2696 assert(conss != NULL);
2697 assert(nconss >= 0);
2698 assert(result != NULL);
2699 assert(nchgbds != NULL);
2700 assert(*nchgbds >= 0);
2701
2702 /* no constraints to propagate */
2703 if( nconss == 0 )
2704 {
2705 *result = SCIP_DIDNOTRUN;
2706 return SCIP_OKAY;
2707 }
2708
2709 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2710 assert(conshdlrdata != NULL);
2711#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2712 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2713#endif
2714 assert(!conshdlrdata->globalbounds);
2715
2716 *result = SCIP_DIDNOTFIND;
2717 roundnr = 0;
2718
2719 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2720 conshdlrdata->forceboundtightening = force;
2721
2722 /* invalidate all propbounds (probably not needed) */
2723 ++conshdlrdata->curpropboundstag;
2724
2725 /* create iterator that we will use if we need to look at all auxvars */
2726 if( conshdlrdata->propauxvars )
2727 {
2728 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2729 }
2730
2731 /* main propagation loop */
2732 do
2733 {
2734 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2735
2736 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2737
2738 /* apply forward propagation (update expression activities)
2739 * and add promising root expressions into queue for reversepropagation
2740 */
2741 for( i = 0; i < nconss; ++i )
2742 {
2743 consdata = SCIPconsGetData(conss[i]);
2744 assert(consdata != NULL);
2745
2746 /* skip deleted, non-active, or propagation-disabled constraints */
2747 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2748 continue;
2749
2750 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2751 * activity didn't change
2752 */
2753 if( consdata->ispropagated )
2754 continue;
2755
2756 /* update activities in expression */
2757 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2758 SCIPdebugPrintCons(scip, conss[i], NULL);
2759
2760 ntightenings = 0;
2761 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2762 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2763
2764 if( cutoff )
2765 {
2766 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2767 *result = SCIP_CUTOFF;
2768 break;
2769 }
2770
2771 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2772
2773 /* 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 */
2774 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2775 {
2776 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2777 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2778 * so taking auxvar bounds is enough)
2779 */
2780 if( ownerdata->auxvar == NULL )
2781 {
2782 /* relax sides by SCIPepsilon() and handle infinite sides */
2783 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2784 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2785 SCIPintervalSetBounds(&conssides, lhs, rhs);
2786 }
2787 else
2788 {
2789 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2790 }
2791 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2792 }
2793 else
2794 {
2795 /* check whether bounds of any auxvar used in constraint provides a tightening
2796 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2797 * but skip exprs that have an auxvar, but do not participate in propagation
2798 */
2799 SCIP_EXPR* expr;
2800
2801 assert(revpropcollectit != NULL);
2802 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2803 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2804 {
2805 ownerdata = SCIPexprGetOwnerData(expr);
2806 assert(ownerdata != NULL);
2807
2808 if( ownerdata->auxvar == NULL )
2809 continue;
2810
2811 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2812 continue;
2813
2814 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2815 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2816 }
2817 }
2818
2819 if( cutoff )
2820 {
2821 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2822 *result = SCIP_CUTOFF;
2823 break;
2824 }
2825
2826 assert(ntightenings >= 0);
2827 if( ntightenings > 0 )
2828 {
2829 *nchgbds += ntightenings;
2830 *result = SCIP_REDUCEDDOM;
2831 }
2832
2833 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2834 consdata->ispropagated = TRUE;
2835 }
2836
2837 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2838 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2839 assert(ntightenings >= 0);
2840 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2841
2842 if( cutoff )
2843 {
2844 SCIPdebugMsg(scip, " -> cutoff\n");
2845 *result = SCIP_CUTOFF;
2846 break;
2847 }
2848
2849 if( ntightenings > 0 )
2850 {
2851 *nchgbds += ntightenings;
2852 *result = SCIP_REDUCEDDOM;
2853 }
2854 }
2855 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2856
2857 if( conshdlrdata->propauxvars )
2858 {
2859 SCIPfreeExpriter(&revpropcollectit);
2860 }
2861
2862 conshdlrdata->forceboundtightening = FALSE;
2863
2864 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2865 ++conshdlrdata->curpropboundstag;
2866
2867 return SCIP_OKAY;
2868}
2869
2870/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2871 *
2872 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2873 *
2874 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2875 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2876 */
2877static
2879 SCIP* scip, /**< SCIP data structure */
2880 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2881 SCIP_CONS** conss, /**< constraints to propagate */
2882 int nconss, /**< total number of constraints */
2883 SCIP_RESULT* result, /**< pointer to store the result */
2884 int* nchgbds /**< buffer to add the number of changed bounds */
2885 )
2886{
2887 SCIP_CONSDATA* consdata;
2888 SCIP_EXPRITER* it;
2889 SCIP_EXPR* expr;
2890 SCIP_EXPR_OWNERDATA* ownerdata;
2891 SCIP_Bool cutoff = FALSE;
2892 int ntightenings;
2893 int c;
2894 int e;
2895
2896 assert(scip != NULL);
2897 assert(conshdlr != NULL);
2898 assert(conss != NULL);
2899 assert(nconss >= 0);
2900 assert(result != NULL);
2901 assert(nchgbds != NULL);
2902 assert(*nchgbds >= 0);
2903
2904#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2905 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2906#endif
2907 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2908 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2909
2910 *result = SCIP_DIDNOTFIND;
2911
2914
2915 for( c = 0; c < nconss && !cutoff; ++c )
2916 {
2917 /* skip deleted, non-active, or propagation-disabled constraints */
2918 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2919 continue;
2920
2921 consdata = SCIPconsGetData(conss[c]);
2922 assert(consdata != NULL);
2923
2924 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2925 {
2926 ownerdata = SCIPexprGetOwnerData(expr);
2927 assert(ownerdata != NULL);
2928
2929 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2930 * this will propagate the current activity
2931 */
2932 for( e = 0; e < ownerdata->nenfos; ++e )
2933 {
2934 SCIP_NLHDLR* nlhdlr;
2935 assert(ownerdata->enfos[e] != NULL);
2936
2937 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2938 assert(nlhdlr != NULL);
2939 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2940 continue;
2941
2942 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2943 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2944 ntightenings = 0;
2945 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2946 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2947
2948 if( cutoff )
2949 {
2950 /* stop everything if we detected infeasibility */
2951 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2952 *result = SCIP_CUTOFF;
2953 break;
2954 }
2955
2956 assert(ntightenings >= 0);
2957 if( ntightenings > 0 )
2958 {
2959 *nchgbds += ntightenings;
2960 *result = SCIP_REDUCEDDOM;
2961 }
2962 }
2963 }
2964 }
2965
2966 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2967 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2968 assert(ntightenings >= 0);
2969
2970 if( cutoff )
2971 {
2972 SCIPdebugMsg(scip, " -> cutoff\n");
2973 *result = SCIP_CUTOFF;
2974 }
2975 else if( ntightenings > 0 )
2976 {
2977 *nchgbds += ntightenings;
2978 *result = SCIP_REDUCEDDOM;
2979 }
2980
2981 SCIPfreeExpriter(&it);
2982
2983 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2984 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2985
2986 return SCIP_OKAY;
2987}
2988
2989/** propagates variable locks through expression and adds locks to variables */
2990static
2992 SCIP* scip, /**< SCIP data structure */
2993 SCIP_EXPR* expr, /**< expression */
2994 int nlockspos, /**< number of positive locks */
2995 int nlocksneg /**< number of negative locks */
2996 )
2997{
2998 SCIP_EXPR_OWNERDATA* ownerdata;
2999 SCIP_EXPRITER* it;
3000 SCIP_EXPRITER_USERDATA ituserdata;
3001
3002 assert(expr != NULL);
3003
3004 /* if no locks, then nothing to propagate */
3005 if( nlockspos == 0 && nlocksneg == 0 )
3006 return SCIP_OKAY;
3007
3011 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3012
3013 /* store locks in root node */
3014 ituserdata.intvals[0] = nlockspos;
3015 ituserdata.intvals[1] = nlocksneg;
3016 SCIPexpriterSetCurrentUserData(it, ituserdata);
3017
3018 while( !SCIPexpriterIsEnd(it) )
3019 {
3020 /* collect locks */
3021 ituserdata = SCIPexpriterGetCurrentUserData(it);
3022 nlockspos = ituserdata.intvals[0];
3023 nlocksneg = ituserdata.intvals[1];
3024
3025 ownerdata = SCIPexprGetOwnerData(expr);
3026
3027 switch( SCIPexpriterGetStageDFS(it) )
3028 {
3030 {
3031 if( SCIPisExprVar(scip, expr) )
3032 {
3033 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3034 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3035 }
3036
3037 /* add locks to expression */
3038 ownerdata->nlockspos += nlockspos;
3039 ownerdata->nlocksneg += nlocksneg;
3040
3041 /* add monotonicity information if expression has been locked for the first time */
3042 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3044 {
3045 int i;
3046
3047 assert(ownerdata->monotonicity == NULL);
3048 assert(ownerdata->monotonicitysize == 0);
3049
3050 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3051 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3052
3053 /* store the monotonicity for each child */
3054 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3055 {
3056 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3057 }
3058 }
3059 break;
3060 }
3061
3063 {
3064 /* remove monotonicity information if expression has been unlocked */
3065 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3066 {
3067 assert(ownerdata->monotonicitysize > 0);
3068 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3069 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3070
3071 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3072 ownerdata->monotonicitysize = 0;
3073 }
3074 break;
3075 }
3076
3078 {
3079 SCIP_MONOTONE monotonicity;
3080
3081 /* get monotonicity of child */
3082 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3083 * SCIPcallExprMonotonicity
3084 */
3085 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3086
3087 /* compute resulting locks of the child expression */
3088 switch( monotonicity )
3089 {
3090 case SCIP_MONOTONE_INC:
3091 ituserdata.intvals[0] = nlockspos;
3092 ituserdata.intvals[1] = nlocksneg;
3093 break;
3094 case SCIP_MONOTONE_DEC:
3095 ituserdata.intvals[0] = nlocksneg;
3096 ituserdata.intvals[1] = nlockspos;
3097 break;
3099 ituserdata.intvals[0] = nlockspos + nlocksneg;
3100 ituserdata.intvals[1] = nlockspos + nlocksneg;
3101 break;
3103 ituserdata.intvals[0] = 0;
3104 ituserdata.intvals[1] = 0;
3105 break;
3106 }
3107 /* set locks in child expression */
3108 SCIPexpriterSetChildUserData(it, ituserdata);
3109
3110 break;
3111 }
3112
3113 default :
3114 /* you should never be here */
3115 SCIPABORT();
3116 break;
3117 }
3118
3119 expr = SCIPexpriterGetNext(it);
3120 }
3121
3122 SCIPfreeExpriter(&it);
3123
3124 return SCIP_OKAY;
3125}
3126
3127/** main function for adding locks to expressions and variables
3128 *
3129 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3130 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3131 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3132 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3133 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3134 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3135 * which implies that updating the monotonicity information during the next locking of this expression does not
3136 * break existing locks.
3137 *
3138 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3139 * locks from an expression and repropagating them after the structural changes have been applied.
3140 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3141 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3142 */
3143static
3145 SCIP* scip, /**< SCIP data structure */
3146 SCIP_CONS* cons, /**< nonlinear constraint */
3147 int nlockspos, /**< number of positive rounding locks */
3148 int nlocksneg /**< number of negative rounding locks */
3149 )
3150{
3151 SCIP_CONSDATA* consdata;
3152
3153 assert(cons != NULL);
3154
3155 if( nlockspos == 0 && nlocksneg == 0 )
3156 return SCIP_OKAY;
3157
3158 consdata = SCIPconsGetData(cons);
3159 assert(consdata != NULL);
3160
3161 /* no constraint sides -> nothing to lock */
3162 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3163 return SCIP_OKAY;
3164
3165 /* remember locks */
3166 consdata->nlockspos += nlockspos;
3167 consdata->nlocksneg += nlocksneg;
3168
3169 assert(consdata->nlockspos >= 0);
3170 assert(consdata->nlocksneg >= 0);
3171
3172 /* compute locks for lock propagation */
3173 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3174 {
3175 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3176 }
3177 else if( !SCIPisInfinity(scip, consdata->rhs) )
3178 {
3179 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3180 }
3181 else
3182 {
3183 assert(!SCIPisInfinity(scip, -consdata->lhs));
3184 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3185 }
3186
3187 return SCIP_OKAY;
3188}
3189
3190/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3191static
3193 SCIP* scip, /**< SCIP data structure */
3194 SCIP_CONS* cons /**< nonlinear constraint */
3195 )
3196{
3197 SCIP_CONSDATA* consdata;
3198
3199 assert(scip != NULL);
3200 assert(cons != NULL);
3201
3202 consdata = SCIPconsGetData(cons);
3203 assert(consdata != NULL);
3204 assert(consdata->expr != NULL);
3205
3206 if( consdata->nlrow != NULL )
3207 {
3208 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3209 }
3210
3211 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3212 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3213 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3214
3215 if( SCIPisExprSum(scip, consdata->expr) )
3216 {
3217 /* if root is a sum, then split into linear and nonlinear terms */
3218 SCIP_EXPR* nonlinpart;
3219 SCIP_EXPR* child;
3220 SCIP_Real* coefs;
3221 int i;
3222
3223 coefs = SCIPgetCoefsExprSum(consdata->expr);
3224
3225 /* constant term of sum */
3226 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3227
3228 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3229 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3230
3231 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3232 {
3233 child = SCIPexprGetChildren(consdata->expr)[i];
3234 if( SCIPisExprVar(scip, child) )
3235 {
3236 /* linear term */
3237 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3238 }
3239 else
3240 {
3241 /* nonlinear term */
3242 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3243 }
3244 }
3245
3246 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3247 {
3248 /* add expression to nlrow (this will make a copy) */
3249 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3250 }
3251 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3252 }
3253 else
3254 {
3255 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3256 }
3257
3258 return SCIP_OKAY;
3259}
3260
3261/** compares enfodata by enforcement priority of nonlinear handler
3262 *
3263 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3264 */
3265static
3267{
3268 SCIP_NLHDLR* h1;
3269 SCIP_NLHDLR* h2;
3270
3271 assert(elem1 != NULL);
3272 assert(elem2 != NULL);
3273
3274 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3275 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3276
3277 assert(h1 != NULL);
3278 assert(h2 != NULL);
3279
3282
3285
3286 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3287}
3288
3289/** install nlhdlrs in one expression */
3290static
3292 SCIP* scip, /**< SCIP data structure */
3293 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3294 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3295 )
3296{
3297 SCIP_EXPR_OWNERDATA* ownerdata;
3298 SCIP_CONSHDLRDATA* conshdlrdata;
3299 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3300 SCIP_NLHDLR_METHOD enforcemethods;
3301 SCIP_NLHDLR_METHOD enforcemethodsnew;
3302 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3303 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3304 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3305 int enfossize; /* allocated length of expr->enfos array */
3306 int h;
3307
3308 assert(expr != NULL);
3309
3310 ownerdata = SCIPexprGetOwnerData(expr);
3311 assert(ownerdata != NULL);
3312
3313 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3314 assert(conshdlrdata != NULL);
3315 assert(conshdlrdata->auxvarid >= 0);
3316 assert(!conshdlrdata->indetect);
3317
3318 /* there should be no enforcer yet and detection should not even have considered expr yet */
3319 assert(ownerdata->nenfos < 0);
3320 assert(ownerdata->enfos == NULL);
3321
3322 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3323 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3324 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3325 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3326 * - if no one uses activity, then do not need activity methods
3327 */
3328 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3329 if( ownerdata->nauxvaruses == 0 )
3330 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3331 else
3332 {
3333 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3334 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3335 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3336 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3337 }
3338 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3339 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3340
3341 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3342 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3343
3344 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3345 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3346
3347 ownerdata->nenfos = 0;
3348 enfossize = 2;
3349 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3350 conshdlrdata->indetect = TRUE;
3351
3352 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3353 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3354 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3355 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3356 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3357
3358 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3359 {
3360 SCIP_NLHDLR* nlhdlr;
3361
3362 nlhdlr = conshdlrdata->nlhdlrs[h];
3363 assert(nlhdlr != NULL);
3364
3365 /* skip disabled nlhdlrs */
3366 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3367 continue;
3368
3369 /* call detect routine of nlhdlr */
3370 nlhdlrexprdata = NULL;
3371 enforcemethodsnew = enforcemethods;
3372 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3373 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3374 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3375 /* coverity[var_deref_model] */
3376 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3377
3378 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3379 nlhdlrparticipating &= enforcemethodsallowed;
3380
3381 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3382 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3383
3384 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3385 * They are also cleaned up here to ensure that only the needed methods are claimed.
3386 */
3387 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3388
3389 /* nlhdlr needs to participate for the methods it is enforcing */
3390 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3391
3392 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3393 {
3394 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3395 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3396
3397 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3398 if( nlhdlrexprdata != NULL )
3399 {
3400 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3401 }
3402 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3403 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3404
3405 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3406
3407 continue;
3408 }
3409
3410 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3411 SCIPnlhdlrGetName(nlhdlr),
3412 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3413 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3414 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3415
3416 /* store nlhdlr and its data */
3417 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3418 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3419 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3420 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3421 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3422 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3423 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3424 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3425 ownerdata->nenfos++;
3426
3427 /* update enforcement flags */
3428 enforcemethods = enforcemethodsnew;
3429 }
3430
3431 conshdlrdata->indetect = FALSE;
3432
3433 /* stop if an enforcement method is missing but we are already in solving stage
3434 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3435 */
3436 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3437 {
3438 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3439 return SCIP_ERROR;
3440 }
3441
3442 assert(ownerdata->nenfos > 0);
3443
3444 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3445 if( ownerdata->nenfos > 1 )
3446 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3447
3448 /* resize enfos array to be nenfos long */
3449 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3450
3451 return SCIP_OKAY;
3452}
3453
3454/** detect nlhdlrs that can handle the expressions */
3455static
3457 SCIP* scip, /**< SCIP data structure */
3458 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3459 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3460 int nconss /**< total number of constraints */
3461 )
3462{
3463 SCIP_CONSHDLRDATA* conshdlrdata;
3464 SCIP_CONSDATA* consdata;
3465 SCIP_EXPR* expr;
3466 SCIP_EXPR_OWNERDATA* ownerdata;
3467 SCIP_EXPRITER* it;
3468 int i;
3469
3470 assert(conss != NULL || nconss == 0);
3471 assert(nconss >= 0);
3472 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 */
3473
3474 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3475 assert(conshdlrdata != NULL);
3476
3479
3481 {
3482 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3483 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3484 */
3486 conshdlrdata->globalbounds = TRUE;
3487 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3488 }
3489
3490 for( i = 0; i < nconss; ++i )
3491 {
3492 assert(conss != NULL && conss[i] != NULL);
3493
3494 consdata = SCIPconsGetData(conss[i]);
3495 assert(consdata != NULL);
3496 assert(consdata->expr != NULL);
3497
3498 /* if a constraint is separated, we currently need it to be initial, too
3499 * this is because INITLP will create the auxiliary variables that are used for any separation
3500 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3501 */
3502 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3503
3504 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3505 assert(ownerdata != NULL);
3506
3507 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3508 * then we would normally skip to run DETECT again
3509 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3510 * thus, if expr is the root expression, we rerun DETECT
3511 */
3512 if( ownerdata->nenfos > 0 )
3513 {
3514 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3515 assert(ownerdata->nenfos < 0);
3516 }
3517
3518 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3519 * this way we can treat the root expression like any other expression when enforcing via separation
3520 * if constraint will be propagated, then register activity usage of root expression
3521 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3522 */
3523 conshdlrdata->indetect = TRUE;
3526 SCIPconsIsPropagated(conss[i]),
3527 FALSE, FALSE) );
3528 conshdlrdata->indetect = FALSE;
3529
3530 /* compute integrality information for all subexpressions */
3531 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3532
3533 /* run detectNlhdlr on all expr where required */
3534 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3535 {
3536 ownerdata = SCIPexprGetOwnerData(expr);
3537 assert(ownerdata != NULL);
3538
3539 /* skip exprs that we already looked at */
3540 if( ownerdata->nenfos >= 0 )
3541 continue;
3542
3543 /* if there is use of the auxvar, then someone requires that
3544 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3545 * thus, we need to find nlhdlrs that separate or estimate
3546 * if there is use of the activity, then there is someone requiring that
3547 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3548 * thus, we need to find nlhdlrs that do interval-evaluation
3549 */
3550 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3551 {
3552 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3553
3554 assert(ownerdata->nenfos >= 0);
3555 }
3556 else
3557 {
3558 /* remember that we looked at this expression during detectNlhdlrs
3559 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3560 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3561 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3562 */
3563 ownerdata->nenfos = 0;
3564 }
3565 }
3566
3567 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3568 if( SCIPconsIsPropagated(conss[i]) )
3569 consdata->ispropagated = FALSE;
3570 }
3571
3573 {
3574 /* ensure that the local bounds are used again when reevaluating the expressions later;
3575 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3576 */
3578 conshdlrdata->globalbounds = FALSE;
3579 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3580 }
3581 else
3582 {
3583 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3585 }
3586
3587 SCIPfreeExpriter(&it);
3588
3589 return SCIP_OKAY;
3590}
3591
3592/** initializes (pre)solving data of constraints
3593 *
3594 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3595 * not be modified.
3596 * In particular, this function
3597 * - runs the detection method of nlhldrs
3598 * - looks for unlocked linear variables
3599 * - checks curvature (if not in presolve)
3600 * - creates and add row to NLP (if not in presolve)
3601 *
3602 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3603 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3604 */
3605static
3607 SCIP* scip, /**< SCIP data structure */
3608 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3609 SCIP_CONS** conss, /**< constraints */
3610 int nconss /**< number of constraints */
3611 )
3612{
3613 int c;
3614
3615 for( c = 0; c < nconss; ++c )
3616 {
3617 /* check for a linear variable that can be increase or decreased without harming feasibility */
3618 findUnlockedLinearVar(scip, conss[c]);
3619
3621 {
3622 SCIP_CONSDATA* consdata;
3623 SCIP_Bool success = FALSE;
3624
3625 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3626 assert(consdata != NULL);
3627 assert(consdata->expr != NULL);
3628
3629 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3630 {
3631 /* call the curvature detection algorithm of the convex nonlinear handler
3632 * Check only for those curvature that may result in a convex inequality, i.e.,
3633 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3634 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3635 */
3636 if( !SCIPisInfinity(scip, -consdata->lhs) )
3637 {
3638 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3639 if( success )
3640 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3641 }
3642 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3643 {
3644 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3645 if( success )
3646 consdata->curv = SCIP_EXPRCURV_CONVEX;
3647 }
3648 }
3649 else
3650 {
3651 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3652 {
3653 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3654 consdata->curv = SCIP_EXPRCURV_LINEAR;
3655 }
3656 else
3657 {
3658 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3659 }
3660 }
3661 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3662
3663 /* add nlrow representation to NLP, if NLP had been constructed */
3664 if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3665 {
3666 if( consdata->nlrow == NULL )
3667 {
3668 SCIP_CALL( createNlRow(scip, conss[c]) );
3669 assert(consdata->nlrow != NULL);
3670 }
3671 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3672 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3673 }
3674 }
3675 }
3676
3677 /* register non linear handlers */
3678 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3679
3680 return SCIP_OKAY;
3681}
3682
3683/** deinitializes (pre)solving data of constraints
3684 *
3685 * This removes the initialization data created in initSolve().
3686 *
3687 * This function can be called in presolve and solve.
3688 *
3689 * TODO At the moment, it should not be called for a constraint if there are other constraints
3690 * that use the same expressions but still require their nlhdlr.
3691 * We should probably only decrement the auxvar and activity usage for the root expr and then
3692 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3693 */
3694static
3696 SCIP* scip, /**< SCIP data structure */
3697 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3698 SCIP_CONS** conss, /**< constraints */
3699 int nconss /**< number of constraints */
3700 )
3701{
3702 SCIP_EXPRITER* it;
3703 SCIP_EXPR* expr;
3704 SCIP_CONSDATA* consdata;
3705 SCIP_Bool rootactivityvalid;
3706 int c;
3707
3711
3712 /* call deinitialization callbacks of expression and nonlinear handlers
3713 * free nonlinear handlers information from expressions
3714 * remove auxiliary variables and nactivityuses counts from expressions
3715 */
3716 for( c = 0; c < nconss; ++c )
3717 {
3718 assert(conss != NULL);
3719 assert(conss[c] != NULL);
3720
3721 consdata = SCIPconsGetData(conss[c]);
3722 assert(consdata != NULL);
3723 assert(consdata->expr != NULL);
3724
3725 /* check and remember whether activity in root is valid */
3726 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3727
3728 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3729 {
3730 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3731
3732 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3733 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3734
3735 /* remove quadratic info */
3737
3738 if( rootactivityvalid )
3739 {
3740 /* ensure activity is valid if consdata->expr activity is valid
3741 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3742 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3743 * so this childs activity would be invalid, which can generate confusion
3744 */
3746 }
3747 }
3748
3749 if( consdata->nlrow != NULL )
3750 {
3751 /* remove row from NLP, if still in solving
3752 * if we are in exitsolve, the whole NLP will be freed anyway
3753 */
3755 {
3756 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3757 }
3758
3759 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3760 }
3761
3762 /* forget about linear variables that can be increased or decreased without harming feasibility */
3763 consdata->linvardecr = NULL;
3764 consdata->linvarincr = NULL;
3765
3766 /* forget about curvature */
3767 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3768 }
3769
3770 SCIPfreeExpriter(&it);
3771
3772 return SCIP_OKAY;
3773}
3774
3775/** helper method to decide whether a given expression is product of at least two binary variables */
3776static
3778 SCIP* scip, /**< SCIP data structure */
3779 SCIP_EXPR* expr /**< expression */
3780 )
3781{
3782 int i;
3783
3784 assert(expr != NULL);
3785
3786 /* check whether the expression is a product */
3787 if( !SCIPisExprProduct(scip, expr) )
3788 return FALSE;
3789
3790 /* don't consider products with a coefficient != 1 and products with a single child
3791 * simplification will take care of this expression later
3792 */
3793 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3794 return FALSE;
3795
3796 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3797 {
3798 SCIP_EXPR* child;
3799 SCIP_VAR* var;
3800 SCIP_Real ub;
3801 SCIP_Real lb;
3802
3803 child = SCIPexprGetChildren(expr)[i];
3804 assert(child != NULL);
3805
3806 if( !SCIPisExprVar(scip, child) )
3807 return FALSE;
3808
3809 var = SCIPgetVarExprVar(child);
3810 lb = SCIPvarGetLbLocal(var);
3811 ub = SCIPvarGetUbLocal(var);
3812
3813 /* check whether variable is integer and has [0,1] as variable bounds */
3814 if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3815 return FALSE;
3816 }
3817
3818 return TRUE;
3819}
3820
3821/** helper method to collect all bilinear binary product terms */
3822static
3824 SCIP* scip, /**< SCIP data structure */
3825 SCIP_EXPR* sumexpr, /**< sum expression */
3826 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3827 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3828 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3829 int* nterms /**< pointer to store the total number of bilinear binary terms */
3830 )
3831{
3832 int i;
3833
3834 assert(sumexpr != NULL);
3835 assert(SCIPisExprSum(scip, sumexpr));
3836 assert(xs != NULL);
3837 assert(ys != NULL);
3838 assert(childidxs != NULL);
3839 assert(nterms != NULL);
3840
3841 *nterms = 0;
3842
3843 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3844 {
3845 SCIP_EXPR* child;
3846
3847 child = SCIPexprGetChildren(sumexpr)[i];
3848 assert(child != NULL);
3849
3850 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3851 {
3854
3855 assert(x != NULL);
3856 assert(y != NULL);
3857
3858 if( x != y )
3859 {
3860 xs[*nterms] = x;
3861 ys[*nterms] = y;
3862 childidxs[*nterms] = i;
3863 ++(*nterms);
3864 }
3865 }
3866 }
3867
3868 return SCIP_OKAY;
3869}
3870
3871/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3872static
3874 SCIP* scip, /**< SCIP data structure */
3875 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3876 SCIP_CONS* cons, /**< constraint */
3877 SCIP_VAR* facvar, /**< variable that has been factorized */
3878 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3879 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3880 int nvars, /**< total number of variables in sum_j c_ij x_j */
3881 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3882 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3883 )
3884{
3885 SCIP_VAR* auxvar;
3886 SCIP_CONS* newcons;
3887 SCIP_Real minact = 0.0;
3888 SCIP_Real maxact = 0.0;
3889 SCIP_Bool integral = TRUE;
3890 char name [SCIP_MAXSTRLEN];
3891 int i;
3892
3893 assert(facvar != NULL);
3894 assert(vars != NULL);
3895 assert(nvars > 1);
3896 assert(newexpr != NULL);
3897
3898 /* compute minimum and maximum activity of sum_j c_ij x_j */
3899 /* 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 */
3900 for( i = 0; i < nvars; ++i )
3901 {
3902 minact += MIN(coefs[i], 0.0);
3903 maxact += MAX(coefs[i], 0.0);
3904 integral = integral && SCIPisIntegral(scip, coefs[i]);
3905 }
3906 assert(minact <= maxact);
3907
3908 /* create and add auxiliary variable */
3909 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3910 SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3911 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3912
3913#ifdef WITH_DEBUG_SOLUTION
3914 if( SCIPdebugIsMainscip(scip) )
3915 {
3916 SCIP_Real debugsolval; /* value of auxvar in debug solution */
3917 SCIP_Real val;
3918
3919 /* compute value of new variable in debug solution */
3920 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
3921 debugsolval = 0.0;
3922 for( i = 0; i < nvars; ++i )
3923 {
3924 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
3925 debugsolval += coefs[i] * val;
3926 }
3927
3928 /* now multiply by x_i (facvar) */
3929 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
3930 debugsolval *= val;
3931
3932 /* store debug solution value of auxiliary variable */
3933 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
3934 }
3935#endif
3936
3937 /* create and add z - maxact x <= 0 */
3938 if( !SCIPisZero(scip, maxact) )
3939 {
3940 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3941 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3942 SCIP_CALL( SCIPaddCons(scip, newcons) );
3943 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3944 if( naddconss != NULL )
3945 ++(*naddconss);
3946 }
3947
3948 /* create and add 0 <= z - minact x */
3949 if( !SCIPisZero(scip, minact) )
3950 {
3951 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3952 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3953 SCIP_CALL( SCIPaddCons(scip, newcons) );
3954 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3955 if( naddconss != NULL )
3956 ++(*naddconss);
3957 }
3958
3959 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3960 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3961 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3962 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3963 if( !SCIPisZero(scip, minact) )
3964 {
3965 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3966 }
3967 SCIP_CALL( SCIPaddCons(scip, newcons) );
3968 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3969 if( naddconss != NULL )
3970 ++(*naddconss);
3971
3972 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
3973 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3974 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3975 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3976 if( !SCIPisZero(scip, maxact) )
3977 {
3978 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
3979 }
3980 SCIP_CALL( SCIPaddCons(scip, newcons) );
3981 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3982 if( naddconss != NULL )
3983 ++(*naddconss);
3984
3985 /* create variable expression */
3986 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
3987
3988 /* release auxvar */
3989 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3990
3991 return SCIP_OKAY;
3992}
3993
3994/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3995static
3997 SCIP* scip, /**< SCIP data structure */
3998 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3999 SCIP_CONS* cons, /**< constraint */
4000 SCIP_EXPR* sumexpr, /**< expression */
4001 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4002 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4003 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4004 )
4005{
4006 SCIP_EXPR** exprs = NULL;
4007 SCIP_VAR** tmpvars = NULL;
4008 SCIP_VAR** vars = NULL;
4009 SCIP_VAR** xs = NULL;
4010 SCIP_VAR** ys = NULL;
4011 SCIP_Real* exprcoefs = NULL;
4012 SCIP_Real* tmpcoefs = NULL;
4013 SCIP_Real* sumcoefs;
4014 SCIP_Bool* isused = NULL;
4015 int* childidxs = NULL;
4016 int* count = NULL;
4017 int nchildren;
4018 int nexprs = 0;
4019 int nterms;
4020 int nvars;
4021 int ntotalvars;
4022 int i;
4023
4024 assert(sumexpr != NULL);
4025 assert(minterms > 1);
4026 assert(newexpr != NULL);
4027
4028 *newexpr = NULL;
4029
4030 /* check whether sumexpr is indeed a sum */
4031 if( !SCIPisExprSum(scip, sumexpr) )
4032 return SCIP_OKAY;
4033
4034 nchildren = SCIPexprGetNChildren(sumexpr);
4035 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4036 nvars = SCIPgetNVars(scip);
4037 ntotalvars = SCIPgetNTotalVars(scip);
4038
4039 /* check whether there are enough terms available */
4040 if( nchildren < minterms )
4041 return SCIP_OKAY;
4042
4043 /* allocate memory */
4044 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4045 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4046 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4047
4048 /* collect all bilinear binary product terms */
4049 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4050
4051 /* check whether there are enough terms available */
4052 if( nterms < minterms )
4053 goto TERMINATE;
4054
4055 /* store how often each variable appears in a bilinear binary product */
4057 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4058 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4059
4060 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4061 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4062 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4063 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4064
4065 for( i = 0; i < nterms; ++i )
4066 {
4067 int xidx;
4068 int yidx;
4069
4070 assert(xs[i] != NULL);
4071 assert(ys[i] != NULL);
4072
4073 xidx = SCIPvarGetIndex(xs[i]);
4074 assert(xidx < ntotalvars);
4075 yidx = SCIPvarGetIndex(ys[i]);
4076 assert(yidx < ntotalvars);
4077
4078 ++count[xidx];
4079 ++count[yidx];
4080
4081 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4082 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4083 }
4084
4085 /* sort variables; don't change order of count array because it depends on problem indices */
4086 {
4087 int* tmpcount;
4088
4089 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4090 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4091 SCIPfreeBufferArray(scip, &tmpcount);
4092 }
4093
4094 for( i = 0; i < nvars; ++i )
4095 {
4096 SCIP_VAR* facvar = vars[i];
4097 int ntmpvars = 0;
4098 int j;
4099
4100 /* skip candidate if there are not enough terms left */
4101 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4102 continue;
4103
4104 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4105
4106 /* collect variables for x_i * sum_j c_ij x_j */
4107 for( j = 0; j < nterms; ++j )
4108 {
4109 int childidx = childidxs[j];
4110 assert(childidx >= 0 && childidx < nchildren);
4111
4112 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4113 {
4114 SCIP_Real coef;
4115 int xidx;
4116 int yidx;
4117
4118 coef = sumcoefs[childidx];
4119 assert(coef != 0.0);
4120
4121 /* collect corresponding variable */
4122 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4123 tmpcoefs[ntmpvars] = coef;
4124 ++ntmpvars;
4125
4126 /* update counters */
4127 xidx = SCIPvarGetIndex(xs[j]);
4128 assert(xidx < ntotalvars);
4129 yidx = SCIPvarGetIndex(ys[j]);
4130 assert(yidx < ntotalvars);
4131 --count[xidx];
4132 --count[yidx];
4133 assert(count[xidx] >= 0);
4134 assert(count[yidx] >= 0);
4135
4136 /* mark term to be used */
4137 isused[childidx] = TRUE;
4138 }
4139 }
4140 assert(ntmpvars >= minterms);
4141 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4142 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4143
4144 /* create required constraints and store the generated expression */
4145 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4146 exprcoefs[nexprs] = 1.0;
4147 ++nexprs;
4148 }
4149
4150 /* factorization was only successful if at least one expression has been generated */
4151 if( nexprs > 0 )
4152 {
4153 int nexprsold = nexprs;
4154
4155 /* add all children of the sum that have not been used */
4156 for( i = 0; i < nchildren; ++i )
4157 {
4158 if( !isused[i] )
4159 {
4160 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4161 exprcoefs[nexprs] = sumcoefs[i];
4162 ++nexprs;
4163 }
4164 }
4165
4166 /* create a new sum expression */
4167 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4168
4169 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4170 for( i = 0; i < nexprsold; ++i )
4171 {
4172 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4173 }
4174 }
4175
4176TERMINATE:
4177 /* free memory */
4178 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4179 SCIPfreeBufferArrayNull(scip, &tmpvars);
4180 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4183 SCIPfreeBufferArrayNull(scip, &isused);
4185 SCIPfreeBufferArray(scip, &childidxs);
4188
4189 return SCIP_OKAY;
4190}
4191
4192/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4193static
4195 SCIP* scip, /**< SCIP data structure */
4196 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4197 SCIP_EXPR* prodexpr, /**< product expression */
4198 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4199 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4200 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4201 )
4202{
4203 SCIP_VAR** vars;
4204 SCIP_CONS* cons;
4205 SCIP_Real* coefs;
4206 SCIP_VAR* w;
4207 char* name;
4208 int nchildren;
4209 int i;
4210
4211 assert(conshdlr != NULL);
4212 assert(prodexpr != NULL);
4213 assert(SCIPisExprProduct(scip, prodexpr));
4214 assert(newexpr != NULL);
4215
4216 nchildren = SCIPexprGetNChildren(prodexpr);
4217 assert(nchildren >= 2);
4218
4219 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4220 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4221 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4222 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4223
4224 /* prepare the names of the variable and the constraints */
4225 /* coverity[secure_coding] */
4226 strcpy(name, "binreform");
4227 for( i = 0; i < nchildren; ++i )
4228 {
4229 vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4230 coefs[i] = 1.0;
4231 assert(vars[i] != NULL);
4232 (void) strcat(name, "_");
4233 (void) strcat(name, SCIPvarGetName(vars[i]));
4234 }
4235
4236 /* create and add variable */
4237 SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4239 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4240
4241#ifdef WITH_DEBUG_SOLUTION
4242 if( SCIPdebugIsMainscip(scip) )
4243 {
4244 SCIP_Real debugsolval; /* value of auxvar in debug solution */
4245 SCIP_Real val;
4246
4247 /* compute value of new variable in debug solution (\prod_i vars[i]) */
4248 debugsolval = 1.0;
4249 for( i = 0; i < nchildren; ++i )
4250 {
4251 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
4252 debugsolval *= val;
4253 }
4254
4255 /* store debug solution value of auxiliary variable */
4256 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
4257 }
4258#endif
4259
4260 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4261 if( nchildren == 2 && !empathy4and )
4262 {
4263 SCIP_VAR* x = vars[0];
4264 SCIP_VAR* y = vars[1];
4265
4266 assert(x != NULL);
4267 assert(y != NULL);
4268 assert(x != y);
4269
4270 /* create and add x - w >= 0 */
4271 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4272 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4273 SCIP_CALL( SCIPaddCons(scip, cons) );
4274 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4275
4276 /* create and add y - w >= 0 */
4277 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4278 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4279 SCIP_CALL( SCIPaddCons(scip, cons) );
4280 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4281
4282 /* create and add x + y - w <= 1 */
4283 vars[2] = w;
4284 coefs[2] = -1.0;
4285 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4286 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4287 SCIP_CALL( SCIPaddCons(scip, cons) );
4288 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4289
4290 /* update number of added constraints */
4291 if( naddconss != NULL )
4292 *naddconss += 3;
4293 }
4294 else
4295 {
4296 /* create, add, and release AND constraint */
4297 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4298 SCIP_CALL( SCIPaddCons(scip, cons) );
4299 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4300 SCIPdebugMsg(scip, " create AND constraint\n");
4301
4302 /* update number of added constraints */
4303 if( naddconss != NULL )
4304 *naddconss += 1;
4305 }
4306
4307 /* create variable expression */
4308 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4309
4310 /* release created variable */
4312
4313 /* free memory */
4314 SCIPfreeBufferArray(scip, &name);
4315 SCIPfreeBufferArray(scip, &coefs);
4316 SCIPfreeBufferArray(scip, &vars);
4317
4318 return SCIP_OKAY;
4319}
4320
4321/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4322static
4324 SCIP* scip, /**< SCIP data structure */
4325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4326 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4327 SCIP_EXPR* prodexpr, /**< product expression */
4328 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4329 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4330 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4331 )
4332{
4333 SCIP_CONSHDLRDATA* conshdlrdata;
4334 int nchildren;
4335
4336 assert(prodexpr != NULL);
4337 assert(newexpr != NULL);
4338
4339 *newexpr = NULL;
4340
4341 /* only consider products of binary variables */
4342 if( !isBinaryProduct(scip, prodexpr) )
4343 return SCIP_OKAY;
4344
4345 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4346 assert(conshdlrdata != NULL);
4347 nchildren = SCIPexprGetNChildren(prodexpr);
4348 assert(nchildren >= 2);
4349
4350 /* check whether there is already an expression that represents the product */
4351 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4352 {
4353 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4354 assert(*newexpr != NULL);
4355
4356 /* capture expression */
4357 SCIPcaptureExpr(*newexpr);
4358 }
4359 else
4360 {
4361 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4362
4363 if( nchildren == 2 )
4364 {
4365 SCIP_CLIQUE** xcliques;
4366 SCIP_VAR* x;
4367 SCIP_VAR* y;
4368 SCIP_Bool found_clique = FALSE;
4369 int c;
4370
4371 /* get variables from the product expression */
4372 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4373 assert(x != NULL);
4374 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4375 assert(y != NULL);
4376 assert(x != y);
4377
4378 /* first try to find a clique containing both variables */
4379 xcliques = SCIPvarGetCliques(x, TRUE);
4380
4381 /* look in cliques containing x */
4382 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4383 {
4384 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4385 {
4386 /* create zero value expression */
4387 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4388
4389 if( nchgcoefs != NULL )
4390 *nchgcoefs += 1;
4391
4392 found_clique = TRUE;
4393 break;
4394 }
4395
4396 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4397 {
4398 /* create variable expression for x */
4399 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4400
4401 if( nchgcoefs != NULL )
4402 *nchgcoefs += 2;
4403
4404 found_clique = TRUE;
4405 break;
4406 }
4407 }
4408
4409 if( !found_clique )
4410 {
4411 xcliques = SCIPvarGetCliques(x, FALSE);
4412
4413 /* look in cliques containing complement of x */
4414 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4415 {
4416 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4417 {
4418 /* create variable expression for y */
4419 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4420
4421 if( nchgcoefs != NULL )
4422 *nchgcoefs += 1;
4423
4424 found_clique = TRUE;
4425 break;
4426 }
4427
4428 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4429 {
4430 /* create sum expression */
4431 SCIP_EXPR* sum_children[2];
4432 SCIP_Real sum_coefs[2];
4433 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4434 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4435 sum_coefs[0] = 1.0;
4436 sum_coefs[1] = 1.0;
4437 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4438
4439 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4440 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4441
4442 if( nchgcoefs != NULL )
4443 *nchgcoefs += 3;
4444
4445 found_clique = TRUE;
4446 break;
4447 }
4448 }
4449 }
4450
4451 /* if the variables are not in a clique, do standard linearization */
4452 if( !found_clique )
4453 {
4454 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4455 }
4456 }
4457 else
4458 {
4459 /* linearize binary product using an AND constraint because nchildren > 2 */
4460 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4461 }
4462
4463 /* hash variable expression */
4464 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4465 }
4466
4467 return SCIP_OKAY;
4468}
4469
4470/** helper function to replace binary products in a given constraint */
4471static
4473 SCIP* scip, /**< SCIP data structure */
4474 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4475 SCIP_CONS* cons, /**< constraint */
4476 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4477 SCIP_EXPRITER* it, /**< expression iterator */
4478 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4479 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4480 )
4481{
4482 SCIP_CONSHDLRDATA* conshdlrdata;
4483 SCIP_CONSDATA* consdata;
4484 SCIP_EXPR* expr;
4485
4486 assert(conshdlr != NULL);
4487 assert(cons != NULL);
4488 assert(exprmap != NULL);
4489 assert(it != NULL);
4490
4491 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4492 assert(conshdlrdata != NULL);
4493
4494 consdata = SCIPconsGetData(cons);
4495 assert(consdata != NULL);
4496 assert(consdata->expr != NULL);
4497
4498 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4499
4500 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4501 {
4502 SCIP_EXPR* newexpr = NULL;
4503 SCIP_EXPR* childexpr;
4504 int childexpridx;
4505
4506 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4507 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4508 childexpr = SCIPexpriterGetChildExprDFS(it);
4509 assert(childexpr != NULL);
4510
4511 /* try to factorize variables in a sum expression that contains several products of binary variables */
4512 if( conshdlrdata->reformbinprodsfac > 1 )
4513 {
4514 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4515 }
4516
4517 /* try to create an expression that represents a product of binary variables */
4518 if( newexpr == NULL )
4519 {
4520 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4521 }
4522
4523 if( newexpr != NULL )
4524 {
4525 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4526
4527 /* replace product expression */
4528 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4529
4530 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4531 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4532
4533 /* mark the constraint to not be simplified anymore */
4534 consdata->issimplified = FALSE;
4535 }
4536 }
4537
4538 return SCIP_OKAY;
4539}
4540
4541/** reformulates products of binary variables during presolving in the following way:
4542 *
4543 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4544 * 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}:
4545 * \f[
4546 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4547 * \f]
4548 *
4549 * 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$.
4550 * These cliques allow for a better reformulation. There are four cases:
4551 *
4552 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4553 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4554 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4555 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4556 *
4557 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4558 *
4559 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4560 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4561 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4562 * Such a lower sum is reformulated with only one extra variable w_i:
4563 * \f{align}{
4564 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4565 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4566 * \text{minact}\, x_i & \leq w_i, \\
4567 * w_i &\leq \text{maxact}\, x_i, \\
4568 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4569 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4570 * \f}
4571 * 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
4572 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4573 * of terms are prioritized.
4574 */
4575static
4577 SCIP* scip, /**< SCIP data structure */
4578 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4579 SCIP_CONS** conss, /**< constraints */
4580 int nconss, /**< total number of constraints */
4581 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4582 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4583 )
4584{
4585 SCIP_CONSHDLRDATA* conshdlrdata;
4586 SCIP_HASHMAP* exprmap;
4587 SCIP_EXPRITER* it;
4588 int c;
4589
4590 assert(conshdlr != NULL);
4591
4592 /* no nonlinear constraints or binary variables -> skip */
4593 if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4594 return SCIP_OKAY;
4595 assert(conss != NULL);
4596
4597 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4598 assert(conshdlrdata != NULL);
4599
4600 /* create expression hash map */
4602
4603 /* create expression iterator */
4607
4608 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4609
4610 for( c = 0; c < nconss; ++c )
4611 {
4612 SCIP_CONSDATA* consdata;
4613 SCIP_EXPR* newexpr = NULL;
4614
4615 assert(conss[c] != NULL);
4616
4617 consdata = SCIPconsGetData(conss[c]);
4618 assert(consdata != NULL);
4619
4620 /* try to reformulate the root expression */
4621 if( conshdlrdata->reformbinprodsfac > 1 )
4622 {
4623 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4624 }
4625
4626 /* release the root node if another expression has been found */
4627 if( newexpr != NULL )
4628 {
4629 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4630 consdata->expr = newexpr;
4631
4632 /* mark constraint to be not simplified anymore */
4633 consdata->issimplified = FALSE;
4634 }
4635
4636 /* replace each product of binary variables separately */
4637 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4638 }
4639
4640 /* free memory */
4641 SCIPhashmapFree(&exprmap);
4642 SCIPfreeExpriter(&it);
4643
4644 return SCIP_OKAY;
4645}
4646
4647/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4648 *
4649 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4650 * Then scale by -1 if
4651 * - \f$n_+ < n_-\f$, or
4652 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4653 */
4654static
4656 SCIP* scip, /**< SCIP data structure */
4657 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4658 SCIP_CONS* cons, /**< nonlinear constraint */
4659 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4660 )
4661{
4662 SCIP_CONSDATA* consdata;
4663 int i;
4664
4665 assert(cons != NULL);
4666
4667 consdata = SCIPconsGetData(cons);
4668 assert(consdata != NULL);
4669
4670 if( SCIPisExprSum(scip, consdata->expr) )
4671 {
4672 SCIP_Real* coefs;
4673 SCIP_Real constant;
4674 int nchildren;
4675 int counter = 0;
4676
4677 coefs = SCIPgetCoefsExprSum(consdata->expr);
4678 constant = SCIPgetConstantExprSum(consdata->expr);
4679 nchildren = SCIPexprGetNChildren(consdata->expr);
4680
4681 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4682 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4683 {
4684 SCIP_EXPR* expr;
4685 expr = consdata->expr;
4686
4687 consdata->expr = SCIPexprGetChildren(expr)[0];
4688 assert(!SCIPisExprSum(scip, consdata->expr));
4689
4690 SCIPcaptureExpr(consdata->expr);
4691
4692 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4693 consdata->lhs = -consdata->lhs;
4694 consdata->rhs = -consdata->rhs;
4695
4696 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4697 *changed = TRUE;
4698 return SCIP_OKAY;
4699 }
4700
4701 /* compute n_+ - n_i */
4702 for( i = 0; i < nchildren; ++i )
4703 counter += coefs[i] > 0 ? 1 : -1;
4704
4705 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4706 {
4707 SCIP_EXPR* expr;
4708 SCIP_Real* newcoefs;
4709
4710 /* allocate memory */
4711 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4712
4713 for( i = 0; i < nchildren; ++i )
4714 newcoefs[i] = -coefs[i];
4715
4716 /* create a new sum expression */
4717 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4718
4719 /* replace expression in constraint data and scale sides */
4720 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4721 consdata->expr = expr;
4722 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4723 consdata->lhs = -consdata->lhs;
4724 consdata->rhs = -consdata->rhs;
4725
4726 /* free memory */
4727 SCIPfreeBufferArray(scip, &newcoefs);
4728
4729 *changed = TRUE;
4730 }
4731 }
4732
4733 return SCIP_OKAY;
4734}
4735
4736/** forbid multiaggrations of variables that appear nonlinear in constraints */
4737static
4739 SCIP* scip, /**< SCIP data structure */
4740 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4741 SCIP_CONS** conss, /**< constraints */
4742 int nconss /**< number of constraints */
4743 )
4744{
4745 SCIP_EXPRITER* it;
4746 SCIP_CONSDATA* consdata;
4747 SCIP_EXPR* expr;
4748 int c;
4749
4750 assert(scip != NULL);
4751 assert(conshdlr != NULL);
4752
4753 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4754 return SCIP_OKAY;
4755
4758
4759 for( c = 0; c < nconss; ++c )
4760 {
4761 consdata = SCIPconsGetData(conss[c]);
4762 assert(consdata != NULL);
4763
4764 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4765 * i.e., skip children of sum that are variables
4766 */
4767 if( SCIPisExprSum(scip, consdata->expr) )
4768 {
4769 int i;
4770 SCIP_EXPR* child;
4771 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4772 {
4773 child = SCIPexprGetChildren(consdata->expr)[i];
4774
4775 /* skip variable expression, as they correspond to a linear term */
4776 if( SCIPisExprVar(scip, child) )
4777 continue;
4778
4779 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4780 if( SCIPisExprVar(scip, expr) )
4781 {
4783 }
4784 }
4785 }
4786 else
4787 {
4788 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4789 if( SCIPisExprVar(scip, expr) )
4790 {
4792 }
4793 }
4794 }
4795
4796 SCIPfreeExpriter(&it);
4797
4798 return SCIP_OKAY;
4799}
4800
4801/** simplifies expressions and replaces common subexpressions for a set of constraints
4802 * @todo put the constant to the constraint sides
4803 */
4804static
4806 SCIP* scip, /**< SCIP data structure */
4807 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4808 SCIP_CONS** conss, /**< constraints */
4809 int nconss, /**< total number of constraints */
4810 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4811 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4812 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4813 int* naddconss, /**< counter to add number of added constraints, or NULL */
4814 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4815 )
4816{
4817 SCIP_CONSHDLRDATA* conshdlrdata;
4818 SCIP_CONSDATA* consdata;
4819 int* nlockspos;
4820 int* nlocksneg;
4821 SCIP_Bool havechange;
4822 int i;
4823
4824 assert(scip != NULL);
4825 assert(conshdlr != NULL);
4826 assert(conss != NULL);
4827 assert(nconss > 0);
4828 assert(infeasible != NULL);
4829
4830 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4831 assert(conshdlrdata != NULL);
4832
4833 /* update number of canonicalize calls */
4834 ++(conshdlrdata->ncanonicalizecalls);
4835
4836 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4837
4838 *infeasible = FALSE;
4839
4840 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4841 havechange = conshdlrdata->ncanonicalizecalls == 1;
4842
4843 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4844 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4845
4846 /* allocate memory for storing locks of each constraint */
4847 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4848 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4849
4850 /* unlock all constraints */
4851 for( i = 0; i < nconss; ++i )
4852 {
4853 assert(conss[i] != NULL);
4854
4855 consdata = SCIPconsGetData(conss[i]);
4856 assert(consdata != NULL);
4857
4858 /* remember locks */
4859 nlockspos[i] = consdata->nlockspos;
4860 nlocksneg[i] = consdata->nlocksneg;
4861
4862 /* remove locks */
4863 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4864 assert(consdata->nlockspos == 0);
4865 assert(consdata->nlocksneg == 0);
4866 }
4867
4868#ifndef NDEBUG
4869 /* check whether all locks of each expression have been removed */
4870 for( i = 0; i < nconss; ++i )
4871 {
4872 SCIP_EXPR* expr;
4873 SCIP_EXPRITER* it;
4874
4876
4877 consdata = SCIPconsGetData(conss[i]);
4878 assert(consdata != NULL);
4879
4881 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4882 {
4883 assert(expr != NULL);
4884 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4885 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4886 }
4887 SCIPfreeExpriter(&it);
4888 }
4889#endif
4890
4891 /* reformulate products of binary variables */
4892 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4893 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4894 {
4895 int tmpnaddconss = 0;
4896 int tmpnchgcoefs = 0;
4897
4898 /* call this function before simplification because expressions might not be simplified after reformulating
4899 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4900 */
4901 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4902
4903 /* update counters */
4904 if( naddconss != NULL )
4905 *naddconss = tmpnaddconss;
4906 if( nchgcoefs != NULL )
4907 *nchgcoefs = tmpnchgcoefs;
4908
4909 /* check whether at least one expression has changed */
4910 if( tmpnaddconss + tmpnchgcoefs > 0 )
4911 havechange = TRUE;
4912 }
4913
4914 for( i = 0; i < nconss; ++i )
4915 {
4916 consdata = SCIPconsGetData(conss[i]);
4917 assert(consdata != NULL);
4918
4919 /* call simplify for each expression */
4920 if( !consdata->issimplified && consdata->expr != NULL )
4921 {
4922 SCIP_EXPR* simplified;
4923 SCIP_Bool changed;
4924
4925 changed = FALSE;
4926 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4927 consdata->issimplified = TRUE;
4928
4929 if( changed )
4930 havechange = TRUE;
4931
4932 /* 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").
4933 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4934 */
4935 if( simplified != consdata->expr )
4936 {
4937 assert(changed);
4938
4939 /* release old expression */
4940 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4941
4942 /* store simplified expression */
4943 consdata->expr = simplified;
4944 }
4945 else
4946 {
4947 /* The simplify captures simplified in any case, also if nothing has changed.
4948 * Therefore, we have to release it here.
4949 */
4950 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4951 }
4952
4953 if( *infeasible )
4954 break;
4955
4956 /* scale constraint sides */
4957 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4958
4959 if( changed )
4960 havechange = TRUE;
4961
4962 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4963 if( SCIPisExprValue(scip, consdata->expr) )
4964 {
4965 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4966 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4967 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4968 {
4969 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4970 SCIPdebugPrintCons(scip, conss[i], NULL);
4971 *infeasible = TRUE;
4972 break;
4973 }
4974 else
4975 {
4976 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
4977 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
4978 if( ndelconss != NULL )
4979 ++*ndelconss;
4980 havechange = TRUE;
4981 }
4982 }
4983 }
4984 }
4985
4986 /* replace common subexpressions */
4987 if( havechange && !*infeasible )
4988 {
4989 SCIP_CONS** consssorted;
4990 SCIP_EXPR** rootexprs;
4991 SCIP_Bool replacedroot;
4992
4993 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
4994 for( i = 0; i < nconss; ++i )
4995 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
4996
4997 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
4998
4999 /* update pointer to root expr in constraints, if any has changed
5000 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5001 */
5002 if( replacedroot )
5003 for( i = 0; i < nconss; ++i )
5004 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5005
5006 SCIPfreeBufferArray(scip, &rootexprs);
5007
5008 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5009 * been changed after simplification; now we completely recollect all variable expression and variable events
5010 */
5011
5012 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5013 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5014 */
5015 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5016 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5017
5018 for( i = nconss-1; i >= 0; --i )
5019 {
5020 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5021 if( SCIPconsIsDeleted(consssorted[i]) )
5022 continue;
5023
5024 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5025 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5026 }
5027 for( i = 0; i < nconss; ++i )
5028 {
5029 if( SCIPconsIsDeleted(consssorted[i]) )
5030 continue;
5031
5032 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5033 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5034 }
5035
5036 SCIPfreeBufferArray(scip, &consssorted);
5037
5038 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5039 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5040 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5041 */
5042 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5043 }
5044
5045 /* restore locks */
5046 for( i = 0; i < nconss; ++i )
5047 {
5048 if( SCIPconsIsDeleted(conss[i]) )
5049 continue;
5050
5051 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5052 }
5053
5054 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5055 * TODO can we skip this in presoltiming fast?
5056 */
5057 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5058 {
5059 /* reset one of the number of detections counter to count only current presolving round */
5060 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5061 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5062
5063 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5064 }
5065
5066 /* free allocated memory */
5067 SCIPfreeBufferArray(scip, &nlocksneg);
5068 SCIPfreeBufferArray(scip, &nlockspos);
5069
5070 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5071
5072 return SCIP_OKAY;
5073}
5074
5075/** merges constraints that have the same root expression */
5076static
5078 SCIP* scip, /**< SCIP data structure */
5079 SCIP_CONS** conss, /**< constraints to process */
5080 int nconss, /**< number of constraints */
5081 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5082 )
5083{
5084 SCIP_HASHMAP* expr2cons;
5085 SCIP_Bool* updatelocks;
5086 int* nlockspos;
5087 int* nlocksneg;
5088 int c;
5089
5090 assert(success != NULL);
5091
5092 *success = FALSE;
5093
5094 /* not enough constraints available */
5095 if( nconss <= 1 )
5096 return SCIP_OKAY;
5097
5098 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5099 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5100 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5101 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5102
5103 for( c = 0; c < nconss; ++c )
5104 {
5105 SCIP_CONSDATA* consdata;
5106
5107 /* ignore deleted constraints */
5108 if( SCIPconsIsDeleted(conss[c]) )
5109 continue;
5110
5111 consdata = SCIPconsGetData(conss[c]);
5112 assert(consdata != NULL);
5113
5114 /* add expression to the hash map if not seen so far */
5115 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5116 {
5117 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5118 }
5119 else
5120 {
5121 SCIP_CONSDATA* imgconsdata;
5122 int idx;
5123
5124 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5125 assert(idx >= 0 && idx < nconss);
5126
5127 imgconsdata = SCIPconsGetData(conss[idx]);
5128 assert(imgconsdata != NULL);
5129 assert(imgconsdata->expr == consdata->expr);
5130
5131 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5132 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5133
5134 /* check whether locks need to be updated */
5135 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5136 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5137 {
5138 nlockspos[idx] = imgconsdata->nlockspos;
5139 nlocksneg[idx] = imgconsdata->nlocksneg;
5140 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5141 updatelocks[idx] = TRUE;
5142 }
5143
5144 /* update constraint sides */
5145 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5146 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5147
5148 /* delete constraint */
5149 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5150 *success = TRUE;
5151 }
5152 }
5153
5154 /* restore locks of updated constraints */
5155 if( *success )
5156 {
5157 for( c = 0; c < nconss; ++c )
5158 {
5159 if( updatelocks[c] )
5160 {
5161 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5162 }
5163 }
5164 }
5165
5166 /* free memory */
5167 SCIPfreeBufferArray(scip, &nlocksneg);
5168 SCIPfreeBufferArray(scip, &nlockspos);
5169 SCIPfreeBufferArray(scip, &updatelocks);
5170 SCIPhashmapFree(&expr2cons);
5171
5172 return SCIP_OKAY;
5173}
5174
5175/** interval evaluation of variables as used in redundancy check
5176 *
5177 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5178 */
5179static
5180SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5181{ /*lint --e{715}*/
5182 SCIP_CONSHDLRDATA* conshdlrdata;
5183 SCIP_INTERVAL interval;
5184 SCIP_Real lb;
5185 SCIP_Real ub;
5186
5187 assert(scip != NULL);
5188 assert(var != NULL);
5189
5190 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5191 assert(conshdlrdata != NULL);
5192
5193 if( conshdlrdata->globalbounds )
5194 {
5195 lb = SCIPvarGetLbGlobal(var);
5196 ub = SCIPvarGetUbGlobal(var);
5197 }
5198 else
5199 {
5200 lb = SCIPvarGetLbLocal(var);
5201 ub = SCIPvarGetUbLocal(var);
5202 }
5203 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5204
5205 /* relax variable bounds, if there are bounds and variable is not fixed
5206 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5207 */
5208 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5209 {
5210 if( !SCIPisInfinity(scip, -lb) )
5211 lb -= SCIPfeastol(scip);
5212
5213 if( !SCIPisInfinity(scip, ub) )
5214 ub += SCIPfeastol(scip);
5215 }
5216
5217 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5220 assert(lb <= ub);
5221
5222 SCIPintervalSetBounds(&interval, lb, ub);
5223
5224 return interval;
5225}
5226
5227/** removes constraints that are always feasible or very simple
5228 *
5229 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5230 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5231 * might violate variable bounds by up to feastol, too.
5232 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5233 *
5234 * Also removes constraints of the form lhs &le; variable &le; rhs.
5235 *
5236 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5237 *
5238 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5239 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5240 * would appear as if the constraint is redundant.
5241 */
5242static
5244 SCIP* scip, /**< SCIP data structure */
5245 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5246 SCIP_CONS** conss, /**< constraints to propagate */
5247 int nconss, /**< total number of constraints */
5248 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5249 int* ndelconss, /**< buffer to add the number of deleted constraints */
5250 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5251 )
5252{
5253 SCIP_CONSHDLRDATA* conshdlrdata;
5254 SCIP_CONSDATA* consdata;
5255 SCIP_INTERVAL activity;
5256 SCIP_INTERVAL sides;
5257 int i;
5258
5259 assert(scip != NULL);
5260 assert(conshdlr != NULL);
5261 assert(conss != NULL);
5262 assert(nconss >= 0);
5263 assert(cutoff != NULL);
5264 assert(ndelconss != NULL);
5265 assert(nchgbds != NULL);
5266
5267 /* no constraints to check */
5268 if( nconss == 0 )
5269 return SCIP_OKAY;
5270
5271 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5272 assert(conshdlrdata != NULL);
5273
5274 /* increase curboundstag and set lastvaractivitymethodchange
5275 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5276 * for the redundancy check differently than for domain propagation
5277 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5278 */
5279 ++conshdlrdata->curboundstag;
5280 assert(conshdlrdata->curboundstag > 0);
5281 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5282 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5283 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5284
5285 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5286
5287 *cutoff = FALSE;
5288 for( i = 0; i < nconss; ++i )
5289 {
5290 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5291 continue;
5292
5293 consdata = SCIPconsGetData(conss[i]);
5294 assert(consdata != NULL);
5295
5296 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5297 if( SCIPisExprValue(scip, consdata->expr) )
5298 {
5299 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5300
5301 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5302 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5303 {
5304 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5305 *cutoff = TRUE;
5306
5307 goto TERMINATE;
5308 }
5309
5310 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5311
5312 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5313 ++*ndelconss;
5314
5315 continue;
5316 }
5317
5318 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5319 if( SCIPisExprVar(scip, consdata->expr) )
5320 {
5321 SCIP_VAR* var;
5322 SCIP_Bool tightened;
5323
5324 var = SCIPgetVarExprVar(consdata->expr);
5325 assert(var != NULL);
5326
5327 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);
5328
5329 /* ensure that variable bounds are within constraint sides */
5330 if( !SCIPisInfinity(scip, -consdata->lhs) )
5331 {
5332 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5333
5334 if( tightened )
5335 ++*nchgbds;
5336
5337 if( *cutoff )
5338 goto TERMINATE;
5339 }
5340
5341 if( !SCIPisInfinity(scip, consdata->rhs) )
5342 {
5343 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5344
5345 if( tightened )
5346 ++*nchgbds;
5347
5348 if( *cutoff )
5349 goto TERMINATE;
5350 }
5351
5352 /* delete the (now) redundant constraint locally */
5353 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5354 ++*ndelconss;
5355
5356 continue;
5357 }
5358
5359 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5360 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5361 * variable bounds by up to feastol
5362 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5363 */
5364 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5365 SCIPdebugPrintCons(scip, conss[i], NULL);
5366
5367 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5368 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5369
5370 /* it is unlikely that we detect infeasibility by doing forward propagation */
5371 if( *cutoff )
5372 {
5373 SCIPdebugMsg(scip, " -> cutoff\n");
5374 goto TERMINATE;
5375 }
5376
5377 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5378 activity = SCIPexprGetActivity(consdata->expr);
5379
5380 /* relax sides by feastol
5381 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5382 */
5383 SCIPintervalSetBounds(&sides,
5384 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5385 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5386
5387 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5388 {
5389 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5390
5391 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5392 ++*ndelconss;
5393
5394 continue;
5395 }
5396
5397 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5398 }
5399
5400TERMINATE:
5401 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5402 ++conshdlrdata->curboundstag;
5403 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5404 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5405 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5406
5407 return SCIP_OKAY;
5408}
5409
5410/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5411static
5413 SCIP* scip, /**< SCIP data structure */
5414 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5415 SCIP_CONS* cons, /**< source constraint to try to convert */
5416 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5417 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5418 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5419 )
5420{
5421 SCIP_CONSHDLRDATA* conshdlrdata;
5422 SCIP_CONSDATA* consdata;
5423 SCIP_CONS** upgdconss;
5424 int upgdconsssize;
5425 int nupgdconss_;
5426 int i;
5427
5428 assert(scip != NULL);
5429 assert(conshdlr != NULL);
5430 assert(cons != NULL);
5431 assert(!SCIPconsIsModifiable(cons));
5432 assert(upgraded != NULL);
5433 assert(nupgdconss != NULL);
5434 assert(naddconss != NULL);
5435
5436 *upgraded = FALSE;
5437
5438 nupgdconss_ = 0;
5439
5440 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5441 assert(conshdlrdata != NULL);
5442
5443 /* if there are no upgrade methods, we can stop */
5444 if( conshdlrdata->nconsupgrades == 0 )
5445 return SCIP_OKAY;
5446
5447 upgdconsssize = 2;
5448 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5449
5450 /* call the upgrading methods */
5451 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5453
5454 consdata = SCIPconsGetData(cons);
5455 assert(consdata != NULL);
5456
5457 /* try all upgrading methods in priority order in case the upgrading step is enable */
5458 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5459 {
5460 if( !conshdlrdata->consupgrades[i]->active )
5461 continue;
5462
5463 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5464
5465 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5466
5467 while( nupgdconss_ < 0 )
5468 {
5469 /* upgrade function requires more memory: resize upgdconss and call again */
5470 assert(-nupgdconss_ > upgdconsssize);
5471 upgdconsssize = -nupgdconss_;
5472 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5473
5474 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5475
5476 assert(nupgdconss_ != 0);
5477 }
5478
5479 if( nupgdconss_ > 0 )
5480 {
5481 /* got upgrade */
5482 int j;
5483
5484 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5485
5486 /* add the upgraded constraints to the problem and forget them */
5487 for( j = 0; j < nupgdconss_; ++j )
5488 {
5489 SCIPdebugMsgPrint(scip, "\t");
5490 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5491
5492 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5493 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5494 }
5495
5496 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5497 *nupgdconss += 1;
5498 *naddconss += nupgdconss_ - 1;
5499 *upgraded = TRUE;
5500
5501 /* delete upgraded constraint */
5502 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5503 SCIP_CALL( SCIPdelCons(scip, cons) );
5504
5505 break;
5506 }
5507 }
5508
5509 SCIPfreeBufferArray(scip, &upgdconss);
5510
5511 return SCIP_OKAY;
5512}
5513
5514/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5515 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5516 * variable bounds, and is not binary
5517 */
5518static
5520 SCIP* scip, /**< SCIP data structure */
5521 SCIP_EXPR* expr /**< variable expression */
5522 )
5523{
5524 SCIP_VAR* var;
5525 SCIP_EXPR_OWNERDATA* ownerdata;
5526
5527 assert(SCIPisExprVar(scip, expr));
5528
5529 var = SCIPgetVarExprVar(expr);
5530 assert(var != NULL);
5531
5532 ownerdata = SCIPexprGetOwnerData(expr);
5533 assert(ownerdata != NULL);
5534
5535 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5536 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5537 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5541}
5542
5543/** removes all variable expressions that are contained in a given expression from a hash map */
5544static
5546 SCIP* scip, /**< SCIP data structure */
5547 SCIP_EXPR* expr, /**< expression */
5548 SCIP_EXPRITER* it, /**< expression iterator */
5549 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5550 )
5551{
5552 SCIP_EXPR* e;
5553
5554 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5555 {
5556 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5557 {
5558 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5559 }
5560 }
5561
5562 return SCIP_OKAY;
5563}
5564
5565/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5566 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5567 *
5568 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5569 * Otherwise, a bound disjunction constraint is added.
5570 *
5571 * @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
5572 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5573 * 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
5574 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5575 */
5576static
5578 SCIP* scip, /**< SCIP data structure */
5579 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5580 SCIP_CONS* cons, /**< nonlinear constraint */
5581 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5582 int* naddconss, /**< pointer to store the total number of added constraints */
5583 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5584 )
5585{
5586 SCIP_CONSHDLRDATA* conshdlrdata;
5587 SCIP_CONSDATA* consdata;
5588 SCIP_EXPR** singlelocked;
5589 SCIP_HASHMAP* exprcands;
5590 SCIP_Bool hasbounddisj;
5591 SCIP_Bool haslhs;
5592 SCIP_Bool hasrhs;
5593 int nsinglelocked = 0;
5594 int i;
5595
5596 assert(conshdlr != NULL);
5597 assert(cons != NULL);
5598 assert(nchgvartypes != NULL);
5599 assert(naddconss != NULL);
5600 assert(infeasible != NULL);
5601
5602 *nchgvartypes = 0;
5603 *naddconss = 0;
5604 *infeasible = FALSE;
5605
5606 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5607 assert(conshdlrdata != NULL);
5608 consdata = SCIPconsGetData(cons);
5609 assert(consdata != NULL);
5610
5611 /* only consider constraints with one finite side */
5612 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5613 return SCIP_OKAY;
5614
5615 /* only consider sum expressions */
5616 if( !SCIPisExprSum(scip, consdata->expr) )
5617 return SCIP_OKAY;
5618
5619 /* remember which side is finite */
5620 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5621 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5622
5623 /* allocate memory */
5624 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5625 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5626
5627 /* check all variable expressions for single locked variables */
5628 for( i = 0; i < consdata->nvarexprs; ++i )
5629 {
5630 assert(consdata->varexprs[i] != NULL);
5631
5632 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5633 {
5634 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5635 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5636 }
5637 }
5638 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5639
5640 if( nsinglelocked > 0 )
5641 {
5642 SCIP_EXPR** children;
5643 SCIP_EXPRITER* it;
5644 int nchildren;
5645
5646 children = SCIPexprGetChildren(consdata->expr);
5647 nchildren = SCIPexprGetNChildren(consdata->expr);
5648
5649 /* create iterator */
5653
5654 for( i = 0; i < nchildren; ++i )
5655 {
5656 SCIP_EXPR* child;
5657 SCIP_Real coef;
5658
5659 child = children[i];
5660 assert(child != NULL);
5661 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5662
5663 /* ignore linear terms */
5664 if( SCIPisExprVar(scip, child) )
5665 continue;
5666
5667 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5668 * expression that represents f_j and remove each variable expression from exprcands
5669 */
5670 else if( SCIPisExprProduct(scip, child) )
5671 {
5672 int j;
5673
5674 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5675 {
5676 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5677
5678 if( !SCIPisExprVar(scip, grandchild) )
5679 {
5680 /* mark all variable expressions that are contained in the expression */
5681 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5682 }
5683 }
5684 }
5685 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5686 * for an integer k >= 1
5687 */
5688 else if( SCIPisExprPower(scip, child) )
5689 {
5690 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5691 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5692 SCIP_Bool valid;
5693
5694 /* check for even integral exponent */
5695 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5696
5697 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5698 {
5699 /* mark all variable expressions that are contained in the expression */
5700 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5701 }
5702 }
5703 /* all other cases cannot be handled */
5704 else
5705 {
5706 /* mark all variable expressions that are contained in the expression */
5707 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5708 }
5709 }
5710
5711 /* free expression iterator */
5712 SCIPfreeExpriter(&it);
5713 }
5714
5715 /* check whether the bound disjunction constraint handler is available */
5716 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5717
5718 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5719 for( i = 0; i < nsinglelocked; ++i )
5720 {
5721 /* only consider expressions that are still contained in the exprcands map */
5722 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5723 {
5724 SCIP_CONS* newcons;
5725 SCIP_VAR* vars[2];
5726 SCIP_BOUNDTYPE boundtypes[2];
5727 SCIP_Real bounds[2];
5728 char name[SCIP_MAXSTRLEN];
5729 SCIP_VAR* var;
5730
5731 var = SCIPgetVarExprVar(singlelocked[i]);
5732 assert(var != NULL);
5733 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5735
5736 /* try to change the variable type to binary */
5737 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5738 {
5739 assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5740 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5741 ++(*nchgvartypes);
5742
5743 if( *infeasible )
5744 {
5745 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5746 break;
5747 }
5748 }
5749 /* add bound disjunction constraint if bounds of the variable are finite */
5750 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5751 {
5752 vars[0] = var;
5753 vars[1] = var;
5754 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5755 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5756 bounds[0] = SCIPvarGetUbGlobal(var);
5757 bounds[1] = SCIPvarGetLbGlobal(var);
5758
5759 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5760
5761 /* create, add, and release bound disjunction constraint */
5762 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5763 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5765 SCIP_CALL( SCIPaddCons(scip, newcons) );
5766 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5767 ++(*naddconss);
5768 }
5769 }
5770 }
5771
5772 /* free memory */
5773 SCIPfreeBufferArray(scip, &singlelocked);
5774 SCIPhashmapFree(&exprcands);
5775
5776 return SCIP_OKAY;
5777}
5778
5779/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5780static
5782 SCIP* scip, /**< SCIP data structure */
5783 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5784 SCIP_CONS** conss, /**< nonlinear constraints */
5785 int nconss, /**< total number of nonlinear constraints */
5786 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5787 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5788 )
5789{
5790 int c;
5791
5792 assert(scip != NULL);
5793 assert(conshdlr != NULL);
5794 assert(conss != NULL || nconss == 0);
5795 assert(nchgvartypes != NULL);
5796 assert(infeasible != NULL);
5797
5798 *infeasible = FALSE;
5799
5800 /* nothing can be done if there are no binary and integer variables available */
5801 if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5802 return SCIP_OKAY;
5803
5804 /* no continuous var can be made implicit-integer if there are no continuous variables */
5805 if( SCIPgetNContVars(scip) == 0 )
5806 return SCIP_OKAY;
5807
5808 for( c = 0; c < nconss; ++c )
5809 {
5810 SCIP_CONSDATA* consdata;
5811 SCIP_EXPR** children;
5812 int nchildren;
5813 SCIP_Real* coefs;
5814 SCIP_EXPR* cand = NULL;
5815 SCIP_Real candcoef = 0.0;
5816 int i;
5817
5818 assert(conss != NULL && conss[c] != NULL);
5819
5820 consdata = SCIPconsGetData(conss[c]);
5821 assert(consdata != NULL);
5822
5823 /* the constraint must be an equality constraint */
5824 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5825 continue;
5826
5827 /* the root expression needs to be a sum expression */
5828 if( !SCIPisExprSum(scip, consdata->expr) )
5829 continue;
5830
5831 children = SCIPexprGetChildren(consdata->expr);
5832 nchildren = SCIPexprGetNChildren(consdata->expr);
5833
5834 /* the sum expression must have at least two children
5835 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5836 */
5837 if( nchildren <= 1 )
5838 continue;
5839
5840 coefs = SCIPgetCoefsExprSum(consdata->expr);
5841
5842 /* find first continuous variable and get value of its coefficient */
5843 for( i = 0; i < nchildren; ++i )
5844 {
5845 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5846 continue;
5847
5848 candcoef = coefs[i];
5849 assert(candcoef != 0.0);
5850
5851 /* lhs/rhs - constant divided by candcoef must be integral
5852 * if not, break with cand == NULL, so give up
5853 */
5854 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5855 cand = children[i];
5856
5857 break;
5858 }
5859
5860 /* no suitable continuous variable found */
5861 if( cand == NULL )
5862 continue;
5863
5864 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5865 for( i = 0; i < nchildren; ++i )
5866 {
5867 if( children[i] == cand )
5868 continue;
5869
5870 /* child i must be integral */
5871 if( !SCIPexprIsIntegral(children[i]) )
5872 {
5873 cand = NULL;
5874 break;
5875 }
5876
5877 /* coefficient of child i must be integral if diving by candcoef */
5878 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5879 {
5880 cand = NULL;
5881 break;
5882 }
5883 }
5884
5885 if( cand == NULL )
5886 continue;
5887
5888 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5890
5891 /* change variable type */
5893
5894 if( *infeasible )
5895 return SCIP_OKAY;
5896
5897 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5899 }
5900
5901 return SCIP_OKAY;
5902}
5903
5904/** creates auxiliary variable for a given expression
5905 *
5906 * @note for a variable expression it does nothing
5907 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5908 */
5909static
5911 SCIP* scip, /**< SCIP data structure */
5912 SCIP_EXPR* expr /**< expression */
5913 )
5914{
5915 SCIP_EXPR_OWNERDATA* ownerdata;
5916 SCIP_CONSHDLRDATA* conshdlrdata;
5917 SCIP_VARTYPE vartype;
5918 SCIP_INTERVAL activity;
5919 char name[SCIP_MAXSTRLEN];
5920
5921 assert(scip != NULL);
5922 assert(expr != NULL);
5923
5924 ownerdata = SCIPexprGetOwnerData(expr);
5925 assert(ownerdata != NULL);
5926 assert(ownerdata->nauxvaruses > 0);
5927
5928 /* if we already have auxvar, then do nothing */
5929 if( ownerdata->auxvar != NULL )
5930 return SCIP_OKAY;
5931
5932 /* if expression is a variable-expression, then do nothing */
5933 if( SCIPisExprVar(scip, expr) )
5934 return SCIP_OKAY;
5935
5937 {
5938 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5939 return SCIP_INVALIDCALL;
5940 }
5941
5942 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5943 assert(conshdlrdata != NULL);
5944 assert(conshdlrdata->auxvarid >= 0);
5945
5946 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5947 * but it usually indicates a missing simplify
5948 * if we find situations where we need to have an auxvar for a constant, then remove this assert
5949 */
5950 assert(!SCIPisExprValue(scip, expr));
5951
5952 /* create and capture auxiliary variable */
5953 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5954 ++conshdlrdata->auxvarid;
5955
5956 /* type of auxiliary variable depends on integrality information of the expression */
5958
5959 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5960 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5961 {
5962 activity = SCIPexprGetActivity(expr);
5963 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5964 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5965 * and abort in debug mode only
5966 */
5968 {
5969 SCIPABORT();
5971 }
5972 }
5973 else
5975
5976 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
5977 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
5978 */
5979 if( SCIPgetDepth(scip) == 0 )
5980 {
5981 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
5982 }
5983 else
5984 {
5985 SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
5986 }
5987
5988 /* mark the auxiliary variable to be added for the relaxation only
5989 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
5990 * or to copy the variable to a subscip
5991 */
5992 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
5993
5994 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
5995
5996 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
5997
5998 /* add variable locks in both directions
5999 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6000 * but then we need to also update the auxvars locks when the expr locks change
6001 */
6002 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6003
6004#ifdef WITH_DEBUG_SOLUTION
6005 if( SCIPdebugIsMainscip(scip) )
6006 {
6007 /* store debug solution value of auxiliary variable
6008 * assumes that expression has been evaluated in debug solution before
6009 */
6010 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6011 }
6012#endif
6013
6014 if( SCIPgetDepth(scip) > 0 )
6015 {
6016 /* initialize local bounds to (locally valid) activity */
6017 SCIP_Bool cutoff;
6018 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6019 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6020 }
6021
6022 return SCIP_OKAY;
6023}
6024
6025/** initializes separation for constraint
6026 *
6027 * - ensures that activities are up to date in all expressions
6028 * - creates auxiliary variables where required
6029 * - calls propExprDomains() to possibly tighten auxvar bounds
6030 * - calls separation initialization callback of nlhdlrs
6031 */
6032static
6034 SCIP* scip, /**< SCIP data structure */
6035 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6036 SCIP_CONS** conss, /**< constraints */
6037 int nconss, /**< number of constraints */
6038 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6039 )
6040{
6041 SCIP_CONSDATA* consdata;
6042 SCIP_CONSHDLRDATA* conshdlrdata;
6043 SCIP_EXPRITER* it;
6044 SCIP_EXPR* expr;
6045 SCIP_RESULT result;
6046 SCIP_VAR* auxvar;
6047 int nreductions = 0;
6048 int c, e;
6049
6050 assert(scip != NULL);
6051 assert(conshdlr != NULL);
6052 assert(conss != NULL || nconss == 0);
6053 assert(nconss >= 0);
6054 assert(infeasible != NULL);
6055
6056 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6057 assert(conshdlrdata != NULL);
6058
6059 /* start with new propbounds (just to be sure, should not be needed) */
6060 ++conshdlrdata->curpropboundstag;
6061
6064
6065 /* first ensure activities are up to date and create auxvars */
6066 *infeasible = FALSE;
6067 for( c = 0; c < nconss; ++c )
6068 {
6069 assert(conss != NULL);
6070 assert(conss[c] != NULL);
6071
6072 consdata = SCIPconsGetData(conss[c]);
6073 assert(consdata != NULL);
6074 assert(consdata->expr != NULL);
6075
6076#ifdef WITH_DEBUG_SOLUTION
6077 if( SCIPdebugIsMainscip(scip) )
6078 {
6079 SCIP_SOL* debugsol;
6080
6081 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6082
6083 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6084 {
6085 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6086 * in createAuxVar()
6087 */
6088 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6089 }
6090 }
6091#endif
6092
6093 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6094 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6095
6096 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6097 {
6098 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6099 {
6100 SCIP_CALL( createAuxVar(scip, expr) );
6101 }
6102 }
6103
6104 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6105 if( auxvar != NULL )
6106 {
6107 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6108 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6109 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6110 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6111 if( *infeasible )
6112 {
6113 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6114 break;
6115 }
6116
6117 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6118 if( *infeasible )
6119 {
6120 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6121 break;
6122 }
6123 }
6124 }
6125
6126 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6127 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6128 * (e.g., log(x*y), which becomes log(w), w=x*y
6129 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6130 */
6131 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6132 if( result == SCIP_CUTOFF )
6133 *infeasible = TRUE;
6134
6135 /* now call initsepa of nlhdlrs
6136 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6137 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6138 */
6140 for( c = 0; c < nconss && !*infeasible; ++c )
6141 {
6142 assert(conss != NULL);
6143 assert(conss[c] != NULL);
6144
6145 consdata = SCIPconsGetData(conss[c]);
6146 assert(consdata != NULL);
6147 assert(consdata->expr != NULL);
6148
6149 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6150 {
6151 SCIP_EXPR_OWNERDATA* ownerdata;
6152
6153 ownerdata = SCIPexprGetOwnerData(expr);
6154 assert(ownerdata != NULL);
6155
6156 if( ownerdata->nauxvaruses == 0 )
6157 continue;
6158
6159 for( e = 0; e < ownerdata->nenfos; ++e )
6160 {
6161 SCIP_NLHDLR* nlhdlr;
6162 SCIP_Bool underestimate;
6163 SCIP_Bool overestimate;
6164 assert(ownerdata->enfos[e] != NULL);
6165
6166 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6167 * which participated in a previous initSepa() call
6168 */
6169 if( ownerdata->enfos[e]->issepainit )
6170 continue;
6171
6172 /* only call initsepa if it will actually separate */
6173 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6174 continue;
6175
6176 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6177 assert(nlhdlr != NULL);
6178
6179 /* only init sepa if there is an initsepa callback */
6180 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6181 continue;
6182
6183 /* check whether expression needs to be under- or overestimated */
6184 overestimate = ownerdata->nlocksneg > 0;
6185 underestimate = ownerdata->nlockspos > 0;
6186 assert(underestimate || overestimate);
6187
6188 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6189
6190 /* call the separation initialization callback of the nonlinear handler */
6191 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6192 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6193 ownerdata->enfos[e]->issepainit = TRUE;
6194
6195 if( *infeasible )
6196 {
6197 /* stop everything if we detected infeasibility */
6198 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6199 break;
6200 }
6201 }
6202 }
6203 }
6204
6205 SCIPfreeExpriter(&it);
6206
6207 return SCIP_OKAY;
6208}
6209
6210/** returns whether we are ok to branch on auxiliary variables
6211 *
6212 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6213 */
6214static
6216 SCIP* scip, /**< SCIP data structure */
6217 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6218 )
6219{
6220 SCIP_CONSHDLRDATA* conshdlrdata;
6221
6222 assert(conshdlr != NULL);
6223
6224 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6225 assert(conshdlrdata != NULL);
6226
6227 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6228}
6229
6230/** gets weight of variable when splitting violation score onto several variables in an expression */
6231static
6233 SCIP* scip, /**< SCIP data structure */
6234 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6235 SCIP_VAR* var, /**< variable */
6236 SCIP_SOL* sol /**< current solution */
6237 )
6238{
6239 SCIP_CONSHDLRDATA* conshdlrdata;
6240
6241 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6242 assert(conshdlrdata != NULL);
6243
6244 switch( conshdlrdata->branchviolsplit )
6245 {
6246 case 'u' : /* uniform: everyone gets the same score */
6247 return 1.0;
6248
6249 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6250 {
6251 SCIP_Real weight;
6252 weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6253 return MAX(0.05, weight);
6254 }
6255
6256 case 'd' : /* domain width */
6257 return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6258
6259 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6260 {
6261 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6262 assert(width > 0.0);
6263 if( width > 10.0 )
6264 return 10.0*log10(width);
6265 if( width < 0.1 )
6266 return 0.1/(-log10(width));
6267 return width;
6268 }
6269
6270 default :
6271 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6272 SCIPABORT();
6273 return SCIP_INVALID;
6274 }
6275}
6276
6277/** adds violation-branching score to a set of expressions, thereby distributing the score
6278 *
6279 * Each expression must either be a variable expression or have an aux-variable.
6280 *
6281 * If unbounded variables are present, each unbounded var gets an even score.
6282 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6283 */
6284static
6286 SCIP* scip, /**< SCIP data structure */
6287 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6288 int nexprs, /**< number of expressions */
6289 SCIP_Real violscore, /**< violation-branching score to add to expression */
6290 SCIP_SOL* sol, /**< current solution */
6291 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6292 )
6293{
6294 SCIP_CONSHDLR* conshdlr;
6295 SCIP_VAR* var;
6296 SCIP_Real weight;
6297 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6298 int nunbounded = 0; /* number of candidates with unbounded domain */
6299 int i;
6300
6301 assert(exprs != NULL);
6302 assert(nexprs > 0);
6303 assert(success != NULL);
6304
6305 if( nexprs == 1 )
6306 {
6307 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6308 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6310 *success = TRUE;
6311 return;
6312 }
6313
6314 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6315
6316 for( i = 0; i < nexprs; ++i )
6317 {
6318 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6319 assert(var != NULL);
6320
6322 ++nunbounded;
6323 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6324 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6325 }
6326
6327 *success = FALSE;
6328 for( i = 0; i < nexprs; ++i )
6329 {
6330 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6331 assert(var != NULL);
6332
6333 if( nunbounded > 0 )
6334 {
6336 {
6337 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6338 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6339 100.0/nunbounded, violscore,
6341 *success = TRUE;
6342 }
6343 }
6344 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6345 {
6346 assert(weightsum > 0.0);
6347
6348 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6349 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6350 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6351 100*weight / weightsum, violscore,
6353 *success = TRUE;
6354 }
6355 else
6356 {
6357 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6359 }
6360 }
6361}
6362
6363/** adds violation-branching score to children of expression for given auxiliary variables
6364 *
6365 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6366 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6367 *
6368 * @note This method may modify the given auxvars array by means of sorting.
6369 */
6370static
6372 SCIP* scip, /**< SCIP data structure */
6373 SCIP_EXPR* expr, /**< expression where to start searching */
6374 SCIP_Real violscore, /**< violation score to add to expression */
6375 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6376 int nauxvars, /**< number of auxiliary variables */
6377 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6378 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6379 )
6380{
6381 SCIP_EXPRITER* it;
6382 SCIP_VAR* auxvar;
6383 SCIP_EXPR** exprs;
6384 int nexprs;
6385 int pos;
6386
6387 assert(scip != NULL);
6388 assert(expr != NULL);
6389 assert(auxvars != NULL);
6390 assert(success != NULL);
6391
6392 /* sort variables to make lookup below faster */
6393 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6394
6397
6398 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6399 nexprs = 0;
6400
6401 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6402 {
6403 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6404 if( auxvar == NULL )
6405 continue;
6406
6407 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6408 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6409 {
6410 assert(auxvars[pos] == auxvar);
6411
6412 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6413 exprs[nexprs++] = expr;
6414
6415 if( nexprs == nauxvars )
6416 break;
6417 }
6418 }
6419
6420 SCIPfreeExpriter(&it);
6421
6422 if( nexprs > 0 )
6423 {
6424 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6425 }
6426 else
6427 *success = FALSE;
6428
6429 SCIPfreeBufferArray(scip, &exprs);
6430
6431 return SCIP_OKAY;
6432}
6433
6434/** registers all unfixed variables in violated constraints as branching candidates */
6435static
6437 SCIP* scip, /**< SCIP data structure */
6438 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6439 SCIP_CONS** conss, /**< constraints */
6440 int nconss, /**< number of constraints */
6441 int* nnotify /**< counter for number of notifications performed */
6442 )
6443{
6444 SCIP_CONSDATA* consdata;
6445 SCIP_VAR* var;
6446 int c;
6447 int i;
6448
6449 assert(conshdlr != NULL);
6450 assert(conss != NULL || nconss == 0);
6451 assert(nnotify != NULL);
6452
6453 *nnotify = 0;
6454
6455 for( c = 0; c < nconss; ++c )
6456 {
6457 assert(conss != NULL && conss[c] != NULL);
6458
6459 consdata = SCIPconsGetData(conss[c]);
6460 assert(consdata != NULL);
6461
6462 /* consider only violated constraints */
6463 if( !isConsViolated(scip, conss[c]) )
6464 continue;
6465
6466 /* register all variables that have not been fixed yet */
6467 assert(consdata->varexprs != NULL);
6468 for( i = 0; i < consdata->nvarexprs; ++i )
6469 {
6470 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6471 assert(var != NULL);
6472
6474 {
6476 ++(*nnotify);
6477 }
6478 }
6479 }
6480
6481 return SCIP_OKAY;
6482}
6483
6484/** registers all variables in violated constraints with branching scores as external branching candidates */
6485static
6487 SCIP* scip, /**< SCIP data structure */
6488 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6489 SCIP_CONS** conss, /**< constraints */
6490 int nconss, /**< number of constraints */
6491 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6492 )
6493{
6494 SCIP_CONSDATA* consdata;
6495 SCIP_EXPRITER* it = NULL;
6496 int c;
6497
6498 assert(conshdlr != NULL);
6499 assert(success != NULL);
6500
6501 *success = FALSE;
6502
6503 if( branchAuxNonlinear(scip, conshdlr) )
6504 {
6507 }
6508
6509 /* register external branching candidates */
6510 for( c = 0; c < nconss; ++c )
6511 {
6512 assert(conss != NULL && conss[c] != NULL);
6513
6514 consdata = SCIPconsGetData(conss[c]);
6515 assert(consdata != NULL);
6516 assert(consdata->varexprs != NULL);
6517
6518 /* consider only violated constraints */
6519 if( !isConsViolated(scip, conss[c]) )
6520 continue;
6521
6522 if( !branchAuxNonlinear(scip, conshdlr) )
6523 {
6524 int i;
6525
6526 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6527 * only, so we can loop over variable expressions
6528 */
6529 for( i = 0; i < consdata->nvarexprs; ++i )
6530 {
6531 SCIP_Real violscore;
6532 SCIP_Real lb;
6533 SCIP_Real ub;
6534 SCIP_VAR* var;
6535
6536 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6537
6538 /* skip variable expressions that do not have a violation score */
6539 if( violscore == 0.0 )
6540 continue;
6541
6542 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6543 assert(var != NULL);
6544
6545 lb = SCIPvarGetLbLocal(var);
6546 ub = SCIPvarGetUbLocal(var);
6547
6548 /* consider variable for branching if it has not been fixed yet */
6549 if( !SCIPisEQ(scip, lb, ub) )
6550 {
6551 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6553 *success = TRUE;
6554 }
6555 else
6556 {
6557 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6558 }
6559
6560 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6561 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6562 */
6563 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6564 }
6565 }
6566 else
6567 {
6568 SCIP_EXPR* expr;
6569 SCIP_VAR* var;
6570 SCIP_Real lb;
6571 SCIP_Real ub;
6572 SCIP_Real violscore;
6573
6574 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6575 {
6576 violscore = SCIPgetExprViolScoreNonlinear(expr);
6577 if( violscore == 0.0 )
6578 continue;
6579
6580 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6581 * variable, so this expression should either be an original variable or have an auxiliary variable
6582 */
6583 var = SCIPgetExprAuxVarNonlinear(expr);
6584 assert(var != NULL);
6585
6586 lb = SCIPvarGetLbLocal(var);
6587 ub = SCIPvarGetUbLocal(var);
6588
6589 /* consider variable for branching if it has not been fixed yet */
6590 if( !SCIPisEQ(scip, lb, ub) )
6591 {
6592 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6593
6595 *success = TRUE;
6596 }
6597 else
6598 {
6599 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6600 }
6601 }
6602 }
6603 }
6604
6605 if( it != NULL )
6606 SCIPfreeExpriter(&it);
6607
6608 return SCIP_OKAY;
6609}
6610
6611/** collect branching candidates from violated constraints
6612 *
6613 * Fills array with expressions that serve as branching candidates.
6614 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6615 * branching candidate.
6616 *
6617 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6618 * through variable-expressions only.
6619 */
6620static
6622 SCIP* scip, /**< SCIP data structure */
6623 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6624 SCIP_CONS** conss, /**< constraints to process */
6625 int nconss, /**< number of constraints */
6626 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6627 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6628 SCIP_Longint soltag, /**< tag of solution */
6629 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6630 int* ncands /**< number of candidates found */
6631 )
6632{
6633 SCIP_CONSHDLRDATA* conshdlrdata;
6634 SCIP_CONSDATA* consdata;
6635 SCIP_EXPRITER* it = NULL;
6636 int c;
6637 int attempt;
6638 SCIP_VAR* var;
6639
6640 assert(scip != NULL);
6641 assert(conshdlr != NULL);
6642 assert(cands != NULL);
6643 assert(ncands != NULL);
6644
6645 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6646 assert(conshdlrdata != NULL);
6647
6648 if( branchAuxNonlinear(scip, conshdlr) )
6649 {
6652 }
6653
6654 *ncands = 0;
6655 for( attempt = 0; attempt < 2; ++attempt )
6656 {
6657 /* collect branching candidates from violated constraints
6658 * in the first attempt, consider only constraints with large violation
6659 * in the second attempt, consider all remaining violated constraints
6660 */
6661 for( c = 0; c < nconss; ++c )
6662 {
6663 SCIP_Real consviol;
6664
6665 assert(conss != NULL && conss[c] != NULL);
6666
6667 /* consider only violated constraints */
6668 if( !isConsViolated(scip, conss[c]) )
6669 continue;
6670
6671 consdata = SCIPconsGetData(conss[c]);
6672 assert(consdata != NULL);
6673 assert(consdata->varexprs != NULL);
6674
6675 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6676
6677 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6678 continue;
6679 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6680 continue;
6681
6682 if( !branchAuxNonlinear(scip, conshdlr) )
6683 {
6684 int i;
6685
6686 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6687 * only, so we can loop over variable expressions
6688 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6689 * variable, therefore we invalidate the score of a variable after processing it.
6690 */
6691 for( i = 0; i < consdata->nvarexprs; ++i )
6692 {
6693 SCIP_Real lb;
6694 SCIP_Real ub;
6695
6696 /* skip variable expressions that do not have a valid violation score */
6697 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6698 continue;
6699
6700 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6701 assert(var != NULL);
6702
6703 lb = SCIPvarGetLbLocal(var);
6704 ub = SCIPvarGetUbLocal(var);
6705
6706 /* skip already fixed variable */
6707 if( SCIPisEQ(scip, lb, ub) )
6708 {
6709 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6710 continue;
6711 }
6712
6713 assert(*ncands + 1 < SCIPgetNVars(scip));
6714 cands[*ncands].expr = consdata->varexprs[i];
6715 cands[*ncands].var = var;
6716 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6717 ++(*ncands);
6718
6719 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6720 * several times as external branching candidate */
6721 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6722 }
6723 }
6724 else
6725 {
6726 SCIP_EXPR* expr;
6727 SCIP_Real lb;
6728 SCIP_Real ub;
6729
6730 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6731 {
6732 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6733 continue;
6734
6735 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6736 * variables, so this expression should either be an original variable or have an auxiliary variable
6737 */
6738 var = SCIPgetExprAuxVarNonlinear(expr);
6739 assert(var != NULL);
6740
6741 lb = SCIPvarGetLbLocal(var);
6742 ub = SCIPvarGetUbLocal(var);
6743
6744 /* skip already fixed variable */
6745 if( SCIPisEQ(scip, lb, ub) )
6746 {
6747 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6748 continue;
6749 }
6750
6751 assert(*ncands + 1 < SCIPgetNVars(scip));
6752 cands[*ncands].expr = expr;
6753 cands[*ncands].var = var;
6754 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6755 ++(*ncands);
6756 }
6757 }
6758 }
6759
6760 /* if we have branching candidates, then we don't need another attempt */
6761 if( *ncands > 0 )
6762 break;
6763 }
6764
6765 if( it != NULL )
6766 SCIPfreeExpriter(&it);
6767
6768 return SCIP_OKAY;
6769}
6770
6771/** computes a branching score for a variable that reflects how important branching on this variable would be for
6772 * improving the dual bound from the LP relaxation
6773 *
6774 * Assume the Lagrangian for the current LP is something of the form
6775 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6776 * where x are the original variables, z the auxiliary variables,
6777 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6778 *
6779 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6780 * If we could have used not only an estimator, but the actual function f(x), then this would
6781 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6782 * Using a lot of handwaving, we claim that
6783 * lambda_i * (f(x) - a_i'x + b_i)
6784 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6785 * If an estimator depended on local bounds, then it could be improved by branching.
6786 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6787 *
6788 * 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.
6789 * To scale, we divide by the LP objective value (if >1).
6790 *
6791 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6792 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6793 *
6794 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6795 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6796 * would also be branching candidates
6797 */
6798static
6800 SCIP* scip, /**< SCIP data structure */
6801 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6802 SCIP_VAR* var /**< variable */
6803 )
6804{
6805 SCIP_COL* col;
6806 SCIP_ROW** rows;
6807 int nrows;
6808 int r;
6809 SCIP_Real dualscore;
6810
6811 assert(scip != NULL);
6812 assert(conshdlr != NULL);
6813 assert(var != NULL);
6814
6815 /* if LP not solved, then the dual branching score is not available */
6817 return 0.0;
6818
6819 /* if var is not in the LP, then the dual branching score is not available */
6821 return 0.0;
6822
6823 col = SCIPvarGetCol(var);
6824 assert(col != NULL);
6825
6826 if( !SCIPcolIsInLP(col) )
6827 return 0.0;
6828
6829 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6830 rows = SCIPcolGetRows(col);
6831
6832 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6833
6834 /* aggregate duals from all rows from consexpr with non-zero dual
6835 * TODO: this is a quick-and-dirty implementation, and not used by default
6836 * in the long run, this should be either removed or replaced by a proper implementation
6837 */
6838 dualscore = 0.0;
6839 for( r = 0; r < nrows; ++r )
6840 {
6841 SCIP_Real estimategap;
6842 const char* estimategapstr;
6843
6844 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6845 * these would typically be local, unless they are created at the root node
6846 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6847 if( !SCIProwIsLocal(rows[r]) )
6848 continue;
6849 */
6850 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6851 continue;
6852 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6853 continue;
6854
6855 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6856 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6857 continue;
6858 estimategap = atof(estimategapstr + 13);
6859 assert(estimategap >= 0.0);
6860 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6861 estimategap = SCIPgetHugeValue(scip);
6862
6863 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6864 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6865
6866 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6867 }
6868
6869 /* divide by optimal value of LP for scaling */
6870 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6871
6872 return dualscore;
6873}
6874
6875/** computes branching scores (including weighted score) for a set of candidates
6876 *
6877 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6878 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6879 *
6880 * For each score, compute the maximum over all candidates.
6881 *
6882 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6883 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6884 * score of all candidates.
6885 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6886 *
6887 * For example:
6888 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6889 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6890 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6891 * - 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.
6892 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6893 */
6894static
6896 SCIP* scip, /**< SCIP data structure */
6897 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6898 BRANCHCAND* cands, /**< branching candidates */
6899 int ncands, /**< number of candidates */
6900 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6901 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6902 )
6903{
6904 SCIP_CONSHDLRDATA* conshdlrdata;
6905 BRANCHCAND maxscore;
6906 int c;
6907
6908 assert(scip != NULL);
6909 assert(conshdlr != NULL);
6910 assert(cands != NULL);
6911 assert(ncands > 0);
6912
6913 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6914 assert(conshdlrdata != NULL);
6915
6916 /* initialize counts to 0 */
6917 memset(&maxscore, 0, sizeof(BRANCHCAND));
6918
6919 for( c = 0; c < ncands; ++c )
6920 {
6921 if( conshdlrdata->branchviolweight > 0.0 )
6922 {
6923 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6924 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6925 }
6926
6927 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarGetType(cands[c].var) <= SCIP_VARTYPE_INTEGER )
6928 {
6929 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
6930 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
6931 */
6932 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
6933
6934 if( considerfracnl && cands[c].fractionality == 0.0 )
6935 {
6936 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
6937 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
6938 */
6939 SCIP_Real solval;
6940 SCIP_Real rounded;
6941
6942 solval = SCIPgetSolVal(scip, sol, cands[c].var);
6943 rounded = SCIPround(scip, solval);
6944
6945 cands[c].fractionality = REALABS(solval - rounded);
6946 }
6947
6948 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
6949 }
6950 else
6951 cands[c].fractionality = 0.0;
6952
6953 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
6954 {
6955 SCIP_Real domainwidth;
6956 SCIP_VAR* var;
6957
6958 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6959 assert(var != NULL);
6960
6961 /* get domain width, taking infinity at 1e20 on purpose */
6962 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6963
6964 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6965 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6966 * the idea is to penalize very large and very small domains
6967 */
6968 if( domainwidth >= 1.0 )
6969 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6970 else
6971 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6972
6973 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6974 }
6975 else
6976 cands[c].domain = 0.0;
6977
6978 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
6979 {
6980 SCIP_VAR* var;
6981
6982 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6983 assert(var != NULL);
6984
6985 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6986 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6987 }
6988 else
6989 cands[c].dual = 0.0;
6990
6991 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6992 {
6993 SCIP_VAR* var;
6994
6995 var = cands[c].var;
6996 assert(var != NULL);
6997
6998 if( cands[c].expr != NULL )
6999 {
7001 cands[c].pscost = SCIP_INVALID;
7002 else
7003 {
7004 SCIP_Real brpoint;
7005 SCIP_Real pscostdown;
7006 SCIP_Real pscostup;
7007 char strategy;
7008
7009 /* decide how to compute pseudo-cost scores
7010 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7011 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7012 */
7014 strategy = conshdlrdata->branchpscostupdatestrategy;
7015 else
7016 strategy = 'l';
7017
7018 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7019
7020 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7021 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7022 * For here, I use a simple #counts >= branchpscostreliable.
7023 * TODO use SCIPgetVarPseudocostCount() instead?
7024 */
7025 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7026 {
7027 switch( strategy )
7028 {
7029 case 's' :
7030 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7031 break;
7032 case 'd' :
7033 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7034 break;
7035 case 'l' :
7036 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7037 pscostdown = SCIP_INVALID;
7038 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7039 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7040 else
7041 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, sol, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7042 break;
7043 default :
7044 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7045 pscostdown = SCIP_INVALID;
7046 }
7047 }
7048 else
7049 pscostdown = SCIP_INVALID;
7050
7051 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7052 {
7053 switch( strategy )
7054 {
7055 case 's' :
7056 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7057 break;
7058 case 'd' :
7059 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7060 break;
7061 case 'l' :
7062 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7063 pscostup = SCIP_INVALID;
7064 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7065 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7066 else
7067 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, sol, var) );
7068 break;
7069 default :
7070 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7071 pscostup = SCIP_INVALID;
7072 }
7073 }
7074 else
7075 pscostup = SCIP_INVALID;
7076
7077 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7078 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7079 */
7080 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7081 cands[c].pscost = SCIP_INVALID;
7082 else if( pscostdown == SCIP_INVALID )
7083 cands[c].pscost = pscostup;
7084 else if( pscostup == SCIP_INVALID )
7085 cands[c].pscost = pscostdown;
7086 else
7087 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7088 }
7089 }
7090 else
7091 {
7092 SCIP_Real pscostdown;
7093 SCIP_Real pscostup;
7094 SCIP_Real solval;
7095
7096 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7097
7098 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7099 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7100 * and different between variable value and rounded up value for pscostup
7101 */
7102 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7103 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7104 else
7105 pscostdown = SCIP_INVALID;
7106
7107 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7108 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7109 else
7110 pscostup = SCIP_INVALID;
7111
7112 /* TODO see above for nonlinear variable case */
7113 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7114 cands[c].pscost = SCIP_INVALID;
7115 else if( pscostdown == SCIP_INVALID )
7116 cands[c].pscost = pscostup;
7117 else if( pscostup == SCIP_INVALID )
7118 cands[c].pscost = pscostdown;
7119 else
7120 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7121 }
7122
7123 if( cands[c].pscost != SCIP_INVALID )
7124 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7125 }
7126 else
7127 cands[c].pscost = SCIP_INVALID;
7128
7129 if( conshdlrdata->branchvartypeweight > 0.0 )
7130 {
7131 switch( SCIPvarGetType(cands[c].var) )
7132 {
7133 case SCIP_VARTYPE_BINARY :
7134 cands[c].vartype = 1.0;
7135 break;
7137 cands[c].vartype = 0.1;
7138 break;
7140 cands[c].vartype = 0.01;
7141 break;
7143 default:
7144 cands[c].vartype = 0.0;
7145 }
7146 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7147 }
7148 }
7149
7150 /* now compute a weighted score for each candidate from the single scores
7151 * the single scores are scaled to be in [0,1] for this
7152 */
7153 for( c = 0; c < ncands; ++c )
7154 {
7155 SCIP_Real weightsum;
7156
7157 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7158
7159 cands[c].weighted = 0.0;
7160 weightsum = 0.0;
7161
7162 if( maxscore.auxviol > 0.0 )
7163 {
7164 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7165 weightsum += conshdlrdata->branchviolweight;
7166
7167 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7168 }
7169
7170 if( maxscore.fractionality > 0.0 )
7171 {
7172 cands[c].fractionality += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7173 weightsum += conshdlrdata->branchfracweight;
7174
7175 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7176 }
7177
7178 if( maxscore.domain > 0.0 )
7179 {
7180 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7181 weightsum += conshdlrdata->branchdomainweight;
7182
7183 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7184 }
7185
7186 if( maxscore.dual > 0.0 )
7187 {
7188 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7189 weightsum += conshdlrdata->branchdualweight;
7190
7191 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7192 }
7193
7194 if( maxscore.pscost > 0.0 )
7195 {
7196 /* use pseudo-costs only if available */
7197 if( cands[c].pscost != SCIP_INVALID )
7198 {
7199 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7200 weightsum += conshdlrdata->branchpscostweight;
7201
7202 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7203 }
7204 else
7205 {
7206 /* do not add pscostscore, if not available, also do not add into weightsum */
7207 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7208 }
7209 }
7210
7211 if( maxscore.vartype > 0.0 )
7212 {
7213 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7214 weightsum += conshdlrdata->branchvartypeweight;
7215
7216 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7217 }
7218
7219 assert(weightsum > 0.0); /* we should have got at least one valid score */
7220 cands[c].weighted /= weightsum;
7221
7222 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7223 }
7224}
7225
7226/** compare two branching candidates by their weighted score
7227 *
7228 * if weighted score is equal, use variable index of (aux)var
7229 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7230 */
7231static
7232SCIP_DECL_SORTINDCOMP(branchcandCompare)
7233{
7234 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7235
7236 if( cands[ind1].weighted != cands[ind2].weighted )
7237 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7238
7239 if( cands[ind1].var != cands[ind2].var )
7240 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7241
7242 return cands[ind1].expr != NULL ? 1 : -1;
7243}
7244
7245/** picks a candidate from array of branching candidates */
7246static
7248 SCIP* scip, /**< SCIP data structure */
7249 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7250 BRANCHCAND* cands, /**< branching candidates */
7251 int ncands, /**< number of candidates */
7252 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7253 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
7254 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7255)
7256{
7257 SCIP_CONSHDLRDATA* conshdlrdata;
7258 int* perm;
7259 int c;
7260 int left;
7261 int right;
7262 SCIP_Real threshold;
7263
7264 assert(cands != NULL);
7265 assert(ncands >= 1);
7266 assert(selected != NULL);
7267
7268 if( ncands == 1 )
7269 {
7270 *selected = cands;
7271 return SCIP_OKAY;
7272 }
7273
7274 /* if there are more than one candidate, then compute scores and select */
7275
7276 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7277 assert(conshdlrdata != NULL);
7278
7279 /* compute additional scores on branching candidates and weighted score */
7280 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
7281
7282 /* sort candidates by weighted score */
7283 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7284 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7285
7286 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7287 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7288 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7289
7290 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7291 left = 0;
7292 right = ncands - 1;
7293 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7294 while( left < right )
7295 {
7296 int mid = (left + right) / 2;
7297 if( cands[perm[mid]].weighted >= threshold )
7298 left = mid + 1;
7299 else
7300 right = mid;
7301 }
7302 assert(left <= ncands);
7303
7304 if( left < ncands )
7305 {
7306 if( cands[perm[left]].weighted >= threshold )
7307 {
7308 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7309 ncands = left + 1;
7310 }
7311 else
7312 {
7313 assert(cands[perm[left]].weighted < threshold);
7314 ncands = left;
7315 }
7316 }
7317 assert(ncands > 0);
7318
7319 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7320 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7321 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7322
7323 if( ncands > 1 )
7324 {
7325 /* choose at random from candidates 0..ncands-1 */
7326 if( conshdlrdata->branchrandnumgen == NULL )
7327 {
7328 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7329 }
7330 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7331 *selected = &cands[perm[c]];
7332 }
7333 else
7334 *selected = &cands[perm[0]];
7335
7336 SCIPfreeBufferArray(scip, &perm);
7337
7338 return SCIP_OKAY;
7339}
7340
7341/** do spatial branching or register branching candidates */
7342static
7344 SCIP* scip, /**< SCIP data structure */
7345 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7346 SCIP_CONS** conss, /**< constraints to process */
7347 int nconss, /**< number of constraints */
7348 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7349 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7350 SCIP_Longint soltag, /**< tag of solution */
7351 SCIP_RESULT* result /**< pointer to store the result of branching */
7352 )
7353{
7354 SCIP_CONSHDLRDATA* conshdlrdata;
7355 BRANCHCAND* cands;
7356 int ncands;
7357 BRANCHCAND* selected = NULL;
7358 SCIP_NODE* downchild;
7359 SCIP_NODE* eqchild;
7360 SCIP_NODE* upchild;
7361
7362 assert(conshdlr != NULL);
7363 assert(result != NULL);
7364
7365 *result = SCIP_DIDNOTFIND;
7366
7367 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7368 assert(conshdlrdata != NULL);
7369
7370 if( conshdlrdata->branchexternal )
7371 {
7372 /* just register branching candidates as external */
7373 SCIP_Bool success;
7374
7375 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7376 if( success )
7377 *result = SCIP_INFEASIBLE;
7378
7379 return SCIP_OKAY;
7380 }
7381
7382 /* collect branching candidates and their auxviol-score */
7384 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7385
7386 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7387 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7388 */
7389 if( ncands == 0 )
7390 goto TERMINATE;
7391
7392 /* here we include fractionality of integer variables into the branching score
7393 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7394 */
7395 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
7396 assert(selected != NULL);
7397 assert(selected->expr != NULL);
7398
7399 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7400 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7401
7402 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7403 &upchild) );
7404 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7405 *result = SCIP_BRANCHED;
7406 else
7407 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7408 *result = SCIP_REDUCEDDOM;
7409
7410 TERMINATE:
7411 SCIPfreeBufferArray(scip, &cands);
7412
7413 return SCIP_OKAY;
7414}
7415
7416/** call enforcement or estimate callback of nonlinear handler
7417 *
7418 * Calls the enforcement callback, if available.
7419 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7420 *
7421 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7422 */
7423static
7425 SCIP* scip, /**< SCIP main data structure */
7426 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7427 SCIP_CONS* cons, /**< nonlinear constraint */
7428 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7429 SCIP_EXPR* expr, /**< expression */
7430 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7431 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7432 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7433 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7434 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7435 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7436 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7437 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7438 SCIP_RESULT* result /**< pointer to store the result */
7439 )
7440{
7441 assert(result != NULL);
7442
7443 /* call enforcement callback of the nlhdlr */
7444 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7445 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7446
7447 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7448 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7449 {
7450 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7451 SCIPnlhdlrGetName(nlhdlr), *result); )
7452 return SCIP_OKAY;
7453 }
7454 else
7455 {
7456 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7457 }
7458
7459 *result = SCIP_DIDNOTFIND;
7460
7461 /* now call the estimator callback of the nlhdlr */
7462 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7463 {
7464 SCIP_VAR* auxvar;
7465 SCIP_Bool sepasuccess = FALSE;
7466 SCIP_Bool branchscoresuccess = FALSE;
7467 SCIP_PTRARRAY* rowpreps;
7468 int minidx;
7469 int maxidx;
7470 int r;
7471 SCIP_ROWPREP* rowprep;
7472
7473 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7474
7475 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7476 assert(auxvar != NULL);
7477
7478 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7479 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7480
7481 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7482 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7483
7484 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7485
7486 if( !sepasuccess )
7487 {
7488 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7489 SCIPnlhdlrGetName(nlhdlr)); )
7490 }
7491
7492 for( r = minidx; r <= maxidx; ++r )
7493 {
7494 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7495
7496 assert(rowprep != NULL);
7497 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7498
7499 if( !branchcandonly )
7500 {
7501 /* complete estimator to cut */
7502 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7503
7504 /* add the cut and/or branching scores
7505 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7506 */
7507 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7508 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7509 }
7510
7511 SCIPfreeRowprep(scip, &rowprep);
7512 }
7513
7514 if( branchcandonly && branchscoresuccess )
7515 {
7516 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7517 *result = SCIP_BRANCHED;
7518 }
7519
7520 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7521 }
7522
7523 return SCIP_OKAY;
7524}
7525
7526/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7527 *
7528 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7529 */
7530static
7532 SCIP* scip, /**< SCIP data structure */
7533 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7534 SCIP_CONS* cons, /**< nonlinear constraint */
7535 SCIP_EXPR* expr, /**< expression */
7536 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7537 SCIP_Longint soltag, /**< tag of solution */
7538 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7539 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7540 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7541 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7542 )
7543{
7544 SCIP_CONSHDLRDATA* conshdlrdata;
7545 SCIP_EXPR_OWNERDATA* ownerdata;
7546 SCIP_Real origviol;
7547 SCIP_Bool underestimate;
7548 SCIP_Bool overestimate;
7549 SCIP_Real auxviol;
7550 SCIP_Bool auxunderestimate;
7551 SCIP_Bool auxoverestimate;
7552 SCIP_RESULT hdlrresult;
7553 int e;
7554
7555 assert(scip != NULL);
7556 assert(expr != NULL);
7557 assert(result != NULL);
7558
7559 ownerdata = SCIPexprGetOwnerData(expr);
7560 assert(ownerdata != NULL);
7561 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7562
7563 *result = SCIP_DIDNOTFIND;
7564
7565 /* make sure that this expression has been evaluated */
7566 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7567
7568 /* decide whether under- or overestimate is required and get amount of violation */
7569 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7570
7571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7572 assert(conshdlrdata != NULL);
7573
7574 /* no sufficient violation w.r.t. the original variables -> skip expression */
7575 if( !overestimate && !underestimate )
7576 {
7577 return SCIP_OKAY;
7578 }
7579
7580 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7581 for( e = 0; e < ownerdata->nenfos; ++e )
7582 {
7583 SCIP_NLHDLR* nlhdlr;
7584
7585 /* skip nlhdlr that do not want to participate in any separation */
7586 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7587 continue;
7588
7589 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7590 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7591 continue;
7592
7593 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7594 assert(nlhdlr != NULL);
7595
7596 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7597 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7598 ENFOLOG(
7599 SCIPinfoMessage(scip, enfologfile, " expr ");
7600 SCIPprintExpr(scip, expr, enfologfile);
7601 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7602 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7603 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7604 )
7605
7606 /* TODO if expr is root of constraint (consdata->expr == expr),
7607 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7608 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7609 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7610 * so we should enforce in these auxiliaries first
7611 * if changing this here, we must also adapt analyzeViolation()
7612 */
7613
7614 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7615 assert(auxviol >= 0.0);
7616
7617 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7618 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7619 {
7620 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7621 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7622 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7623
7624 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7625 continue;
7626 }
7627
7628 /* 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 */
7629 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7630 {
7631 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7632 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7633 underestimate, overestimate); )
7634
7635 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7636 continue;
7637 }
7638
7639 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7640 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7641 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7642
7643 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7644 * wants to be called for separation on this side, then call separation of nlhdlr
7645 */
7646 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7647 {
7648 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7649 hdlrresult = SCIP_DIDNOTFIND;
7650 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7651 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7652
7653 if( hdlrresult == SCIP_CUTOFF )
7654 {
7655 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7656 *result = SCIP_CUTOFF;
7657 ownerdata->lastenforced = conshdlrdata->enforound;
7658 break;
7659 }
7660
7661 if( hdlrresult == SCIP_SEPARATED )
7662 {
7663 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7664 *result = SCIP_SEPARATED;
7665 ownerdata->lastenforced = conshdlrdata->enforound;
7666 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7667 break;
7668 }
7669
7670 if( hdlrresult == SCIP_REDUCEDDOM )
7671 {
7672 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7673 *result = SCIP_REDUCEDDOM;
7674 ownerdata->lastenforced = conshdlrdata->enforound;
7675 /* TODO or should we always just stop here? */
7676 }
7677
7678 if( hdlrresult == SCIP_BRANCHED )
7679 {
7680 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7681 assert(inenforcement);
7682
7683 /* separation and domain reduction takes precedence over branching */
7684 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7685 if( *result == SCIP_DIDNOTFIND )
7686 *result = SCIP_BRANCHED;
7687 ownerdata->lastenforced = conshdlrdata->enforound;
7688 }
7689 }
7690
7691 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7692 * wants to be called for separation on this side, then call separation of nlhdlr
7693 */
7694 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7695 {
7696 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7697 hdlrresult = SCIP_DIDNOTFIND;
7698 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7699 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7700
7701 if( hdlrresult == SCIP_CUTOFF )
7702 {
7703 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7704 *result = SCIP_CUTOFF;
7705 ownerdata->lastenforced = conshdlrdata->enforound;
7706 break;
7707 }
7708
7709 if( hdlrresult == SCIP_SEPARATED )
7710 {
7711 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7712 *result = SCIP_SEPARATED;
7713 ownerdata->lastenforced = conshdlrdata->enforound;
7714 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7715 break;
7716 }
7717
7718 if( hdlrresult == SCIP_REDUCEDDOM )
7719 {
7720 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7721 *result = SCIP_REDUCEDDOM;
7722 ownerdata->lastenforced = conshdlrdata->enforound;
7723 /* TODO or should we always just stop here? */
7724 }
7725
7726 if( hdlrresult == SCIP_BRANCHED )
7727 {
7728 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7729 assert(inenforcement);
7730
7731 /* separation takes precedence over branching */
7732 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7733 if( *result == SCIP_DIDNOTFIND )
7734 *result = SCIP_BRANCHED;
7735 ownerdata->lastenforced = conshdlrdata->enforound;
7736 }
7737 }
7738 }
7739
7740 return SCIP_OKAY;
7741}
7742
7743/** helper function to enforce a single constraint */
7744static
7746 SCIP* scip, /**< SCIP data structure */
7747 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7748 SCIP_CONS* cons, /**< constraint to process */
7749 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7750 SCIP_Longint soltag, /**< tag of solution */
7751 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7752 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7753 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7754 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7755 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7756 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7757 )
7758{
7759 SCIP_CONSDATA* consdata;
7760 SCIP_CONSHDLRDATA* conshdlrdata;
7761 SCIP_EXPR* expr;
7762
7763 assert(conshdlr != NULL);
7764 assert(cons != NULL);
7765 assert(it != NULL);
7766 assert(result != NULL);
7767 assert(success != NULL);
7768
7769 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7770 assert(conshdlrdata != NULL);
7771
7772 consdata = SCIPconsGetData(cons);
7773 assert(consdata != NULL);
7774 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7775
7776 *success = FALSE;
7777
7778 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7779 {
7780 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7781 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7782 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7783 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7784 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7785 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7786 * confuse the stalling check for how long to do separation).
7787 */
7788 SCIP_Bool infeasible;
7789 int ntightenings;
7790
7791 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7792 if( infeasible )
7793 {
7794 *result = SCIP_CUTOFF;
7795 return SCIP_OKAY;
7796 }
7797 /* if we tightened an auxvar bound, we better communicate that */
7798 if( ntightenings > 0 )
7799 *result = SCIP_REDUCEDDOM;
7800 }
7801
7802 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7803 {
7804 SCIP_EXPR_OWNERDATA* ownerdata;
7805 SCIP_RESULT resultexpr;
7806
7807 ownerdata = SCIPexprGetOwnerData(expr);
7808 assert(ownerdata != NULL);
7809
7810 /* we can only enforce if there is an auxvar to compare with */
7811 if( ownerdata->auxvar == NULL )
7812 continue;
7813
7814 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7815 if( ownerdata->lastenforced == conshdlrdata->enforound )
7816 {
7817 ENFOLOG(
7818 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7819 SCIPprintExpr(scip, expr, enfologfile);
7820 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7821 )
7822 *success = TRUE;
7823 continue;
7824 }
7825
7826 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7827
7828 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7829 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7830 if( ownerdata->lastenforced == conshdlrdata->enforound )
7831 *success = TRUE;
7832
7833 if( resultexpr == SCIP_CUTOFF )
7834 {
7835 *result = SCIP_CUTOFF;
7836 break;
7837 }
7838
7839 if( resultexpr == SCIP_SEPARATED )
7840 *result = SCIP_SEPARATED;
7841
7842 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7843 *result = SCIP_REDUCEDDOM;
7844
7845 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7846 *result = SCIP_BRANCHED;
7847 }
7848
7849 return SCIP_OKAY;
7850}
7851
7852/** try to separate violated constraints and, if in enforcement, register branching scores
7853 *
7854 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7855 *
7856 * Sets result to
7857 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7858 * - SCIP_CUTOFF, if node can be cutoff,
7859 * - SCIP_SEPARATED, if a cut has been added,
7860 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7861 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7862 * - SCIP_INFEASIBLE, if external branching candidates were registered
7863 */
7864static
7866 SCIP* scip, /**< SCIP data structure */
7867 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7868 SCIP_CONS** conss, /**< constraints to process */
7869 int nconss, /**< number of constraints */
7870 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7871 SCIP_Longint soltag, /**< tag of solution */
7872 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7873 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7874 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7875 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7876 )
7877{
7878 SCIP_CONSHDLRDATA* conshdlrdata;
7879 SCIP_EXPRITER* it;
7880 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7881 int c;
7882
7883 assert(conshdlr != NULL);
7884 assert(conss != NULL || nconss == 0);
7885 assert(result != NULL);
7886
7887 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7888 assert(conshdlrdata != NULL);
7889
7890 /* increase tag to tell whether branching scores in expression belong to this sweep
7891 * and which expressions have already been enforced in this sweep
7892 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7893 */
7894 ++(conshdlrdata->enforound);
7895
7896 *result = SCIP_DIDNOTFIND;
7897
7900
7901 for( c = 0; c < nconss; ++c )
7902 {
7903 assert(conss != NULL && conss[c] != NULL);
7904
7905 /* skip constraints that are not enabled or deleted */
7906 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7907 continue;
7908 assert(SCIPconsIsActive(conss[c]));
7909
7910 /* skip constraints that have separation disabled if we are only in separation */
7911 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7912 continue;
7913
7914 /* skip non-violated constraints */
7915 if( !isConsViolated(scip, conss[c]) )
7916 continue;
7917
7918 ENFOLOG(
7919 {
7920 SCIP_CONSDATA* consdata;
7921 int i;
7922 consdata = SCIPconsGetData(conss[c]);
7923 assert(consdata != NULL);
7924 SCIPinfoMessage(scip, enfologfile, " constraint ");
7925 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7926 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7927 for( i = 0; i < consdata->nvarexprs; ++i )
7928 {
7929 SCIP_VAR* var;
7930 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7931 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7932 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7933 }
7934 })
7935
7936 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
7937
7938 if( *result == SCIP_CUTOFF )
7939 break;
7940
7941 if( !consenforced && inenforcement && !branchcandonly )
7942 {
7943 SCIP_Real viol;
7944
7945 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7946 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7947 {
7948 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7949 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7950
7951 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
7952
7953 if( consenforced )
7954 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7955
7956 if( *result == SCIP_CUTOFF )
7957 break;
7958 }
7959 }
7960 }
7961
7962 SCIPfreeExpriter(&it);
7963
7964 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7965
7966 if( *result == SCIP_BRANCHED && !branchcandonly )
7967 {
7968 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7969 * branching
7970 */
7971 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7972
7973 /* branching should either have branched: result == SCIP_BRANCHED,
7974 * or fixed a variable: result == SCIP_REDUCEDDOM,
7975 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7976 * or have not done anything: result == SCIP_DIDNOTFIND
7977 */
7978 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7979 }
7980
7981 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7982
7983 return SCIP_OKAY;
7984}
7985
7986/** decide whether to branch on fractional integer or nonlinear variable
7987 *
7988 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
7989 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
7990 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
7991 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
7992 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
7993 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
7994 */
7995static
7997 SCIP* scip, /**< SCIP data structure */
7998 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7999 SCIP_CONS** conss, /**< constraints to process */
8000 int nconss, /**< number of constraints */
8001 SCIP_Longint soltag, /**< tag of LP solution */
8002 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
8003 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
8004 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
8005 )
8006{
8007 SCIP_RESULT result;
8008 int nlpcands;
8009 SCIP_VAR** lpcands; /* fractional integer variables */
8010 SCIP_Real* lpcandsfrac; /* fractionalities */
8011 BRANCHCAND* cands;
8012 BRANCHCAND* selected;
8013 int ncands;
8014 int c;
8015
8016 assert(scip != NULL);
8017 assert(conshdlr != NULL);
8018 assert(conss != NULL);
8019 assert(nconss > 0);
8020 assert(branchintegral != NULL);
8021 assert(cutoff != NULL);
8022
8023 *branchintegral = FALSE;
8024 *cutoff = FALSE;
8025
8027 return SCIP_OKAY;
8028
8029 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
8030 switch( result )
8031 {
8032 case SCIP_DIDNOTFIND:
8033 /* no branching candidates found could mean that the LP solution is in a convex region */
8034 *branchintegral = TRUE;
8035 return SCIP_OKAY;
8036
8037 case SCIP_CUTOFF:
8038 /* probably cannot happen, but easy to handle */
8039 *cutoff = TRUE;
8040 return SCIP_OKAY;
8041
8042 case SCIP_SEPARATED:
8043 case SCIP_REDUCEDDOM:
8044 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8045 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8046 return SCIP_ERROR;
8047
8048 case SCIP_BRANCHED:
8049 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8050 break;
8051
8052 case SCIP_INFEASIBLE:
8053 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8054 * but this was disabled by branchcandonly = TRUE)
8055 */
8056 default:
8057 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8058 return SCIP_ERROR;
8059 } /*lint !e788*/
8060
8061 /* collect spatial branching candidates and their auxviol-score */
8063 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8064
8065 /* add fractional integer variables to branching candidates */
8066 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
8067
8068 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8069
8070 for( c = 0; c < nlpcands; ++c )
8071 {
8072 assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
8073 assert(SCIPvarGetType(lpcands[c]) <= SCIP_VARTYPE_INTEGER);
8074 cands[ncands].expr = NULL;
8075 cands[ncands].var = lpcands[c];
8076 cands[ncands].auxviol = 0.0;
8077 cands[ncands].fractionality = lpcandsfrac[c];
8078 ++ncands;
8079 }
8080
8081 /* select a variable for branching
8082 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8083 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
8084 */
8085 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
8086 assert(selected != NULL);
8087
8088 if( selected->expr == NULL )
8089 {
8090 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8091
8092 *branchintegral = TRUE;
8093 }
8094
8095 SCIPfreeBufferArray(scip, &cands);
8096
8097 return SCIP_OKAY;
8098}
8099
8100/** decide whether to consider spatial branching before integrality has been enforced
8101 *
8102 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8103 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8104 *
8105 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8106 */
8107static
8109 SCIP* scip, /**< SCIP data structure */
8110 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8111 SCIP_SOL* sol /**< solution to be enforced */
8112)
8113{
8114 SCIP_CONSHDLRDATA* conshdlrdata;
8115
8116 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8117 assert(conshdlrdata != NULL);
8118
8119 /* if LP still unbounded, then work on nonlinear constraints first */
8121 return FALSE;
8122
8123 /* no branching in cons_integral if no integer variables */
8125 return FALSE;
8126
8127 /* no branching in cons_integral if LP solution not fractional */
8128 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
8129 return FALSE;
8130
8131 /* no branching in cons_integral if relax solution not fractional */
8132 if( sol != NULL )
8133 {
8134 SCIP_Bool isfractional = FALSE;
8135 SCIP_VAR** vars;
8136 int nbinvars;
8137 int nintvars;
8138 int i;
8139
8140 vars = SCIPgetVars(scip);
8141 nbinvars = SCIPgetNBinVars(scip);
8142 nintvars = SCIPgetNIntVars(scip);
8143
8144 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
8145 {
8146 assert(vars[i] != NULL);
8147 assert(SCIPvarIsIntegral(vars[i]));
8148
8149 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[i])) )
8150 isfractional = TRUE;
8151 }
8152
8153 if( !isfractional )
8154 return FALSE;
8155 }
8156
8157 /* branchmixfractional being infinity means that integral should always go first */
8158 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8159 return TRUE;
8160
8161 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8162 if( conshdlrdata->branchmixfractional == 0.0 )
8163 return FALSE;
8164
8165 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8166 * @todo this gives the total pseudocost count divided by the number of discrete variables
8167 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8168 */
8169 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8170 return TRUE;
8171 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8172 return TRUE;
8173
8174 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8175 return FALSE;
8176}
8177
8178/** collect (and print (if debugging enfo)) information on violation in expressions
8179 *
8180 * assumes that constraint violations have been computed
8181 */
8182static
8184 SCIP* scip, /**< SCIP data structure */
8185 SCIP_CONS** conss, /**< constraints */
8186 int nconss, /**< number of constraints */
8187 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8188 SCIP_Longint soltag, /**< tag of solution */
8189 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8190 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8191 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8192 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8193 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8194 )
8195{
8196 SCIP_CONSDATA* consdata;
8197 SCIP_EXPRITER* it;
8198 SCIP_EXPR* expr;
8199 SCIP_Real v;
8200 int c;
8201
8202 assert(conss != NULL || nconss == 0);
8203 assert(maxabsconsviol != NULL);
8204 assert(maxrelconsviol != NULL);
8205 assert(maxauxviol != NULL);
8206 assert(maxvarboundviol != NULL);
8207
8210
8211 *maxabsconsviol = 0.0;
8212 *maxrelconsviol = 0.0;
8213 *minauxviol = SCIPinfinity(scip);
8214 *maxauxviol = 0.0;
8215 *maxvarboundviol = 0.0;
8216
8217 for( c = 0; c < nconss; ++c )
8218 {
8219 assert(conss != NULL && conss[c] != NULL);
8220
8221 consdata = SCIPconsGetData(conss[c]);
8222 assert(consdata != NULL);
8223
8224 /* skip constraints that are not enabled, deleted, or have separation disabled */
8225 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8226 continue;
8227 assert(SCIPconsIsActive(conss[c]));
8228
8229 v = getConsAbsViolation(conss[c]);
8230 *maxabsconsviol = MAX(*maxabsconsviol, v);
8231
8232 /* skip non-violated constraints */
8233 if( !isConsViolated(scip, conss[c]) )
8234 continue;
8235
8236 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8237 *maxrelconsviol = MAX(*maxrelconsviol, v);
8238
8239 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8240 {
8241 SCIP_EXPR_OWNERDATA* ownerdata;
8242 SCIP_Real auxvarvalue;
8243 SCIP_Real auxvarlb;
8244 SCIP_Real auxvarub;
8245 SCIP_Bool violunder;
8246 SCIP_Bool violover;
8247 SCIP_Real origviol;
8248 SCIP_Real auxviol;
8249 int e;
8250
8251 ownerdata = SCIPexprGetOwnerData(expr);
8252 assert(ownerdata != NULL);
8253
8254 if( ownerdata->auxvar == NULL )
8255 {
8256 /* check violation of variable bounds of original variable */
8257 if( SCIPisExprVar(scip, expr) )
8258 {
8259 SCIP_VAR* var;
8260 var = SCIPgetVarExprVar(expr);
8261 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8262 auxvarlb = SCIPvarGetLbLocal(var);
8263 auxvarub = SCIPvarGetUbLocal(var);
8264
8265 origviol = 0.0;
8266 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8267 origviol = auxvarlb - auxvarvalue;
8268 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8269 origviol = auxvarvalue - auxvarub;
8270 if( origviol <= 0.0 )
8271 continue;
8272
8273 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8274
8275 ENFOLOG(
8276 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8277 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8278 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8279 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8280 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8281 SCIPinfoMessage(scip, enfologfile, "\n");
8282 )
8283 }
8284
8285 continue;
8286 }
8287
8288 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8289 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8290 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8291
8292 /* check violation of variable bounds of auxiliary variable */
8293 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8294 *maxvarboundviol = auxvarlb - auxvarvalue;
8295 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8296 *maxvarboundviol = auxvarvalue - auxvarub;
8297
8298 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8299
8300 ENFOLOG(
8301 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8302 {
8303 SCIPinfoMessage(scip, enfologfile, "expr ");
8304 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8305 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8306
8307 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8308 if( origviol > 0.0 )
8309 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8310 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8311 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8312 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8313 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8314 SCIPinfoMessage(scip, enfologfile, "\n");
8315 }
8316 )
8317
8318 /* no violation w.r.t. the original variables -> skip expression */
8319 if( origviol == 0.0 )
8320 continue;
8321
8322 /* compute aux-violation for each nonlinear handlers */
8323 for( e = 0; e < ownerdata->nenfos; ++e )
8324 {
8325 SCIP_NLHDLR* nlhdlr;
8326
8327 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8328 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8329 continue;
8330
8331 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8332 assert(nlhdlr != NULL);
8333
8334 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8335 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8336
8337 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8338
8339 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8340
8341 if( auxviol > 0.0 )
8342 {
8343 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8344 *maxauxviol = MAX(*maxauxviol, auxviol);
8345 *minauxviol = MIN(*minauxviol, auxviol);
8346 }
8347 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8348 }
8349 }
8350 }
8351
8352 SCIPfreeExpriter(&it);
8353
8354 return SCIP_OKAY;
8355} /*lint !e715*/
8356
8357/** enforcement of constraints called by enfolp and enforelax */
8358static
8360 SCIP* scip, /**< SCIP data structure */
8361 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8362 SCIP_CONS** conss, /**< constraints to process */
8363 int nconss, /**< number of constraints */
8364 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8365 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8366 )
8367{
8368 SCIP_CONSHDLRDATA* conshdlrdata;
8369 SCIP_Real maxabsconsviol;
8370 SCIP_Real maxrelconsviol;
8371 SCIP_Real minauxviol;
8372 SCIP_Real maxauxviol;
8373 SCIP_Real maxvarboundviol;
8374 SCIP_Longint soltag;
8375 SCIP_Bool branchintegral;
8376 int nnotify;
8377 int c;
8378
8379 if( branchingIntegralFirst(scip, conshdlr, sol) )
8380 {
8381 /* let cons_integral handle enforcement */
8382 *result = SCIP_INFEASIBLE;
8383 return SCIP_OKAY;
8384 }
8385
8386 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8387 assert(conshdlr != NULL);
8388
8389 soltag = SCIPgetExprNewSoltag(scip);
8390
8391 *result = SCIP_FEASIBLE;
8392 for( c = 0; c < nconss; ++c )
8393 {
8394 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8395
8396 if( isConsViolated(scip, conss[c]) )
8397 *result = SCIP_INFEASIBLE;
8398 }
8399
8400 if( *result == SCIP_FEASIBLE )
8401 {
8402 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8404 return SCIP_OKAY;
8405 }
8406
8407 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8408 &minauxviol, &maxauxviol, &maxvarboundviol) );
8409
8410 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8411 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8412 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8413 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8414
8415 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8416
8417 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8418 if( sol == NULL )
8419 {
8420 SCIP_Bool cutoff;
8421
8422 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8423 if( cutoff )
8424 {
8425 *result = SCIP_CUTOFF;
8426 return SCIP_OKAY;
8427 }
8428 if( branchintegral )
8429 {
8430 /* let cons_integral handle enforcement */
8431 *result = SCIP_INFEASIBLE;
8432 return SCIP_OKAY;
8433 }
8434 }
8435
8436 /* try to propagate */
8437 if( conshdlrdata->propinenforce )
8438 {
8439 SCIP_RESULT propresult;
8440 int nchgbds = 0;
8441
8442 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8443
8444 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8445 {
8446 *result = propresult;
8447 return SCIP_OKAY;
8448 }
8449 }
8450
8451 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8452 * all violated expr/auxvar in violated constraints)
8453 */
8454 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8455 sol == NULL )
8456 {
8457 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8458 ++conshdlrdata->ntightenlp;
8459
8460 *result = SCIP_SOLVELP;
8461
8462 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8463 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8464
8465 return SCIP_OKAY;
8466 }
8467
8468 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8469 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8470 */
8471 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8472 {
8473 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8474 ++conshdlrdata->ntightenlp;
8475
8476 *result = SCIP_SOLVELP;
8477
8478 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8479
8480 return SCIP_OKAY;
8481 }
8482
8483 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8484
8485 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8486 *result == SCIP_INFEASIBLE )
8487 return SCIP_OKAY;
8488
8489 assert(*result == SCIP_DIDNOTFIND);
8490
8491 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8492 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8493
8494 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8495 {
8496 /* if there are still fractional integer variables, then let cons_integral go first */
8497 *result = SCIP_INFEASIBLE;
8498 return SCIP_OKAY;
8499 }
8500
8501 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8502 {
8503 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8504 ++conshdlrdata->ntightenlp;
8505
8506 *result = SCIP_SOLVELP;
8507
8508 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8509 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8510
8511 return SCIP_OKAY;
8512 }
8513
8514 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8515 SCIPgetLPFeastol(scip)) && sol == NULL )
8516 {
8517 /* try whether tighten the LP feasibility tolerance could help
8518 * maybe it is just some cut that hasn't been taken into account sufficiently
8519 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8520 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8521 * until the LP feastol reaches epsilon
8522 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8523 * when maxauxviol is above LP feastol)
8524 */
8525 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8526 ++conshdlrdata->ndesperatetightenlp;
8527
8528 *result = SCIP_SOLVELP;
8529
8530 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8531
8532 return SCIP_OKAY;
8533 }
8534
8535 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8536 if( !conshdlrdata->propinenforce )
8537 {
8538 SCIP_RESULT propresult;
8539 int nchgbds = 0;
8540
8541 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8542
8543 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8544 {
8545 *result = propresult;
8546 return SCIP_OKAY;
8547 }
8548 }
8549
8550 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8551 * now look if we find any unfixed variable that we could still branch on
8552 */
8553 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8554
8555 if( nnotify > 0 )
8556 {
8557 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8558 ++conshdlrdata->ndesperatebranch;
8559
8560 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8561
8562 return SCIP_OKAY;
8563 }
8564
8565 /* if everything is fixed in violated constraints, then let's cut off the node
8566 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8567 * result may not be conclusive (when constraint violations are small)
8568 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8569 * sufficiently (see st_e40)
8570 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8571 * not "desperate", but a pretty obvious thing to do
8572 */
8573 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8574 *result = SCIP_CUTOFF;
8575
8576 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8577 if( !SCIPisZero(scip, maxvarboundviol) )
8578 ++conshdlrdata->ndesperatecutoff;
8579
8580 return SCIP_OKAY;
8581}
8582
8583/** separation for all violated constraints to be used by SEPA callbacks */
8584static
8586 SCIP* scip, /**< SCIP data structure */
8587 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8588 SCIP_CONS** conss, /**< constraints to process */
8589 int nconss, /**< number of constraints */
8590 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8591 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8592 )
8593{
8594 SCIP_Longint soltag;
8595 SCIP_Bool haveviol = FALSE;
8596 int c;
8597
8598 *result = SCIP_DIDNOTFIND;
8599
8600 soltag = SCIPgetExprNewSoltag(scip);
8601
8602 /* compute violations */
8603 for( c = 0; c < nconss; ++c )
8604 {
8605 assert(conss[c] != NULL);
8606
8607 /* skip constraints that are not enabled, deleted, or have separation disabled */
8608 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8609 continue;
8610 assert(SCIPconsIsActive(conss[c]));
8611
8612 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8613
8614 if( isConsViolated(scip, conss[c]) )
8615 haveviol = TRUE;
8616 }
8617
8618 /* if none of our constraints are violated, don't attempt separation */
8619 if( !haveviol )
8620 {
8621 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8622 return SCIP_OKAY;
8623 }
8624
8625 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8626
8627 /* call separation */
8628 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8629
8630 return SCIP_OKAY;
8631}
8632
8633/** hash key retrieval function for bilinear term entries */
8634static
8635SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8636{ /*lint --e{715}*/
8637 SCIP_CONSHDLRDATA* conshdlrdata;
8638 int idx;
8639
8640 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8641 assert(conshdlrdata != NULL);
8642
8643 idx = ((int)(size_t)elem) - 1;
8644 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8645
8646 return (void*)&conshdlrdata->bilinterms[idx];
8647}
8648
8649/** returns TRUE iff the bilinear term entries are equal */
8650static
8651SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8652{ /*lint --e{715}*/
8655
8656 /* get corresponding entries */
8657 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8658 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8659 assert(entry1->x != NULL && entry1->y != NULL);
8660 assert(entry2->x != NULL && entry2->y != NULL);
8661 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8662 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8663
8664 return entry1->x == entry2->x && entry1->y == entry2->y;
8665}
8666
8667/** returns the hash value of the key */
8668static
8669SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8670{ /*lint --e{715}*/
8672
8673 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8674 assert(entry->x != NULL && entry->y != NULL);
8675 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8676
8677 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8678}
8679
8680/** compare two auxiliary expressions
8681 *
8682 * Compares auxiliary variables, followed by coefficients, and then constants.
8683 */
8684static
8686{
8689 int compvars;
8690 int i;
8691
8692 /* compare the auxiliary variables */
8693 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8694
8695 if( compvars != 0 )
8696 return compvars;
8697
8698 /* compare the coefficients and constants */
8699 for( i = 0; i < 3; ++i )
8700 {
8701 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8702 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8703 }
8704
8705 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8706}
8707
8708/* add an auxiliary expression to a bilinear term */
8709static
8711 SCIP* scip, /**< SCIP data structure */
8712 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8713 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8714 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8715 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8716 )
8717{
8718 SCIP_Bool found;
8719 int pos;
8720 int i;
8721
8722 *added = FALSE;
8723
8724 /* check if auxexpr has already been added to term */
8725 if( term->nauxexprs == 0 )
8726 {
8727 found = FALSE;
8728 pos = 0;
8729 }
8730 else
8731 {
8732 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8733 }
8734
8735 if( !found )
8736 {
8737 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8738 return SCIP_OKAY;
8739
8741 assert(term->auxexprssize >= term->nauxexprs + 1);
8742
8743 /* insert expression at the correct position */
8744 for( i = term->nauxexprs; i > pos; --i )
8745 {
8746 term->aux.exprs[i] = term->aux.exprs[i-1];
8747 }
8748 term->aux.exprs[pos] = auxexpr;
8749 ++(term->nauxexprs);
8750 *added = TRUE;
8751 }
8752 else
8753 {
8754 assert(term->aux.exprs != NULL);
8755 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8756 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8757 }
8758
8759 return SCIP_OKAY;
8760}
8761
8762/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8763static
8765 SCIP* scip, /**< SCIP data structure */
8766 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8767 SCIP_CONS** conss, /**< nonlinear constraints */
8768 int nconss /**< total number of nonlinear constraints */
8769 )
8770{
8771 SCIP_CONSHDLRDATA* conshdlrdata;
8772 SCIP_EXPRITER* it;
8773 int c;
8774
8775 assert(conss != NULL || nconss == 0);
8776
8777 if( nconss == 0 )
8778 return SCIP_OKAY;
8779
8780 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8781 assert(conshdlrdata != NULL);
8782
8783 /* check whether the bilinear terms have been stored already */
8784 if( conshdlrdata->bilinterms != NULL )
8785 return SCIP_OKAY;
8786
8787 /* create and initialize iterator */
8791
8792 /* iterate through all constraints */
8793 for( c = 0; c < nconss; ++c )
8794 {
8795 SCIP_CONSDATA* consdata;
8796 SCIP_EXPR* expr;
8797
8798 assert(conss != NULL && conss[c] != NULL);
8799 consdata = SCIPconsGetData(conss[c]);
8800 assert(consdata != NULL);
8801
8802 /* iterate through all expressions */
8803 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8804 {
8805 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8806 SCIP_VAR* x = NULL;
8807 SCIP_VAR* y = NULL;
8808
8809 /* check whether the expression is of the form f(..)^2 */
8810 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8811 {
8812 x = SCIPgetExprAuxVarNonlinear(children[0]);
8813 y = x;
8814 }
8815 /* check whether the expression is of the form f(..) * g(..) */
8816 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8817 {
8818 x = SCIPgetExprAuxVarNonlinear(children[0]);
8819 y = SCIPgetExprAuxVarNonlinear(children[1]);
8820 }
8821
8822 /* add variables to the hash table */
8823 if( x != NULL && y != NULL )
8824 {
8827 }
8828 }
8829 }
8830
8831 /* release iterator */
8832 SCIPfreeExpriter(&it);
8833
8834 return SCIP_OKAY;
8835}
8836
8837/** store x, y and the locks in a new bilinear term */
8838static
8840 SCIP* scip, /**< SCIP data structure */
8841 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8842 SCIP_VAR* x, /**< the first variable */
8843 SCIP_VAR* y, /**< the second variable */
8844 int nlockspos, /**< number of positive locks of the bilinear term */
8845 int nlocksneg, /**< number of negative locks of the bilinear term */
8846 int* idx, /**< pointer to store the position of the term in bilinterms array */
8847 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8848 )
8849{
8850 SCIP_CONSHDLRDATA* conshdlrdata;
8852
8853 assert(conshdlr != NULL);
8854 assert(x != NULL);
8855 assert(y != NULL);
8856 assert(nlockspos >= 0);
8857 assert(nlocksneg >= 0);
8858
8859 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8860 assert(conshdlrdata != NULL);
8861
8862 /* ensure that x.index <= y.index */
8863 if( SCIPvarCompare(x, y) == 1 )
8864 {
8865 SCIPswapPointers((void**)&x, (void**)&y);
8866 }
8867 assert(SCIPvarCompare(x, y) < 1);
8868
8869 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8870
8871 /* update or create the term */
8872 if( *idx >= 0 )
8873 { /* the term has already been added */
8874 assert(conshdlrdata->bilinterms[*idx].x == x);
8875 assert(conshdlrdata->bilinterms[*idx].y == y);
8876
8877 /* get term and add locks */
8878 term = &conshdlrdata->bilinterms[*idx];
8879 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8880 term->nlockspos += nlockspos;
8881 term->nlocksneg += nlocksneg;
8882 }
8883 else
8884 { /* this is the first time we encounter this product */
8885 /* ensure size of bilinterms array */
8886 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8887
8888 *idx = conshdlrdata->nbilinterms;
8889
8890 /* get term and set values in the created bilinear term */
8891 term = &conshdlrdata->bilinterms[*idx];
8892 assert(term != NULL);
8893 term->x = x;
8894 term->y = y;
8895 term->nauxexprs = 0;
8896 term->auxexprssize = 0;
8897 term->nlockspos = nlockspos;
8898 term->nlocksneg = nlocksneg;
8899 term->existing = existing;
8900 if( existing )
8901 term->aux.var = NULL;
8902 else
8903 term->aux.exprs = NULL;
8904
8905 /* increase the total number of bilinear terms */
8906 ++(conshdlrdata->nbilinterms);
8907
8908 /* save to the hashtable */
8909 if( conshdlrdata->bilinhashtable == NULL )
8910 {
8911 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8912 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8913 (void*)conshdlrdata) );
8914 }
8915 assert(conshdlrdata->bilinhashtable != NULL);
8916
8917 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8918 * because zero can not be inserted into hash table
8919 */
8920 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8921
8922 /* capture product variables */
8925 }
8926
8927 return SCIP_OKAY;
8928}
8929
8930/** frees array of bilinear terms and hash table */
8931static
8933 SCIP* scip, /**< SCIP data structure */
8934 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8935 )
8936{
8937 int i;
8938 int j;
8939
8940 assert(conshdlrdata != NULL);
8941
8942 /* check whether bilinear terms have been stored */
8943 if( conshdlrdata->bilinterms == NULL )
8944 {
8945 assert(conshdlrdata->bilinterms == NULL);
8946 assert(conshdlrdata->nbilinterms == 0);
8947 assert(conshdlrdata->bilintermssize == 0);
8948
8949 return SCIP_OKAY;
8950 }
8951
8952 /* release variables */
8953 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8954 {
8955 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8956 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8957
8958 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8959 {
8960 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8961 {
8962 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8963 }
8964 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8965 }
8966
8967 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8968 {
8969 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8970 continue;
8971 }
8972
8973 /* the rest is for simple terms with a single auxvar */
8974
8975 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8976 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8977 {
8978 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8979 }
8980 }
8981
8982 /* free hash table */
8983 if( conshdlrdata->bilinhashtable != NULL )
8984 {
8985 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8986 }
8987
8988 /* free bilinterms array; reset counters */
8989 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8990 conshdlrdata->nbilinterms = 0;
8991 conshdlrdata->bilintermssize = 0;
8992
8993 return SCIP_OKAY;
8994}
8995
8996/*
8997 * vertex polyhedral separation
8998 */
8999
9000/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
9001static
9003 SCIP* scip, /**< SCIP data structure */
9004 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
9005 SCIP_LPI** lp /**< pointer to store created LP */
9006 )
9007{
9008 SCIP_Real* obj;
9009 SCIP_Real* lb;
9010 SCIP_Real* ub;
9011 SCIP_Real* val;
9012 int* beg;
9013 int* ind;
9014 unsigned int nnonz;
9015 unsigned int ncols;
9016 unsigned int nrows;
9017 unsigned int i;
9018 unsigned int k;
9019
9020 assert(scip != NULL);
9021 assert(lp != NULL);
9022 assert(nvars > 0);
9023 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9024
9025 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
9026
9027 /* create lpi to store the LP */
9029
9030 nrows = (unsigned int)nvars + 1;
9031 ncols = POWEROFTWO((unsigned int)nvars);
9032 nnonz = (ncols * (nrows + 1)) / 2;
9033
9034 /* allocate necessary memory; set obj, lb, and ub to zero */
9035 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
9037 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
9038 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
9039 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
9040 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
9041
9042 /* calculate nonzero entries in the LP */
9043 for( i = 0, k = 0; i < ncols; ++i )
9044 {
9045 int row;
9046 unsigned int a;
9047
9048 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
9049 ub[i] = SCIPlpiInfinity(*lp);
9050
9051 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
9052 beg[i] = (int)k;
9053 row = 0;
9054
9055 /* iterate through the bit representation of i */
9056 a = 1;
9057 while( a <= i )
9058 {
9059 if( (a & i) != 0 )
9060 {
9061 val[k] = 1.0;
9062 ind[k] = row;
9063
9064 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
9065
9066 ++k;
9067 }
9068
9069 a <<= 1;
9070 ++row;
9071 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
9072 assert(POWEROFTWO(row) == a);
9073 }
9074
9075 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
9076 val[k] = 1.0;
9077 ind[k] = (int)nrows - 1;
9078 ++k;
9079 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9080 }
9081 assert(k == nnonz);
9082
9083 /* load all data into LP interface
9084 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9085 */
9086 assert(nrows <= ncols);
9088 (int)ncols, obj, lb, ub, NULL,
9089 (int)nrows, lb, lb, NULL,
9090 (int)nnonz, beg, ind, val) );
9091
9092 /* for the last row, we can set the rhs to 1.0 already */
9093 ind[0] = (int)nrows - 1;
9094 val[0] = 1.0;
9095 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9096
9097 /* free allocated memory */
9104
9105 return SCIP_OKAY;
9106}
9107
9108/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9109 * \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
9110 * set of vertices of the domain
9111 */
9112static
9114 SCIP* scip, /**< SCIP data structure */
9115 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9116 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9117 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9118 int nallvars, /**< number of all variables */
9119 int nvars, /**< number of unfixed variables */
9120 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9121 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9122 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9123 )
9124{
9125 SCIP_Real maxerror;
9126 SCIP_Real facetval;
9127 SCIP_Real funval;
9128 SCIP_Real error;
9129 unsigned int i;
9130 unsigned int ncorners;
9131 unsigned int prev;
9132
9133 assert(scip != NULL);
9134 assert(funvals != NULL);
9135 assert(box != NULL);
9136 assert(nonfixedpos != NULL);
9137 assert(facetcoefs != NULL);
9138
9139 ncorners = POWEROFTWO(nvars);
9140 maxerror = 0.0;
9141
9142 /* check the origin (all variables at lower bound) */
9143 facetval = facetconstant;
9144 for( i = 0; i < (unsigned int) nallvars; ++i )
9145 facetval += facetcoefs[i] * box[2*i];
9146
9147 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9148 funval = funvals[0];
9149 if( overestimate )
9150 error = funval - facetval;
9151 else
9152 error = facetval - funval;
9153
9154 /* update maximum error */
9155 maxerror = MAX(error, maxerror);
9156
9157 prev = 0;
9158 for( i = 1; i < ncorners; ++i )
9159 {
9160 unsigned int gray;
9161 unsigned int diff;
9162 unsigned int pos;
9163 int origpos;
9164
9165 gray = i ^ (i >> 1);
9166 diff = gray ^ prev;
9167
9168 /* compute position of unique 1 of diff */
9169 pos = 0;
9170 while( (diff >>= 1) != 0 )
9171 ++pos;
9172 assert(pos < (unsigned int)nvars);
9173
9174 origpos = nonfixedpos[pos];
9175
9176 if( gray > prev )
9177 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9178 else
9179 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9180
9181 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9182 funval = funvals[gray];
9183 if( overestimate )
9184 error = funval - facetval;
9185 else
9186 error = facetval - funval;
9187
9188 /* update maximum error */
9189 maxerror = MAX(error, maxerror);
9190
9191 prev = gray;
9192 }
9193
9194 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9195
9196 return maxerror;
9197}
9198
9199/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9200static
9202 SCIP* scip, /**< SCIP data structure */
9203 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9204 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9205 SCIP_Real* xstar, /**< point to be separated */
9206 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9207 int nallvars, /**< half of the length of box */
9208 int* nonfixedpos, /**< indices of nonfixed variables */
9209 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9210 int nvars, /**< number of nonfixed variables */
9211 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9212 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9213 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9214 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9215 )
9216{ /*lint --e{715}*/
9217 SCIP_CONSHDLRDATA* conshdlrdata;
9218 SCIP_LPI* lp;
9219 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9220 int* inds;
9221 int ncols;
9222 int nrows;
9223 int i;
9224 SCIP_Real facetvalue;
9225 SCIP_Real mindomwidth;
9226 SCIP_RETCODE lpsolveretcode;
9227
9228 assert(scip != NULL);
9229 assert(conshdlr != NULL);
9230 assert(xstar != NULL);
9231 assert(box != NULL);
9232 assert(nonfixedpos != NULL);
9233 assert(funvals != NULL);
9234 assert(nvars >= 0);
9235 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9236 assert(success != NULL);
9237 assert(facetcoefs != NULL);
9238 assert(facetconstant != NULL);
9239
9240 *success = FALSE;
9241
9242 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9243 assert(conshdlrdata != NULL);
9244
9245 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9246 {
9247 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9248 }
9249
9250 /* construct an LP for this size, if not having one already */
9251 if( conshdlrdata->vp_lp[nvars] == NULL )
9252 {
9253 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9254 }
9255 lp = conshdlrdata->vp_lp[nvars];
9256 assert(lp != NULL);
9257
9258 /* get number of cols and rows of separation lp */
9259 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9260 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9261
9262 /* number of columns should equal the number of corners = 2^nvars */
9263 assert(ncols == (int)POWEROFTWO(nvars));
9264
9265 /* allocate necessary memory */
9266 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9267 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9268
9269 /*
9270 * set up the described LP on the transformed space
9271 */
9272
9273 for( i = 0; i < ncols; ++i )
9274 inds[i] = i;
9275
9276 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9277 mindomwidth = 2*SCIPinfinity(scip);
9278 for( i = 0; i < nrows-1; ++i )
9279 {
9280 SCIP_Real solval;
9281 SCIP_Real lb;
9282 SCIP_Real ub;
9283 int varpos;
9284
9285 assert(i < nvars);
9286
9287 varpos = nonfixedpos[i];
9288 lb = box[2 * varpos];
9289 ub = box[2 * varpos + 1];
9290 solval = xstar[varpos];
9291
9292 if( ub - lb < mindomwidth )
9293 mindomwidth = ub - lb;
9294
9295 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9296 if( solval <= lb )
9297 aux[i] = 0.0;
9298 else if( solval >= ub )
9299 aux[i] = 1.0;
9300 else
9301 aux[i] = (solval - lb) / (ub - lb);
9302
9303 /* perturb point to hopefully obtain a facet of the convex envelope */
9304 if( conshdlrdata->vp_maxperturb > 0.0 )
9305 {
9306 assert(conshdlrdata->vp_randnumgen != NULL);
9307
9308 if( aux[i] == 1.0 )
9309 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9310 else if( aux[i] == 0.0 )
9311 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9312 else
9313 {
9314 SCIP_Real perturbation;
9315
9316 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9317 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9318 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9319 }
9320 assert(0.0 < aux[i] && aux[i] < 1.0);
9321 }
9322
9323 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9324 }
9325
9326 /* update LP */
9327 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9328 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9330
9331 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9332 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9333 {
9334 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9335 }
9336 /* set an iteration limit so we do not run forever */
9338 /* 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 */
9340 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9341 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9342 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9343 */
9345
9346#ifdef SCIP_DEBUG
9348#endif
9349
9350 /*
9351 * solve the LP and store the resulting facet for the transformed space
9352 */
9353 if( conshdlrdata->vp_dualsimplex )
9354 {
9355 lpsolveretcode = SCIPlpiSolveDual(lp);
9356 }
9357 else
9358 {
9359 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9360 }
9361 if( lpsolveretcode == SCIP_LPERROR )
9362 {
9363 SCIPdebugMsg(scip, "LP error, aborting.\n");
9364 goto CLEANUP;
9365 }
9366 SCIP_CALL( lpsolveretcode );
9367
9368 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9369 if( !SCIPlpiIsDualFeasible(lp) )
9370 {
9371 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9372 goto CLEANUP;
9373 }
9374
9375 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9376 * columns than needed, in particular, \bar \beta is the last dual multiplier
9377 */
9378 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9379
9380 for( i = 0; i < nvars; ++i )
9381 facetcoefs[nonfixedpos[i]] = aux[i];
9382 /* last dual multiplier is the constant */
9383 *facetconstant = aux[nrows - 1];
9384
9385#ifdef SCIP_DEBUG
9386 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9387 for( i = 0; i < nallvars; ++i )
9388 {
9389 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9390 }
9391 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9392#endif
9393
9394 /*
9395 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9396 */
9397
9398 SCIPdebugMsg(scip, "facet in orig. space: ");
9399
9400 facetvalue = 0.0;
9401 for( i = 0; i < nvars; ++i )
9402 {
9403 SCIP_Real lb;
9404 SCIP_Real ub;
9405 int varpos;
9406
9407 varpos = nonfixedpos[i];
9408 lb = box[2 * varpos];
9409 ub = box[2 * varpos + 1];
9410 assert(!SCIPisEQ(scip, lb, ub));
9411
9412 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9413 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9414
9415 /* beta = beta_bar - sum_i alpha_i * lb_i */
9416 *facetconstant -= facetcoefs[varpos] * lb;
9417
9418 /* evaluate */
9419 facetvalue += facetcoefs[varpos] * xstar[varpos];
9420
9421 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9422 }
9423 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9424
9425 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9426 facetvalue += *facetconstant;
9427
9428 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9429
9430 /* if overestimate, then we want facetvalue < targetvalue
9431 * if underestimate, then we want facetvalue > targetvalue
9432 * if none holds, give up
9433 * so maybe here we should check against the minimal violation
9434 */
9435 if( overestimate == (facetvalue > targetvalue) )
9436 {
9437 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9438 goto CLEANUP;
9439 }
9440
9441 /* if we made it until here, then we have a nice facet */
9442 *success = TRUE;
9443
9444CLEANUP:
9445 /* free allocated memory */
9446 SCIPfreeBufferArray(scip, &inds);
9448
9449 return SCIP_OKAY;
9450}
9451
9452/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9453 *
9454 * In other words, compute the line that passes through two given points.
9455 */
9456static
9458 SCIP* scip, /**< SCIP data structure */
9459 SCIP_Real left, /**< left coordinate */
9460 SCIP_Real right, /**< right coordinate */
9461 SCIP_Real funleft, /**< value of function in left coordinate */
9462 SCIP_Real funright, /**< value of function in right coordinate */
9463 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9464 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9465 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9466 )
9467{
9468 assert(scip != NULL);
9469 assert(SCIPisLE(scip, left, right));
9470 assert(!SCIPisInfinity(scip, -left));
9471 assert(!SCIPisInfinity(scip, right));
9472 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9473 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9474 assert(success != NULL);
9475 assert(facetcoef != NULL);
9476 assert(facetconstant != NULL);
9477
9478 *facetcoef = (funright - funleft) / (right - left);
9479 *facetconstant = funleft - *facetcoef * left;
9480
9481 *success = TRUE;
9482
9483 return SCIP_OKAY;
9484}
9485
9486/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9487 *
9488 * Three points a, b, and c are given.
9489 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9490 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9491 */
9492static
9494 SCIP* scip, /**< SCIP data structure */
9495 SCIP_Real a1, /**< first coordinate of a */
9496 SCIP_Real a2, /**< second coordinate of a */
9497 SCIP_Real a3, /**< third coordinate of a */
9498 SCIP_Real b1, /**< first coordinate of b */
9499 SCIP_Real b2, /**< second coordinate of b */
9500 SCIP_Real b3, /**< third coordinate of b */
9501 SCIP_Real c1, /**< first coordinate of c */
9502 SCIP_Real c2, /**< second coordinate of c */
9503 SCIP_Real c3, /**< third coordinate of c */
9504 SCIP_Real* alpha, /**< coefficient of first coordinate */
9505 SCIP_Real* beta, /**< coefficient of second coordinate */
9506 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9507 SCIP_Real* delta /**< constant right-hand side */
9508 )
9509{
9510 assert(scip != NULL);
9511 assert(alpha != NULL);
9512 assert(beta != NULL);
9513 assert(gamma_ != NULL);
9514 assert(delta != NULL);
9515
9516 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9517 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9518 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9519 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9520
9521 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9522
9523 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9524 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9525 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9526 {
9527 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9528 *delta = 0.0;
9529 *alpha = 0.0;
9530 *beta = 0.0;
9531 *gamma_ = 0.0;
9532 return SCIP_OKAY;
9533 }
9534
9535 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9536 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9537 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9538 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9539 {
9540 SCIP_Real m[9];
9541 SCIP_Real rhs[3];
9542 SCIP_Real x[3];
9543 SCIP_Bool success;
9544
9545 /*
9546 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));
9547 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));
9548 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));
9549 */
9550
9551 /* initialize matrix column-wise */
9552 m[0] = a1;
9553 m[1] = b1;
9554 m[2] = c1;
9555 m[3] = a2;
9556 m[4] = b2;
9557 m[5] = c2;
9558 m[6] = a3;
9559 m[7] = b3;
9560 m[8] = c3;
9561
9562 rhs[0] = 1.0;
9563 rhs[1] = 1.0;
9564 rhs[2] = 1.0;
9565
9566 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9567
9568 /* solve the linear problem */
9569 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9570
9571 *delta = rhs[0];
9572 *alpha = x[0];
9573 *beta = x[1];
9574 *gamma_ = x[2];
9575
9576 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9577 * not add a cut to SCIP and that all assertions are trivially fulfilled
9578 */
9579 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9580 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9581 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9582 {
9583 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9584 *delta = 0.0;
9585 *alpha = 0.0;
9586 *beta = 0.0;
9587 *gamma_ = 0.0;
9588 }
9589 }
9590
9591 if( *gamma_ < 0.0 )
9592 {
9593 *alpha = -*alpha;
9594 *beta = -*beta;
9595 *gamma_ = -*gamma_;
9596 *delta = -*delta;
9597 }
9598
9599 return SCIP_OKAY;
9600}
9601
9602/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9603static
9605 SCIP* scip, /**< SCIP data structure */
9606 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9607 SCIP_Real p1[2], /**< first vertex of box */
9608 SCIP_Real p2[2], /**< second vertex of box */
9609 SCIP_Real p3[2], /**< third vertex of box */
9610 SCIP_Real p4[2], /**< forth vertex of box */
9611 SCIP_Real p1val, /**< value in p1 */
9612 SCIP_Real p2val, /**< value in p2 */
9613 SCIP_Real p3val, /**< value in p3 */
9614 SCIP_Real p4val, /**< value in p4 */
9615 SCIP_Real xstar[2], /**< point to be separated */
9616 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9617 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9618 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9619 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9620 )
9621{
9622 SCIP_Real alpha, beta, gamma_, delta;
9623 SCIP_Real xstarval, candxstarval = 0.0;
9624 int leaveout;
9625
9626 assert(scip != NULL);
9627 assert(success != NULL);
9628 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9629 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9630 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9631 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9632 assert(facetcoefs != NULL);
9633 assert(facetconstant != NULL);
9634
9635 *success = FALSE;
9636
9637 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9638 if( !overestimate )
9639 {
9640 p1val = -p1val;
9641 p2val = -p2val;
9642 p3val = -p3val;
9643 p4val = -p4val;
9644 targetvalue = -targetvalue;
9645 }
9646
9647 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9648 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9649 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9650 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9651
9652 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9653 * alpha*x + beta*y + gamma*z = delta
9654 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9655 * the fourth corner point lies below this hyperplane.
9656 * 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.,
9657 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9658 * or, equivalently,
9659 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9660 */
9661 for( leaveout = 1; leaveout <= 4; ++leaveout )
9662 {
9663 switch( leaveout)
9664 {
9665 case 1 :
9666 /* get hyperplane through p2, p3, p4 */
9667 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9668 &alpha, &beta, &gamma_, &delta) );
9669 /* if not underestimating in p1, then go to next candidate */
9670 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9671 continue;
9672 break;
9673
9674 case 2 :
9675 /* get hyperplane through p1, p3, p4 */
9676 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9677 &alpha, &beta, &gamma_, &delta) );
9678 /* if not underestimating in p2, then go to next candidate */
9679 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9680 continue;
9681 break;
9682
9683 case 3 :
9684 /* get hyperplane through p1, p2, p4 */
9685 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9686 &alpha, &beta, &gamma_, &delta) );
9687 /* if not underestimating in p3, then go to next candidate */
9688 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9689 continue;
9690 break;
9691
9692 case 4 :
9693 /* get hyperplane through p1, p2, p3 */
9694 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9695 &alpha, &beta, &gamma_, &delta) );
9696 /* if not underestimating in p4, then stop */
9697 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9698 continue;
9699 break;
9700
9701 default: /* only for lint */
9702 alpha = SCIP_INVALID;
9703 beta = SCIP_INVALID;
9704 gamma_ = SCIP_INVALID;
9705 delta = SCIP_INVALID;
9706 break;
9707 }
9708
9709 /* check if bad luck: should not happen if numerics are fine */
9710 if( SCIPisZero(scip, gamma_) )
9711 continue;
9712 assert(!SCIPisNegative(scip, gamma_));
9713
9714 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9715 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9716 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9717 continue;
9718
9719 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9720
9721 /* value of hyperplane candidate in xstar */
9722 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9723
9724 /* if reaching target and first or better than previous candidate, then update */
9725 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9726 {
9727 /* flip hyperplane */
9728 if( !overestimate )
9729 gamma_ = -gamma_;
9730
9731 facetcoefs[0] = -alpha/gamma_;
9732 facetcoefs[1] = -beta/gamma_;
9733 *facetconstant = delta/gamma_;
9734
9735 *success = TRUE;
9736 candxstarval = xstarval;
9737 }
9738 }
9739
9740 return SCIP_OKAY;
9741}
9742
9743/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9744 * graph yet) in an array
9745 */
9746static
9748 SCIP* scip, /**< SCIP pointer */
9749 int** openidx, /**< address of openidx array */
9750 int nelems, /**< number of elements that need to be stored */
9751 int* maxnelems /**< pointer to store maximum number that can be stored */
9752 )
9753{
9754 assert(scip != NULL);
9755 assert(openidx != NULL);
9756 assert(maxnelems != NULL);
9757
9758 if( nelems > *maxnelems )
9759 {
9760 int newsize;
9761
9762 newsize = SCIPcalcMemGrowSize(scip, nelems);
9763 assert(newsize >= nelems);
9764
9765 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9766
9767 *maxnelems = newsize;
9768 }
9769
9770 return SCIP_OKAY;
9771}
9772
9773/** ensures that we can store information about local variables in an array */
9774static
9776 SCIP* scip, /**< SCIP pointer */
9777 SCIP_VAR*** vars, /**< address of variable array */
9778 SCIP_Real** vals, /**< address of value array */
9779 int nelems, /**< number of elements that need to be stored */
9780 int* maxnelems /**< pointer to store maximum number that can be stored */
9781 )
9782{
9783 assert(scip != NULL);
9784 assert(vars != NULL);
9785 assert(vals != NULL);
9786 assert(maxnelems != NULL);
9787
9788 if( nelems > *maxnelems )
9789 {
9790 int newsize;
9791
9792 newsize = SCIPcalcMemGrowSize(scip, nelems);
9793 assert(newsize > *maxnelems);
9794
9795 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
9796 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9797
9798 *maxnelems = newsize;
9799 }
9800
9801 return SCIP_OKAY;
9802}
9803
9804/** tries to add gadget for finding signed permutations of bilinear products
9805 *
9806 * If a product has exactly two children being variables, negating both simultanteoulsy
9807 * is a signed permutation.
9808 */
9809static
9811 SCIP* scip, /**< SCIP pointer */
9812 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9813 SCIP_CONS* cons, /**< constraint containing product expression */
9814 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9815 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9816 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9817 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9818 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9819 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9820 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9821 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9822 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9823 )
9824{
9825 SYM_EXPRDATA* symdata;
9826 SCIP_EXPR** children;
9827 SCIP_VAR* var1 = NULL;
9828 SCIP_VAR* var2 = NULL;
9829 SCIP_Real val1 = 0.0;
9830 SCIP_Real val2 = 0.0;
9831 SCIP_Real coef;
9832 SCIP_Real prodval;
9833 SCIP_Real constant;
9834 int nlocvars;
9835 int optype;
9836 int nchildren;
9837 int prodidx;
9838 int coefidx1;
9839 int coefidx2;
9840 int childidx;
9841
9842 assert(scip != NULL);
9843 assert(expr != NULL);
9844 assert(SCIPisExprProduct(scip, expr));
9845 assert(graph != NULL);
9846 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9847 assert(consvars != NULL);
9848 assert(consvals != NULL);
9849 assert(maxnconsvars != NULL);
9850 assert(*maxnconsvars > 0);
9851 assert(handledexprs != NULL);
9852 assert(success != NULL);
9853
9854 *success = FALSE;
9855
9856 /* we require exactly two children being variables */
9857 nchildren = SCIPexprGetNChildren(expr);
9858 if( nchildren != 2 )
9859 return SCIP_OKAY;
9860
9861 children = SCIPexprGetChildren(expr);
9862 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9863 return SCIP_OKAY;
9864
9865 /* check whether each child is not multi-aggregated and is not shifted */
9866 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9867
9868 for( childidx = 0; childidx < 2; ++childidx )
9869 {
9870 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9871 (*consvals)[0] = 1.0;
9872 nlocvars = 1;
9873 constant = 0.0;
9874
9875 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9876 &constant, SCIPconsIsTransformed(cons)) );
9877
9878 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9879 return SCIP_OKAY;
9880
9881 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9882 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9883 return SCIP_OKAY;
9884
9885 /* store information about variables */
9886 if( childidx == 0 )
9887 {
9888 var1 = (*consvars)[0];
9889 val1 = (*consvals)[0];
9890 }
9891 else
9892 {
9893 var2 = (*consvars)[0];
9894 val2 = (*consvals)[0];
9895 }
9896 }
9897 assert(var1 != NULL);
9898 assert(var2 != NULL);
9899
9900 /* store the we handle the children */
9901 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9902 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9903
9904 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9905 assert(symdata != NULL);
9906 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9907
9908 coef = SCIPgetSymExprdataConstants(symdata)[0];
9909
9910 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9911
9912 /* add gadget modeling the product
9913 *
9914 * Since the constants are 0, each variable is centered at the origin, which leads to
9915 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9916 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9917 * negate both variables simulataneously.
9918 */
9920 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9921 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9922
9923 prodval = coef * val1 * val2;
9924
9925 /* introduce nodes for the product value and its negation; since flipping both variables
9926 * simultaneously is a signed symmetry, assign both nodes the same value
9927 */
9928 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
9929 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
9930
9931 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
9932 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
9933 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
9934
9935 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9936 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9937 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9938 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9939 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9940 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9941 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9942 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9943
9944 *success = TRUE;
9945
9946 return SCIP_OKAY;
9947}
9948
9949/** returns whether an operator is even and, if yes, stores data about operator */
9950static
9952 SCIP* scip, /**< SCIP pointer */
9953 SCIP_EXPR* expr, /**< expression corresponding to operator */
9954 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
9955 * needed for symmetry computation */
9956 SCIP_Real* value /**< pointer to store value for symmetry computation */
9957 )
9958{
9959 SYM_EXPRDATA* symdata;
9960
9961 assert(scip != NULL);
9962 assert(expr != NULL);
9963 assert(hasvalue != NULL);
9964 assert(value != NULL);
9965
9966 /* check for different operators known to be even */
9967 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9968 {
9969 /* get remaining information needed for symmetry detection */
9970 if( SCIPisExprSignpower(scip, expr) )
9971 {
9972 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9973 assert(symdata != NULL);
9974 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9975
9976 *value = SCIPgetSymExprdataConstants(symdata)[0];
9977 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9978
9980 }
9981 else
9982 {
9983 assert(SCIPisExprCos(scip, expr));
9984 *hasvalue = FALSE;
9985 }
9986
9987 return TRUE;
9988 }
9989 else if( SCIPisExprPower(scip, expr) )
9990 {
9991 SCIP_Real exponent;
9992 int safeexponent;
9993
9994 /* only consider expressions corresponding to an even power */
9995 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9996 assert(symdata != NULL);
9997 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9998
9999 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10001
10002 /* check whether the exponent is an even integer */
10003 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
10004 return FALSE;
10005
10006 /* deal with numerics */
10007 safeexponent = (int) (exponent + 0.5);
10008 if( safeexponent % 2 != 0 )
10009 return FALSE;
10010
10011 *hasvalue = TRUE;
10012 *value = exponent;
10013
10014 return TRUE;
10015 }
10016 else if( SCIPisExprAbs(scip, expr) )
10017 {
10018 *hasvalue = FALSE;
10019
10020 return TRUE;
10021 }
10022
10023 return FALSE;
10024}
10025
10026/** returns whether a variable is centered at 0 */
10027static
10029 SCIP* scip, /**< SCIP pointer */
10030 SCIP_VAR* var /**< variable to be checked */
10031 )
10032{
10033 assert(scip != NULL);
10034 assert(var != NULL);
10035
10037 return FALSE;
10038
10040 return TRUE;
10041
10043 return TRUE;
10044
10045 return FALSE;
10046}
10047
10048/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
10049static
10051 SCIP* scip, /**< SCIP pointer */
10052 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10053 SCIP_EXPR* child, /**< child expression of evenopexpr */
10054 SCIP_CONS* cons, /**< constraint containing expression */
10055 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10056 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10057 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10058 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10059 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10060 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10061 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10062 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10063 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10064 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10065 )
10066{
10067 SCIP_VAR* var;
10068 SCIP_Real constant;
10069 SCIP_Real edgeweight;
10070 int nlocvars;
10071 int nodeidx;
10072 int optype;
10073 int thisopidx;
10074
10075 assert(scip != NULL);
10076 assert(evenopexpr != NULL);
10077 assert(child != NULL);
10078 assert(SCIPisExprVar(scip, child));
10079 assert(cons != NULL);
10080 assert(graph != NULL);
10081 assert(parentidx >= 0);
10082 assert(consvars != NULL);
10083 assert(consvals != NULL);
10084 assert(maxnconsvars != NULL);
10085 assert(success != NULL);
10086
10087 *success = FALSE;
10088
10089 /* check whether child variable is (multi-)aggregated */
10090 var = SCIPgetVarExprVar(child);
10091 (*consvars)[0] = var;
10092 (*consvals)[0] = 1.0;
10093 constant = 0.0;
10094 nlocvars = 1;
10095
10096 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10097 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10098 SCIPconsIsTransformed(cons)) );
10099
10100 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10101 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10102 return SCIP_OKAY;
10103
10104 if( !varIsCenteredAt0(scip, var) )
10105 return SCIP_OKAY;
10106
10107 /* store partial information for gadget */
10108 var = (*consvars)[0];
10109 edgeweight = (*consvals)[0];
10110
10111 /* add gadget to graph for even univariate expression */
10112 *success = TRUE;
10113
10115
10116 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10117 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10118
10119 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10120 TRUE, edgeweight) );
10122 TRUE, edgeweight) );
10123
10124 if( hassymval )
10125 {
10126 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10127 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10128 }
10129
10130 return SCIP_OKAY;
10131}
10132
10133/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10134static
10136 SCIP* scip, /**< SCIP pointer */
10137 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10138 SCIP_EXPR* child, /**< child expression of evenopexpr */
10139 SCIP_CONS* cons, /**< constraint containing expression */
10140 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10141 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10142 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10143 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10144 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10145 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10146 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10147 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10148 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10149 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10150 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10151 )
10152{
10153 SCIP_VAR* var;
10154 SCIP_Real constant;
10155 SCIP_Real weight;
10156 int nlocvars;
10157 int nodeidx;
10158 int optype;
10159 int thisopidx;
10160 int i;
10161
10162 assert(scip != NULL);
10163 assert(evenopexpr != NULL);
10164 assert(child != NULL);
10165 assert(SCIPisExprSum(scip, child));
10166 assert(cons != NULL);
10167 assert(graph != NULL);
10168 assert(parentidx >= 0);
10169 assert(consvars != NULL);
10170 assert(consvals != NULL);
10171 assert(maxnconsvars != NULL);
10172 assert(handledexprs != NULL);
10173 assert(success != NULL);
10174
10175 *success = FALSE;
10176
10177 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10178 nlocvars = SCIPexprGetNChildren(child);
10179
10180 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10181
10182 for( i = 0; i < nlocvars; ++i)
10183 {
10184 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10185 {
10186 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10187 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10188 }
10189 else
10190 return SCIP_OKAY;
10191 }
10192 constant = SCIPgetConstantExprSum(child);
10193
10194 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10195 SCIPconsIsTransformed(cons)) );
10196
10197 /* we can only handle the case without constant and two variables with domain centered at origin */
10198 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10199 return SCIP_OKAY;
10200 assert(nlocvars > 0);
10201
10202 var = (*consvars)[0];
10203 if( !varIsCenteredAt0(scip, var) )
10204 return SCIP_OKAY;
10205
10206 if( nlocvars == 2 )
10207 {
10208 var = (*consvars)[1];
10209 if( !varIsCenteredAt0(scip, var) )
10210 return SCIP_OKAY;
10211 }
10212
10213 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10214 *success = TRUE;
10215 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10216 {
10217 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10218 }
10219
10221
10222 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10223 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10224
10225 if( hassymval )
10226 {
10227 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10228 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10229 }
10230
10231 if( nlocvars == 1 )
10232 {
10233 var = (*consvars)[0];
10234 weight = (*consvals)[0];
10235
10236 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10237 TRUE, weight) );
10239 TRUE, weight) );
10240 }
10241 else
10242 {
10243 int dummyidx1;
10244 int dummyidx2;
10245
10246 /* add dummy nodes for gadget */
10247 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10248 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10249
10250 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10251 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10252 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10253
10254 /* connect dummy nodes with variables */
10255 for( i = 0; i < 2; ++i)
10256 {
10257 var = (*consvars)[i];
10258 weight = ABS((*consvals)[i]);
10259
10260 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10261 TRUE, weight) );
10263 TRUE, weight) );
10264 }
10265 }
10266
10267 return SCIP_OKAY;
10268}
10269
10270/** tries to add gadget for finding signed permutations of even univariate operators
10271 *
10272 * We handle two cases. First, if a univariate operator is even and has a variable
10273 * as child, negating the child is signed permutation. Second, the univariate operator
10274 * is even and has a weighted sum of two variables as child.
10275 */
10276static
10278 SCIP* scip, /**< SCIP pointer */
10279 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10280 SCIP_CONS* cons, /**< constraint containing expression */
10281 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10282 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10283 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10284 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10285 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10286 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10287 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10288 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10289 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10290 )
10291{
10292 SCIP_EXPR* child;
10293 SCIP_Real val = 0.0;
10294 SCIP_Bool hasval = FALSE;
10295
10296 assert(scip != NULL);
10297 assert(expr != NULL);
10298 assert(graph != NULL);
10299 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10300 assert(consvars != NULL);
10301 assert(consvals != NULL);
10302 assert(maxnconsvars != NULL);
10303 assert(*maxnconsvars > 0);
10304 assert(handledexprs != NULL);
10305 assert(success != NULL);
10306
10307 *success = FALSE;
10308
10309 /* ignore variable or value expressions */
10310 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10311 return SCIP_OKAY;
10312 assert(SCIPexprGetNChildren(expr) > 0);
10313
10314 /* ignore operators with too many children */
10315 if( SCIPexprGetNChildren(expr) > 1 )
10316 return SCIP_OKAY;
10317
10318 /* check whether operator is even */
10319 if( !isEvenOperator(scip, expr, &hasval, &val) )
10320 return SCIP_OKAY;
10321
10322 /* we can only treat the operator if its child is a variable or a sum */
10323 child = SCIPexprGetChildren(expr)[0];
10324 if( SCIPisExprVar(scip, child) )
10325 {
10326 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10327 hasval, val, consvars, consvals, maxnconsvars, success) );
10328 }
10329 else if( SCIPisExprSum(scip, child) )
10330 {
10331 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10332 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10333 }
10334
10335 if( *success )
10336 {
10337 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10338 }
10339
10340 return SCIP_OKAY;
10341}
10342
10343/** compares two variable pointers */
10344static
10346{ /*lint --e{715}*/
10347 SCIP_VAR** vars;
10348 SCIP_VAR* var1;
10349 SCIP_VAR* var2;
10350
10351 vars = (SCIP_VAR**) dataptr;
10352
10353 var1 = vars[ind1];
10354 var2 = vars[ind2];
10355 assert(var1 != NULL);
10356 assert(var2 != NULL);
10357
10358 /* sort variables by their unique index */
10359 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10360 return -1;
10361 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10362 return 1;
10363
10364 return 0;
10365}
10366
10367/** gets domain center of a variable which has not semi-infinite domain */
10368static
10370 SCIP* scip, /**< SCIP pointer */
10371 SCIP_VAR* var /**< variable */
10372 )
10373{
10374 SCIP_Real ub;
10375 SCIP_Real lb;
10376
10377 ub = SCIPvarGetUbGlobal(var);
10378 lb = SCIPvarGetLbGlobal(var);
10379
10380 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10381
10382 if ( SCIPisInfinity(scip, ub) )
10383 return 0.0;
10384
10385 return (ub + lb) / 2;
10386}
10387
10388/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10389static
10391 SCIP* scip, /**< SCIP pointer */
10392 SCIP_EXPR* sumexpr, /**< sum expression */
10393 SCIP_CONS* cons, /**< constraint containing the sum expression */
10394 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10395 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10396 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10397 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10398 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10399 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10400 )
10401{
10402 SYM_EXPRDATA* symdata;
10403 SCIP_EXPR** children;
10404 SCIP_EXPR** powexprs;
10405 SCIP_EXPR** prodexprs;
10406 SCIP_EXPR* child;
10407 SCIP_VAR** powvars;
10408 SCIP_VAR** prodvars;
10409 SCIP_VAR* actvar;
10410 SCIP_VAR* actvar2;
10411 SCIP_VAR* var;
10412 SCIP_VAR* var2;
10413 SCIP_Real* sumcoefs;
10414 SCIP_Real constant;
10415 SCIP_Real constant2;
10416 SCIP_Real val;
10417 SCIP_Real val2;
10418 SCIP_Bool* powexprused = NULL;
10419 int* powperm = NULL;
10420 int* prodperm = NULL;
10421 int nchildren;
10422 int nlocvars;
10423 int nodeidx;
10424 int coefnodeidx1;
10425 int coefnodeidx2;
10426 int cnt;
10427 int i;
10428 int j;
10429 int nterms;
10430 int npowexprs = 0;
10431 int nprodexprs = 0;
10432 int powcoef = 0;
10433
10434 assert(scip != NULL);
10435 assert(sumexpr != NULL);
10436 assert(cons != NULL);
10437 assert(SCIPisExprSum(scip, sumexpr));
10438 assert(consvars != NULL);
10439 assert(consvals != NULL);
10440 assert(maxnconsvars != NULL);
10441 assert(*maxnconsvars > 0);
10442 assert(handledexprs != NULL);
10443
10444 /* iterate over sum expression and extract all power and product expressions */
10445 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10446 children = SCIPexprGetChildren(sumexpr);
10447 nchildren = SCIPexprGetNChildren(sumexpr);
10448 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10449 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10450 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10451 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10452
10453 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10454 /** @todo make this work in a more general case */
10455 for( i = 0; i < nchildren; ++i )
10456 {
10457 if( SCIPisExprPower(scip, children[i]) )
10458 {
10459 SCIP_Real exponent;
10460
10461 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10462 if( powcoef == 0 )
10463 {
10464 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10465 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10466 }
10467 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10468 continue;
10469
10470 /* we only store power expressions if their child is a variable */
10471 assert(SCIPexprGetNChildren(children[i]) == 1);
10472 child = SCIPexprGetChildren(children[i])[0];
10473 if( !SCIPisExprVar(scip, child) )
10474 continue;
10475
10476 /* the power is required to be a 2 */
10477 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10478 assert(symdata != NULL);
10479 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10480
10481 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10482 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10483
10484 if( !SCIPisEQ(scip, exponent, 2.0) )
10485 continue;
10486
10487 /* we only store power expressions if the child is not multi-aggregated */
10488 var = SCIPgetVarExprVar(child);
10490 {
10491 powexprs[npowexprs] = children[i];
10492 powvars[npowexprs++] = var;
10493 }
10494 }
10495 else if( SCIPisExprProduct(scip, children[i]) )
10496 {
10497 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10498 if( powcoef == 0 )
10499 {
10500 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10501 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10502 }
10503 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10504 continue;
10505
10506 /* we only store power expressions if they have exactly two children being variables */
10507 if( SCIPexprGetNChildren(children[i]) != 2 )
10508 continue;
10509 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10510 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10511 continue;
10512
10513 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10514 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10515
10516 /* we only store product expressions if the children are not multi-aggregated */
10519 {
10520 prodexprs[nprodexprs] = children[i];
10521 prodvars[nprodexprs++] = var;
10522 prodexprs[nprodexprs] = children[i];
10523 prodvars[nprodexprs++] = var2;
10524 }
10525 }
10526 }
10527
10528 if( npowexprs == 0 || nprodexprs != npowexprs )
10529 goto FREEMEMORY;
10530
10531 /* check whether the power variables and product variables match */
10532 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10533 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10534
10535 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10536 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10537
10538 for( i = 0; i < npowexprs; ++i )
10539 {
10540 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10541 goto FREEMEMORY;
10542 }
10543
10544 /* if we reach this line, the variables match: we have found a potential norm constraint */
10545 assert(npowexprs % 2 == 0);
10546 nterms = npowexprs / 2;
10547 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10548
10549 /* add gadget of each squared difference term */
10550 cnt = 0;
10551 for( i = 0; i < nterms; ++i )
10552 {
10553 SCIP_Bool var1found = FALSE;
10554 SCIP_Bool var2found = FALSE;
10555
10556 (*consvals)[0] = 1.0;
10557 (*consvars)[0] = prodvars[cnt++];
10558 constant = 0.0;
10559 nlocvars = 1;
10560
10562 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10563
10564 if( nlocvars != 1 )
10565 {
10566 ++cnt;
10567 continue;
10568 }
10569 actvar = (*consvars)[0];
10570 val = (*consvals)[0];
10571
10572 (*consvals)[0] = 1.0;
10573 (*consvars)[0] = prodvars[cnt++];
10574 constant2 = 0.0;
10575 nlocvars = 1;
10576
10578 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10579
10580 if( nlocvars != 1 )
10581 continue;
10582 actvar2 = (*consvars)[0];
10583 val2 = (*consvals)[0];
10584
10585 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10586 * cannot be centered at the origin or they are not centered around the same point
10587 */
10588 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10592 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10593 continue;
10594
10595 /* add gadget */
10596 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10597 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10598 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10599
10600 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10601 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10602 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10603 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10604 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10605 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10606 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10607 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10608 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10609 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10610 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10611
10612 /* mark product expression as handled */
10613 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10614
10615 /* find corresponding unused power expressions and mark them as handled */
10616 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10617 {
10618 if( powexprused[j] )
10619 continue;
10620 assert(cnt >= 2);
10621
10622 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10623 {
10624 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10625 powexprused[j] = TRUE;
10626 var1found = TRUE;
10627 }
10628 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10629 {
10630 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10631 powexprused[j] = TRUE;
10632 var2found = TRUE;
10633 }
10634 }
10635 }
10636
10637 FREEMEMORY:
10638 SCIPfreeBufferArrayNull(scip, &powexprused);
10639 SCIPfreeBufferArrayNull(scip, &prodperm);
10640 SCIPfreeBufferArrayNull(scip, &powperm);
10641 SCIPfreeBufferArray(scip, &prodvars);
10642 SCIPfreeBufferArray(scip, &powvars);
10643 SCIPfreeBufferArray(scip, &prodexprs);
10644 SCIPfreeBufferArray(scip, &powexprs);
10645
10646 return SCIP_OKAY;
10647}
10648
10649/** adds symmetry information of constraint to a symmetry detection graph */
10650static
10652 SCIP* scip, /**< SCIP pointer */
10653 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10654 SCIP_CONS* cons, /**< constraint */
10655 SYM_GRAPH* graph, /**< symmetry detection graph */
10656 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10657 )
10658{ /*lint --e{850}*/
10659 SCIP_EXPRITER* it;
10660 SCIP_HASHSET* handledexprs;
10661 SCIP_EXPR* rootexpr;
10662 SCIP_EXPR* expr;
10663 SCIP_VAR** consvars;
10664 SCIP_Real* consvals;
10665 SCIP_Real constant;
10666 SCIP_Real parentcoef = 0.0;
10667 int* openidx;
10668 int maxnopenidx;
10669 int parentidx;
10670 int nconsvars;
10671 int maxnconsvars;
10672 int nlocvars;
10673 int nopenidx = 0;
10674 int consnodeidx;
10675 int nodeidx;
10676 int i;
10677 SCIP_Bool iscolored;
10678 SCIP_Bool hasparentcoef;
10679
10680 assert(scip != NULL);
10681 assert(cons != NULL);
10682 assert(graph != NULL);
10683 assert(success != NULL);
10684
10685 /* store lhs/rhs */
10687 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10688
10689 rootexpr = SCIPgetExprNonlinear(cons);
10690 assert(rootexpr != NULL);
10691
10692 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10693 expr = SCIPgetExprNonlinear(cons);
10694 assert(expr != NULL);
10695
10699
10700 /* find potential number of nodes in graph */
10701 maxnopenidx = 0;
10702 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10703 {
10705 continue;
10706
10707 ++maxnopenidx;
10708 }
10709
10710 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10711
10712 maxnconsvars = SCIPgetNVars(scip);
10713 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10714 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10715
10716 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10717 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10718
10719 /* iterate over expression tree and store nodes/edges */
10720 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10723
10724 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10725 {
10726 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10727 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10728 {
10729 SCIP_EXPR* baseexpr;
10730
10731 baseexpr = expr;
10732 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10733 expr = SCIPexpriterGetNext(it);
10734
10735 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10736
10737 /* leave the expression */
10738 continue;
10739 }
10740
10741 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10743 {
10744 --nopenidx;
10745 continue;
10746 }
10748
10749 /* find parentidx */
10750 if( expr == rootexpr )
10751 parentidx = consnodeidx;
10752 else
10753 {
10754 assert(nopenidx >= 1);
10755 parentidx = openidx[nopenidx - 1];
10756 }
10757
10758 /* possibly find a coefficient assigned to the expression by the parent */
10759 hasparentcoef = FALSE;
10760 if ( expr != rootexpr )
10761 {
10762 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10763 }
10764
10765 /* deal with different kinds of expressions and store them in the symmetry data structure */
10766 if( SCIPisExprVar(scip, expr) )
10767 {
10768 /* needed to correctly reset value when leaving expression */
10769 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10770
10771 openidx[nopenidx++] = -1;
10772
10773 assert(maxnconsvars > 0);
10774 assert(parentidx > 0);
10775
10776 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10777 if( hasparentcoef )
10778 {
10779 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10780
10781 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10782 parentidx = nodeidx;
10783 }
10784
10785 /* connect (aggregation of) variable expression with its parent */
10786 nconsvars = 1;
10787 consvars[0] = SCIPgetVarExprVar(expr);
10788 consvals[0] = 1.0;
10789 constant = 0.0;
10790
10791 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10792 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10793
10794 /* check whether variable is aggregated */
10795 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10796 {
10797 int thisidx;
10798
10799 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10800 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10801
10802 parentidx = thisidx;
10803 }
10804 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10805 nconsvars, constant) );
10806 }
10807 else if( SCIPisExprValue(scip, expr) )
10808 {
10809 assert(parentidx > 0);
10810
10811 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10812
10813 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10814
10815 /* needed to correctly reset value when leaving expression */
10816 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10817
10818 openidx[nopenidx++] = -1;
10819 }
10820 else
10821 {
10822 SCIP_Bool usedefaultgadget = TRUE;
10823
10824 assert(expr == rootexpr || parentidx > 0);
10825 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10826
10827 if( SCIPisExprSum(scip, expr) )
10828 {
10829 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10830 SCIP_EXPR** children;
10831 int sumidx;
10832 int optype;
10833 int childidx;
10834
10835 /* sums are handled by a special gadget */
10836 usedefaultgadget = FALSE;
10837
10838 /* extract all children being variables and compute the sum of active variables expression */
10839 nlocvars = 0;
10840 children = SCIPexprGetChildren(expr);
10841
10842 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10843
10844 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10845 {
10846 if( !SCIPisExprVar(scip, children[childidx]) )
10847 continue;
10848
10849 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10850 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10851
10852 /* store that we have already handled this expression */
10853 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10854 }
10855
10856 constant = SCIPgetConstantExprSum(expr);
10857
10858 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10859 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10860
10862
10863 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10864 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10865
10866 /* add the linear part of the sum */
10867 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10868
10869 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10870
10871 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10872 if( symtype == SYM_SYMTYPE_SIGNPERM )
10873 {
10874 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10875 &consvars, &consvals, &maxnconsvars, handledexprs) );
10876 }
10877
10878 /* store sumidx for children that have not been treated */
10879 openidx[nopenidx++] = sumidx;
10880 }
10881 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10882 {
10883 SCIP_Bool succ;
10884
10885 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10886 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10887
10888 if( succ )
10889 {
10890 usedefaultgadget = FALSE;
10891 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10892 }
10893 }
10894 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10895 {
10896 SCIP_Bool succ;
10897
10898 /* we can find more signed permutations for even univariate operators */
10899 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10900 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10901
10902 if( succ )
10903 {
10904 usedefaultgadget = FALSE;
10905 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10906 }
10907 }
10908
10909 if( usedefaultgadget )
10910 {
10911 int opidx;
10912 int optype;
10913
10915 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10916 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10917
10918 /* possibly add constants of expression */
10920 {
10921 SYM_EXPRDATA* symdata;
10922
10923 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10924 assert(symdata != NULL);
10925
10926 /* if expression has multiple constants, assign colors to edges to distinguish them */
10927 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
10928 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10929 {
10930 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
10931 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10932 }
10933
10934 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10935 }
10936
10937 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10938
10939 openidx[nopenidx++] = opidx;
10940 }
10941 }
10942 }
10943
10944 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
10945 SCIPfreeBufferArray(scip, &consvals);
10946 SCIPfreeBufferArray(scip, &consvars);
10947 SCIPfreeBufferArray(scip, &openidx);
10948 SCIPfreeExpriter(&it);
10949
10950 *success = TRUE;
10951
10952 return SCIP_OKAY;
10953}
10954
10955/*
10956 * Callback methods of constraint handler
10957 */
10958
10959/** copy method for constraint handler plugins (called when SCIP copies plugins) */
10960static
10961SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
10962{ /*lint --e{715}*/
10963 SCIP_CONSHDLR* targetconshdlr;
10964 SCIP_CONSHDLRDATA* sourceconshdlrdata;
10965 int i;
10966
10967 assert(scip != NULL);
10968 assert(conshdlr != NULL);
10969 assert(valid != NULL);
10970 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10971
10972 /* create basic data of constraint handler and include it to scip */
10974
10975 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10976 assert(targetconshdlr != NULL);
10977 assert(targetconshdlr != conshdlr);
10978
10979 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
10980 assert(sourceconshdlrdata != NULL);
10981
10982 /* copy nonlinear handlers */
10983 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10984 {
10985 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
10986 }
10987
10988 *valid = TRUE;
10989
10990 return SCIP_OKAY;
10991}
10992
10993/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10994static
10995SCIP_DECL_CONSFREE(consFreeNonlinear)
10996{ /*lint --e{715}*/
10997 SCIP_CONSHDLRDATA* conshdlrdata;
10998 int i;
10999
11000 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11001 assert(conshdlrdata != NULL);
11002
11003 /* free nonlinear handlers */
11004 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11005 {
11006 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11007 assert(conshdlrdata->nlhdlrs[i] == NULL);
11008 }
11009 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11010 conshdlrdata->nlhdlrssize = 0;
11011
11012 /* free upgrade functions */
11013 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11014 {
11015 assert(conshdlrdata->consupgrades[i] != NULL);
11016 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11017 }
11018 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11019
11020 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11021
11022 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11023
11024 if( conshdlrdata->vp_randnumgen != NULL )
11025 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11026
11027 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11028 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11029 {
11030 if( conshdlrdata->vp_lp[i] != NULL )
11031 {
11032 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11033 }
11034 }
11035
11036 assert(conshdlrdata->branchrandnumgen == NULL);
11037
11038 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11039 SCIPhashmapFree(&conshdlrdata->var2expr);
11040
11041 SCIPfreeBlockMemory(scip, &conshdlrdata);
11042 SCIPconshdlrSetData(conshdlr, NULL);
11043
11044 return SCIP_OKAY;
11045}
11046
11047
11048/** initialization method of constraint handler (called after problem was transformed) */
11049static
11050SCIP_DECL_CONSINIT(consInitNonlinear)
11051{ /*lint --e{715}*/
11052 SCIP_CONSHDLRDATA* conshdlrdata;
11053 int i;
11054
11055 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11056 assert(conshdlrdata != NULL);
11057
11058 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11059 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11060 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11061 conshdlrdata->enforound = 1;
11062 /* reset numbering for auxiliary variables */
11063 conshdlrdata->auxvarid = 0;
11064
11065 for( i = 0; i < nconss; ++i )
11066 {
11067 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11068 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11069 }
11070
11071 /* sort nonlinear handlers by detection priority, in decreasing order */
11072 if( conshdlrdata->nnlhdlrs > 1 )
11073 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11074
11075 /* get heuristics for later use */
11076 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11077 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11078
11079 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11080 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11081 {
11082 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11083 }
11084
11085 /* reset statistics in constraint handler */
11086 conshdlrdata->nweaksepa = 0;
11087 conshdlrdata->ntightenlp = 0;
11088 conshdlrdata->ndesperatebranch = 0;
11089 conshdlrdata->ndesperatecutoff = 0;
11090 conshdlrdata->ndesperatetightenlp = 0;
11091 conshdlrdata->nforcelp = 0;
11092 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11093 conshdlrdata->ncanonicalizecalls = 0;
11094
11095#ifdef ENFOLOGFILE
11096 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11097#endif
11098
11099 return SCIP_OKAY;
11100}
11101
11102
11103/** deinitialization method of constraint handler (called before transformed problem is freed) */
11104static
11105SCIP_DECL_CONSEXIT(consExitNonlinear)
11106{ /*lint --e{715}*/
11107 SCIP_CONSHDLRDATA* conshdlrdata;
11108 SCIP_CONS** consssorted;
11109 int i;
11110
11111 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11112 assert(conshdlrdata != NULL);
11113
11114 if( nconss > 0 )
11115 {
11116 /* for better performance of dropVarEvents, we sort by index, descending */
11117 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11118 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11119
11120 for( i = 0; i < nconss; ++i )
11121 {
11122 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11123 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11124 }
11125
11126 SCIPfreeBufferArray(scip, &consssorted);
11127 }
11128
11129 conshdlrdata->subnlpheur = NULL;
11130 conshdlrdata->trysolheur = NULL;
11131
11132 if( conshdlrdata->vp_randnumgen != NULL )
11133 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11134
11135 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11136 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11137 {
11138 if( conshdlrdata->vp_lp[i] != NULL )
11139 {
11140 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11141 }
11142 }
11143
11144 if( conshdlrdata->branchrandnumgen != NULL )
11145 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11146
11147 /* deinitialize nonlinear handlers */
11148 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11149 {
11150 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11151 }
11152
11153 ENFOLOG(
11154 if( enfologfile != NULL )
11155 {
11156 fclose(enfologfile);
11157 enfologfile = NULL;
11158 })
11159
11160 return SCIP_OKAY;
11161}
11162
11163
11164/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11165#ifdef SCIP_DISABLED_CODE
11166static
11168{ /*lint --e{715}*/
11169 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11170 SCIPABORT(); /*lint --e{527}*/
11171
11172 return SCIP_OKAY;
11173}
11174#else
11175#define consInitpreNonlinear NULL
11176#endif
11177
11178
11179/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11180static
11181SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11182{ /*lint --e{715}*/
11183 SCIP_Bool infeasible;
11184
11185 if( nconss == 0 )
11186 return SCIP_OKAY;
11187
11188 /* skip some extra work if already known to be infeasible */
11190 return SCIP_OKAY;
11191
11192 /* simplify constraints and replace common subexpressions */
11193 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11194
11195 /* currently SCIP does not offer to communicate this,
11196 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11197 * or if a constraint expression became constant
11198 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11199 */
11200 /* assert(!infeasible); */
11201
11202 /* tell SCIP that we have something nonlinear */
11204
11205 return SCIP_OKAY;
11206}
11207
11208
11209/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11210static
11211SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11212{ /*lint --e{715}*/
11213 SCIP_CONSHDLRDATA* conshdlrdata;
11214 int i;
11215
11216 /* skip remaining initializations if we have solved already
11217 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11218 * assumes nonempty activities in expressions
11219 */
11220 switch( SCIPgetStatus(scip) )
11221 {
11226 return SCIP_OKAY;
11227 default: ;
11228 } /*lint !e788 */
11229
11230 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11231 assert(conshdlrdata != NULL);
11232
11233 /* reset one of the number of detections counter to count only current round */
11234 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11235 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11236
11237 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11238
11239 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11240 if( conshdlrdata->branchpscostweight > 0.0 )
11241 {
11242 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11243 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11244 {
11245 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11246 SCIPABORT();
11247 return SCIP_INVALIDDATA;
11248 }
11249 }
11250
11251 return SCIP_OKAY;
11252}
11253
11254
11255/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11256static
11257SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11258{ /*lint --e{715}*/
11259 SCIP_CONSHDLRDATA* conshdlrdata;
11260
11261 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11262
11263 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11264 assert(conshdlrdata != NULL);
11265
11266 /* free hash table for bilinear terms */
11267 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11268
11269 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11270 conshdlrdata->checkedvarlocks = FALSE;
11271
11272 /* drop catching new solution event, if catched before */
11273 if( conshdlrdata->newsoleventfilterpos >= 0 )
11274 {
11275 SCIP_EVENTHDLR* eventhdlr;
11276
11277 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11278 assert(eventhdlr != NULL);
11279
11280 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11281 conshdlrdata->newsoleventfilterpos = -1;
11282 }
11283
11284 return SCIP_OKAY;
11285}
11286
11287
11288/** frees specific constraint data */
11289static
11290SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11291{ /*lint --e{715}*/
11292 assert(consdata != NULL);
11293 assert(*consdata != NULL);
11294 assert((*consdata)->expr != NULL);
11295
11296 /* constraint locks should have been removed */
11297 assert((*consdata)->nlockspos == 0);
11298 assert((*consdata)->nlocksneg == 0);
11299
11300 /* free variable expressions */
11301 SCIP_CALL( freeVarExprs(scip, *consdata) );
11302
11303 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11304
11305 /* free nonlinear row representation */
11306 if( (*consdata)->nlrow != NULL )
11307 {
11308 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11309 }
11310
11311 SCIPfreeBlockMemory(scip, consdata);
11312
11313 return SCIP_OKAY;
11314}
11315
11316
11317/** transforms constraint data into data belonging to the transformed problem */
11318static
11319SCIP_DECL_CONSTRANS(consTransNonlinear)
11320{ /*lint --e{715}*/
11321 SCIP_EXPR* targetexpr;
11322 SCIP_CONSDATA* sourcedata;
11323
11324 sourcedata = SCIPconsGetData(sourcecons);
11325 assert(sourcedata != NULL);
11326
11327 /* get a copy of sourceexpr with transformed vars */
11328 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11329 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11330
11331 /* create transformed cons (only captures targetexpr, no need to copy again) */
11332 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11333 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11334 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11335 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11336 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11337 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11338
11339 /* release target expr */
11340 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11341
11342 return SCIP_OKAY;
11343}
11344
11345
11346/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11347static
11348SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11349{ /*lint --e{715}*/
11350 SCIP_CONSHDLRDATA* conshdlrdata;
11351
11352 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11353 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11354 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11355 * for now, there is an assert in detectNlhdlrs to require initial if separated
11356 */
11357 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11358
11359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11360 assert(conshdlrdata != NULL);
11361
11362 /* catch new solution event */
11363 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11364 {
11365 SCIP_EVENTHDLR* eventhdlr;
11366
11367 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11368 assert(eventhdlr != NULL);
11369
11370 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11371 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11372 }
11373
11374 /* collect all bilinear terms for which an auxvar is present
11375 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11376 * addition (and removal?) of constraints during solve
11377 * this is typically the majority of constraints, but the method should be made more flexible
11378 */
11379 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11380
11381 return SCIP_OKAY;
11382}
11383
11384
11385/** separation method of constraint handler for LP solutions */
11386static
11387SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11388{ /*lint --e{715}*/
11389 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11390
11391 return SCIP_OKAY;
11392}
11393
11394
11395/** separation method of constraint handler for arbitrary primal solutions */
11396static
11397SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11398{ /*lint --e{715}*/
11399 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11400
11401 return SCIP_OKAY;
11402}
11403
11404
11405/** constraint enforcing method of constraint handler for LP solutions */
11406static
11407SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11408{ /*lint --e{715}*/
11409 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11410
11411 return SCIP_OKAY;
11412}
11413
11414
11415/** constraint enforcing method of constraint handler for relaxation solutions */
11416static
11417SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11418{ /*lint --e{715}*/
11419 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11420
11421 return SCIP_OKAY;
11422}
11423
11424
11425/** constraint enforcing method of constraint handler for pseudo solutions */
11426static
11427SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11428{ /*lint --e{715}*/
11429 SCIP_RESULT propresult;
11430 SCIP_Longint soltag;
11431 int nchgbds;
11432 int nnotify;
11433 int c;
11434
11435 soltag = SCIPgetExprNewSoltag(scip);
11436
11437 *result = SCIP_FEASIBLE;
11438 for( c = 0; c < nconss; ++c )
11439 {
11440 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11441
11442 if( isConsViolated(scip, conss[c]) )
11443 *result = SCIP_INFEASIBLE;
11444 }
11445
11446 if( *result == SCIP_FEASIBLE )
11447 return SCIP_OKAY;
11448
11449 /* try to propagate
11450 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11451 */
11452 nchgbds = 0;
11453 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11454
11455 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11456 {
11457 *result = propresult;
11458 return SCIP_OKAY;
11459 }
11460
11461 /* register all unfixed variables in all violated constraints as branching candidates */
11462 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11463 if( nnotify > 0 )
11464 {
11465 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11466
11467 return SCIP_OKAY;
11468 }
11469
11470 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11471 *result = SCIP_SOLVELP;
11472 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11473
11474 return SCIP_OKAY;
11475}
11476
11477
11478/** feasibility check method of constraint handler for integral solutions */
11479static
11480SCIP_DECL_CONSCHECK(consCheckNonlinear)
11481{ /*lint --e{715}*/
11482 SCIP_CONSHDLRDATA* conshdlrdata;
11483 SCIP_CONSDATA* consdata;
11484 SCIP_Real maxviol;
11485 SCIP_Bool maypropfeasible;
11486 SCIP_Longint soltag;
11487 int c;
11488
11489 assert(scip != NULL);
11490 assert(conshdlr != NULL);
11491 assert(conss != NULL || nconss == 0);
11492 assert(result != NULL);
11493
11494 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11495 assert(conshdlrdata != NULL);
11496
11497 *result = SCIP_FEASIBLE;
11498 soltag = SCIPgetExprNewSoltag(scip);
11499 maxviol = 0.0;
11500 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11502
11503 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
11504 maypropfeasible = FALSE;
11505
11506 /* check nonlinear constraints for feasibility */
11507 for( c = 0; c < nconss; ++c )
11508 {
11509 assert(conss != NULL && conss[c] != NULL);
11510 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11511
11512 if( isConsViolated(scip, conss[c]) )
11513 {
11514 *result = SCIP_INFEASIBLE;
11515 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11516
11517 consdata = SCIPconsGetData(conss[c]);
11518 assert(consdata != NULL);
11519
11520 /* print reason for infeasibility */
11521 if( printreason )
11522 {
11523 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11524 SCIPinfoMessage(scip, NULL, ";\n");
11525
11526 if( consdata->lhsviol > SCIPfeastol(scip) )
11527 {
11528 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11529 }
11530 if( consdata->rhsviol > SCIPfeastol(scip) )
11531 {
11532 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11533 }
11534 }
11535 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11536 {
11537 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11538 return SCIP_OKAY;
11539 }
11540
11541 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11542 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11543 maypropfeasible = FALSE;
11544
11545 if( maypropfeasible )
11546 {
11547 if( consdata->lhsviol > SCIPfeastol(scip) )
11548 {
11549 /* check if there is a variable which may help to get the left hand side satisfied
11550 * if there is no such variable, then we cannot get feasible
11551 */
11552 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11553 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11554 maypropfeasible = FALSE;
11555 }
11556 else
11557 {
11558 assert(consdata->rhsviol > SCIPfeastol(scip));
11559 /* check if there is a variable which may help to get the right hand side satisfied
11560 * if there is no such variable, then we cannot get feasible
11561 */
11562 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11563 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11564 maypropfeasible = FALSE;
11565 }
11566 }
11567 }
11568 }
11569
11570 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11571 {
11572 SCIP_Bool success;
11573
11574 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11575
11576 /* do not pass solution to NLP heuristic if we made it feasible this way */
11577 if( success )
11578 return SCIP_OKAY;
11579 }
11580
11581 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11582 {
11583 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11584 }
11585
11586 return SCIP_OKAY;
11587}
11588
11589
11590/** domain propagation method of constraint handler */
11591static
11592SCIP_DECL_CONSPROP(consPropNonlinear)
11593{ /*lint --e{715}*/
11594 int nchgbds = 0;
11595
11596 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11597 assert(nchgbds >= 0);
11598
11599 /* TODO would it make sense to check for redundant constraints? */
11600
11601 return SCIP_OKAY;
11602}
11603
11604
11605/** presolving method of constraint handler */
11606static
11607SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11608{ /*lint --e{715}*/
11609 SCIP_CONSHDLRDATA* conshdlrdata;
11610 SCIP_Bool infeasible;
11611 int c;
11612
11613 *result = SCIP_DIDNOTFIND;
11614
11615 if( nconss == 0 )
11616 {
11617 *result = SCIP_DIDNOTRUN;
11618 return SCIP_OKAY;
11619 }
11620
11621 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11622 assert(conshdlrdata != NULL);
11623
11624 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11625 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11626 if( infeasible )
11627 {
11628 *result = SCIP_CUTOFF;
11629 return SCIP_OKAY;
11630 }
11631
11632 /* merge constraints with the same root expression */
11633 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11634 {
11635 SCIP_Bool success;
11636
11637 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11638 if( success )
11639 *result = SCIP_SUCCESS;
11640 }
11641
11642 /* propagate constraints */
11643 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11644 if( *result == SCIP_CUTOFF )
11645 return SCIP_OKAY;
11646
11647 /* propagate function domains (TODO integrate with simplify?) */
11648 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11649 {
11650 SCIP_RESULT localresult;
11651 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11652 if( localresult == SCIP_CUTOFF )
11653 {
11654 *result = SCIP_CUTOFF;
11655 return SCIP_OKAY;
11656 }
11657 if( localresult == SCIP_REDUCEDDOM )
11658 *result = SCIP_REDUCEDDOM;
11659 }
11660
11661 /* check for redundant constraints, remove constraints that are a value expression */
11662 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11663 if( infeasible )
11664 {
11665 *result = SCIP_CUTOFF;
11666 return SCIP_OKAY;
11667 }
11668
11669 /* try to upgrade constraints */
11670 for( c = 0; c < nconss; ++c )
11671 {
11672 SCIP_Bool upgraded;
11673
11674 /* skip inactive and deleted constraints */
11675 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11676 continue;
11677
11678 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11679 }
11680
11681 /* try to change continuous variables that appear linearly to be implicit integer */
11682 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11683 {
11684 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11685
11686 if( infeasible )
11687 {
11688 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11689 *result = SCIP_CUTOFF;
11690 return SCIP_OKAY;
11691 }
11692 }
11693
11694 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11696 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11697 {
11698 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11699 * constraints multiple times
11700 */
11701 conshdlrdata->checkedvarlocks = TRUE;
11702
11703 for( c = 0; c < nconss; ++c )
11704 {
11705 int tmpnchgvartypes = 0;
11706 int tmpnaddconss = 0;
11707
11708 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11709 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11710 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11711
11712 if( infeasible )
11713 {
11714 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11715 *result = SCIP_CUTOFF;
11716 return SCIP_OKAY;
11717 }
11718
11719 (*nchgvartypes) += tmpnchgvartypes;
11720 (*naddconss) += tmpnaddconss;
11721 }
11722 }
11723
11724 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11725 *result = SCIP_SUCCESS;
11726 else
11727 *result = SCIP_DIDNOTFIND;
11728
11729 return SCIP_OKAY;
11730}
11731
11732
11733/** propagation conflict resolving method of constraint handler */
11734#ifdef SCIP_DISABLED_CODE
11735static
11737{ /*lint --e{715}*/
11738 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11739 SCIPABORT(); /*lint --e{527}*/
11740
11741 return SCIP_OKAY;
11742}
11743#else
11744#define consRespropNonlinear NULL
11745#endif
11746
11747
11748/** variable rounding lock method of constraint handler */
11749static
11750SCIP_DECL_CONSLOCK(consLockNonlinear)
11751{ /*lint --e{715}*/
11752 SCIP_CONSDATA* consdata;
11753 SCIP_EXPR_OWNERDATA* ownerdata;
11754 SCIP_Bool reinitsolve = FALSE;
11755
11756 assert(conshdlr != NULL);
11757 assert(cons != NULL);
11758
11759 consdata = SCIPconsGetData(cons);
11760 assert(consdata != NULL);
11761 assert(consdata->expr != NULL);
11762
11763 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11764
11765 /* check whether we need to initSolve again because
11766 * - we have enfo initialized (nenfos >= 0)
11767 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11768 */
11769 if( ownerdata->nenfos >= 0 )
11770 {
11771 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11772 reinitsolve = TRUE;
11773 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11774 reinitsolve = TRUE;
11775 }
11776
11777 if( reinitsolve )
11778 {
11779 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11780 }
11781
11782 /* add locks */
11783 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11784
11785 if( reinitsolve )
11786 {
11787 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11788 }
11789
11790 return SCIP_OKAY;
11791}
11792
11793
11794/** constraint activation notification method of constraint handler */
11795static
11796SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11797{ /*lint --e{715}*/
11798 SCIP_CONSDATA* consdata;
11799 SCIP_Bool infeasible = FALSE;
11800
11801 consdata = SCIPconsGetData(cons);
11802 assert(consdata != NULL);
11803
11804 /* simplify root expression if the constraint has been added after presolving */
11806 {
11807 SCIP_Bool replacedroot;
11808
11809 if( !consdata->issimplified )
11810 {
11811 SCIP_EXPR* simplified;
11812 SCIP_Bool changed;
11813
11814 /* simplify constraint */
11815 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11816 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11817 assert(simplified != NULL);
11818 consdata->expr = simplified;
11819 consdata->issimplified = TRUE;
11820 }
11821
11822 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11823 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11824 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11825
11826 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11827 {
11828 SCIP_CONSHDLRDATA* conshdlrdata;
11829 SCIP_EXPRITER* it;
11830 SCIP_EXPR* expr;
11831
11832 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11833 assert(conshdlrdata != NULL);
11834
11836 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11838 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11839 {
11840 SCIP_EXPR* child;
11841 SCIP_EXPR* hashmapexpr;
11842
11843 child = SCIPexpriterGetChildExprDFS(it);
11844 if( !SCIPisExprVar(scip, child) )
11845 continue;
11846
11847 /* check which expression is stored in the hashmap for the var of child */
11848 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11849 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11850 if( hashmapexpr != NULL && hashmapexpr != child )
11851 {
11853 }
11854 }
11855 SCIPfreeExpriter(&it);
11856 }
11857 }
11858
11859 /* store variable expressions */
11861 {
11862 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11863 }
11864
11865 /* add manually locks to constraints that are not checked for feasibility */
11866 if( !SCIPconsIsChecked(cons) )
11867 {
11868 assert(consdata->nlockspos == 0);
11869 assert(consdata->nlocksneg == 0);
11870
11871 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11872 }
11873
11874 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11875 {
11876 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11877 }
11878
11879 /* TODO deal with infeasibility */
11880 assert(!infeasible);
11881
11882 return SCIP_OKAY;
11883}
11884
11885
11886/** constraint deactivation notification method of constraint handler */
11887static
11888SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11889{ /*lint --e{715}*/
11890 SCIP_CONSHDLRDATA* conshdlrdata;
11891
11892 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11893 assert(conshdlrdata != NULL);
11894
11896 {
11897 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11898 }
11899
11901 {
11902 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11904 }
11905
11906 /* remove locks that have been added in consActiveExpr() */
11907 if( !SCIPconsIsChecked(cons) )
11908 {
11909 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11910
11911 assert(SCIPconsGetData(cons)->nlockspos == 0);
11912 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11913 }
11914
11915 return SCIP_OKAY;
11916}
11917
11918
11919/** constraint enabling notification method of constraint handler */
11920static
11921SCIP_DECL_CONSENABLE(consEnableNonlinear)
11922{ /*lint --e{715}*/
11923 SCIP_CONSHDLRDATA* conshdlrdata;
11924
11925 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11926 assert(conshdlrdata != NULL);
11927
11929 {
11930 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11931 }
11932
11933 return SCIP_OKAY;
11934}
11935
11936
11937/** constraint disabling notification method of constraint handler */
11938static
11939SCIP_DECL_CONSDISABLE(consDisableNonlinear)
11940{ /*lint --e{715}*/
11941 SCIP_CONSHDLRDATA* conshdlrdata;
11942
11943 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11944 assert(conshdlrdata != NULL);
11945
11947 {
11948 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11949 }
11950
11951 return SCIP_OKAY;
11952}
11953
11954/** variable deletion of constraint handler */
11955#ifdef SCIP_DISABLED_CODE
11956static
11958{ /*lint --e{715}*/
11959 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11960 SCIPABORT(); /*lint --e{527}*/
11961
11962 return SCIP_OKAY;
11963}
11964#else
11965#define consDelvarsNonlinear NULL
11966#endif
11967
11968
11969/** constraint display method of constraint handler */
11970static
11971SCIP_DECL_CONSPRINT(consPrintNonlinear)
11972{ /*lint --e{715}*/
11973 SCIP_CONSDATA* consdata;
11974
11975 consdata = SCIPconsGetData(cons);
11976 assert(consdata != NULL);
11977 assert(consdata->expr != NULL);
11978
11979 /* print left hand side for ranged constraints */
11980 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11981 {
11982 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11983 }
11984
11985 /* print expression */
11986 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11987
11988 /* print right hand side */
11989 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11990 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11991 else if( !SCIPisInfinity(scip, consdata->rhs) )
11992 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11993 else if( !SCIPisInfinity(scip, -consdata->lhs) )
11994 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11995 else
11996 SCIPinfoMessage(scip, file, " [free]");
11997
11998 return SCIP_OKAY;
11999}
12000
12001
12002/** constraint copying method of constraint handler */
12003static
12004SCIP_DECL_CONSCOPY(consCopyNonlinear)
12005{ /*lint --e{715}*/
12006 SCIP_CONSHDLR* targetconshdlr;
12007 SCIP_EXPR* targetexpr = NULL;
12008 SCIP_CONSDATA* sourcedata;
12009
12010 assert(cons != NULL);
12011
12012 sourcedata = SCIPconsGetData(sourcecons);
12013 assert(sourcedata != NULL);
12014
12015 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12016 assert(targetconshdlr != NULL);
12017
12018 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12019
12020 if( targetexpr == NULL )
12021 *valid = FALSE;
12022
12023 *cons = NULL;
12024 if( *valid )
12025 {
12026 /* create copy (only capture targetexpr, no need to copy again) */
12027 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12028 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12029 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12030 }
12031
12032 if( targetexpr != NULL )
12033 {
12034 /* release target expr */
12035 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12036 }
12037
12038 return SCIP_OKAY;
12039}
12040
12041
12042/** constraint parsing method of constraint handler */
12043static
12044SCIP_DECL_CONSPARSE(consParseNonlinear)
12045{ /*lint --e{715}*/
12046 SCIP_Real lhs;
12047 SCIP_Real rhs;
12048 char* endptr;
12049 SCIP_EXPR* consexprtree;
12050
12051 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12052
12053 assert(scip != NULL);
12054 assert(success != NULL);
12055 assert(str != NULL);
12056 assert(name != NULL);
12057 assert(cons != NULL);
12058
12059 *success = FALSE;
12060
12061 /* return if string empty */
12062 if( !*str )
12063 return SCIP_OKAY;
12064
12065 endptr = (char*)str;
12066
12067 /* set left and right hand side to their default values */
12068 lhs = -SCIPinfinity(scip);
12069 rhs = SCIPinfinity(scip);
12070
12071 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12072
12073 /* check for left hand side */
12074 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12075 {
12076 /* there is a number coming, maybe it is a left-hand-side */
12077 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12078 {
12079 SCIPerrorMessage("error parsing number from <%s>\n", str);
12080 return SCIP_READERROR;
12081 }
12082
12083 /* ignore whitespace */
12084 SCIP_CALL( SCIPskipSpace(&endptr) );
12085
12086 if( endptr[0] != '<' || endptr[1] != '=' )
12087 {
12088 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12089 lhs = -SCIPinfinity(scip);
12090 }
12091 else
12092 {
12093 /* it was indeed a left-hand-side, so continue parsing after it */
12094 str = endptr + 2;
12095
12096 /* ignore whitespace */
12097 SCIP_CALL( SCIPskipSpace((char**)&str) );
12098 }
12099 }
12100
12101 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12102
12103 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12104 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12105
12106 /* check for left or right hand side */
12107 SCIP_CALL( SCIPskipSpace((char**)&str) );
12108
12109 /* check for free constraint */
12110 if( strncmp(str, "[free]", 6) == 0 )
12111 {
12112 if( !SCIPisInfinity(scip, -lhs) )
12113 {
12114 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12115 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12116 return SCIP_OKAY;
12117 }
12118 *success = TRUE;
12119 }
12120 else
12121 {
12122 switch( *str )
12123 {
12124 case '<':
12125 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12126 break;
12127 case '=':
12128 if( !SCIPisInfinity(scip, -lhs) )
12129 {
12130 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12131 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12132 return SCIP_OKAY;
12133 }
12134 else
12135 {
12136 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12137 lhs = rhs;
12138 }
12139 break;
12140 case '>':
12141 if( !SCIPisInfinity(scip, -lhs) )
12142 {
12143 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12144 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12145 return SCIP_OKAY;
12146 }
12147 else
12148 {
12149 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12150 break;
12151 }
12152 case '\0':
12153 *success = TRUE;
12154 break;
12155 default:
12156 SCIPerrorMessage("unexpected character %c\n", *str);
12157 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12158 return SCIP_OKAY;
12159 }
12160 }
12161
12162 /* create constraint */
12163 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12164 consexprtree, lhs, rhs, FALSE,
12165 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12166 assert(*cons != NULL);
12167
12168 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12169
12170 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12171
12172 return SCIP_OKAY;
12173}
12174
12175
12176/** constraint method of constraint handler which returns the variables (if possible) */
12177static
12178SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12179{ /*lint --e{715}*/
12180 SCIP_CONSDATA* consdata;
12181 int i;
12182
12183 consdata = SCIPconsGetData(cons);
12184 assert(consdata != NULL);
12185
12186 /* store variable expressions if not done so far */
12187 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12188
12189 /* check whether array is too small in order to store all variables */
12190 if( varssize < consdata->nvarexprs )
12191 {
12192 *success = FALSE;
12193 return SCIP_OKAY;
12194 }
12195
12196 for( i = 0; i < consdata->nvarexprs; ++i )
12197 {
12198 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12199 assert(vars[i] != NULL);
12200 }
12201
12202 *success = TRUE;
12203
12204 return SCIP_OKAY;
12205}
12206
12207/** constraint method of constraint handler which returns the number of variables (if possible) */
12208static
12209SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12210{ /*lint --e{715}*/
12211 SCIP_CONSDATA* consdata;
12212
12213 consdata = SCIPconsGetData(cons);
12214 assert(consdata != NULL);
12215
12216 /* store variable expressions if not done so far */
12217 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12218
12219 *nvars = consdata->nvarexprs;
12220 *success = TRUE;
12221
12222 return SCIP_OKAY;
12223}
12224
12225/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12226#ifdef SCIP_DISABLED_CODE
12227static
12229{ /*lint --e{715}*/
12230 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12231 SCIPABORT(); /*lint --e{527}*/
12232
12233 return SCIP_OKAY;
12234}
12235#else
12236#define consGetDiveBdChgsNonlinear NULL
12237#endif
12238
12239/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12240static
12241SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12242{ /*lint --e{715}*/
12243 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12244
12245 return SCIP_OKAY;
12246}
12247
12248/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12249static
12250SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12251{ /*lint --e{715}*/
12252 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12253
12254 return SCIP_OKAY;
12255}
12256
12257/** output method of statistics table to output file stream 'file' */
12258static
12259SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12260{ /*lint --e{715}*/
12261 SCIP_CONSHDLR* conshdlr;
12262 SCIP_CONSHDLRDATA* conshdlrdata;
12263
12264 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12265 assert(conshdlr != NULL);
12266
12267 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12268 assert(conshdlrdata != NULL);
12269
12270 /* print statistics for constraint handler */
12271 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12272 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12273 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12274 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12275 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12276 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12277 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12278 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12279 SCIPinfoMessage(scip, file, "\n");
12280 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12281 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12282 SCIPinfoMessage(scip, file, "\n");
12283
12284 return SCIP_OKAY;
12285}
12286
12287/** output method of statistics table to output file stream 'file' */
12288static
12289SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12290{ /*lint --e{715}*/
12291 SCIP_CONSHDLR* conshdlr;
12292 SCIP_CONSHDLRDATA* conshdlrdata;
12293
12294 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12295 assert(conshdlr != NULL);
12296
12297 /* skip nlhdlr table if there never were active nonlinear constraints */
12298 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12299 return SCIP_OKAY;
12300
12301 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12302 assert(conshdlrdata != NULL);
12303
12304 /* print statistics for nonlinear handlers */
12305 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12306
12307 return SCIP_OKAY;
12308}
12309
12310/** execution method of display nlhdlrs dialog */
12311static
12312SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12313{ /*lint --e{715}*/
12314 SCIP_CONSHDLR* conshdlr;
12315 SCIP_CONSHDLRDATA* conshdlrdata;
12316 int i;
12317
12318 /* add dialog to history of dialogs that have been executed */
12319 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12320
12321 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12322 assert(conshdlr != NULL);
12323
12324 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12325 assert(conshdlrdata != NULL);
12326
12327 /* display list of nonlinear handler */
12328 SCIPdialogMessage(scip, NULL, "\n");
12329 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12330 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12331 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12332 {
12333 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12334 assert(nlhdlr != NULL);
12335
12336 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12337 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12340 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12341 SCIPdialogMessage(scip, NULL, "\n");
12342 }
12343 SCIPdialogMessage(scip, NULL, "\n");
12344
12345 /* next dialog will be root dialog again */
12346 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12347
12348 return SCIP_OKAY;
12349}
12350
12351/*
12352 * constraint handler specific interface methods
12353 */
12354
12355/** creates the handler for nonlinear constraints and includes it in SCIP */
12357 SCIP* scip /**< SCIP data structure */
12358 )
12359{
12360 SCIP_CONSHDLRDATA* conshdlrdata;
12361 SCIP_DIALOG* parentdialog;
12362
12363 /* create nonlinear constraint handler data */
12364 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12365 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12366 conshdlrdata->curboundstag = 1;
12367 conshdlrdata->lastboundrelax = 1;
12368 conshdlrdata->curpropboundstag = 1;
12369 conshdlrdata->newsoleventfilterpos = -1;
12370 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12371 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12372 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12373
12374 /* include constraint handler */
12380 conshdlrCopyNonlinear,
12381 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12382 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12383 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12384 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12385 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12386 consActiveNonlinear, consDeactiveNonlinear,
12387 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12388 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12389 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12390 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12391
12392 /* add nonlinear constraint handler parameters */
12393 /* TODO organize into more subcategories */
12394 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12395 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12396 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12397
12398 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12399 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12400 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12401
12402 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12403 "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",
12404 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12405
12406 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12407 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12408 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12409
12410 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12411 "by how much to relax constraint sides during bound tightening",
12412 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12413
12414 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12415 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12416 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12417
12418 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12419 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12420 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12421
12422 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12423 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12424 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12425
12426 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12427 "maximal number of auxiliary expressions per bilinear term",
12428 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12429
12430 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12431 "whether to reformulate products of binary variables during presolving",
12432 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12433
12434 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12435 "whether to use the AND constraint handler for reformulating binary products",
12436 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12437
12438 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12439 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12440 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12441
12442 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12443 "whether to forbid multiaggregation of nonlinear variables",
12444 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12445
12446 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12447 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12448 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12449
12450 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12451 "whether to (re)run propagation in enforcement",
12452 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12453
12454 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12455 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12456 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12457
12458 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12459 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12460 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12461
12462 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12463 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12464 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12465
12466 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12467 "whether to force \"strong\" cuts in enforcement",
12468 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12469
12470 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12471 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12472 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12473
12474 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12475 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12476 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12477
12478 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12479 "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",
12480 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12481
12482 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12483 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12484 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12485
12486 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12487 "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)",
12488 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12489
12490 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12491 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12492 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12493
12494 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12495 "whether to use external branching candidates and branching rules for branching",
12496 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12497
12498 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12499 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12500 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12501
12502 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12503 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12504 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12505
12506 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12507 "weight by how much to consider the violation assigned to a variable for its branching score",
12508 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12509
12510 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12511 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12512 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12513
12514 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12515 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12516 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12517
12518 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12519 "weight by how much to consider the pseudo cost of a variable for its branching score",
12520 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12521
12522 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12523 "weight by how much to consider the domain width in branching score",
12524 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12525
12526 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12527 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12528 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12529
12530 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12531 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12532 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12533
12534 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12535 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12536 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12537
12538 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12539 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12540 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12541
12542 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12543 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12544 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12545
12546 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12547 "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)",
12548 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12549
12550 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12551 "whether to assume that any constraint is convex",
12552 &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
12553
12554 /* include handler for bound change events */
12555 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12556 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12557 assert(conshdlrdata->eventhdlr != NULL);
12558
12559 /* include tables for statistics */
12562 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
12564
12567 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
12569
12570 /* create, include, and release display nlhdlrs dialog */
12571 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12572 {
12573 SCIP_DIALOG* dialog;
12574
12575 assert(parentdialog != NULL);
12576 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12577
12579 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12581 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12582 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12583 }
12584
12585 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12586 processNewSolutionEvent, NULL) );
12587
12588 return SCIP_OKAY;
12589}
12590
12591/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12593 SCIP* scip, /**< SCIP data structure */
12594 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12595 int priority, /**< priority of upgrading method */
12596 SCIP_Bool active, /**< should the upgrading method by active by default? */
12597 const char* conshdlrname /**< name of the constraint handler */
12598 )
12599{
12600 SCIP_CONSHDLR* conshdlr;
12601 SCIP_CONSHDLRDATA* conshdlrdata;
12602 CONSUPGRADE* consupgrade;
12604 char paramdesc[SCIP_MAXSTRLEN];
12605 int i;
12606
12607 assert(conshdlrname != NULL );
12608 assert(nlconsupgd != NULL);
12609
12610 /* find the nonlinear constraint handler */
12611 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12612 if( conshdlr == NULL )
12613 {
12614 SCIPerrorMessage("nonlinear constraint handler not found\n");
12615 return SCIP_PLUGINNOTFOUND;
12616 }
12617
12618 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12619 assert(conshdlrdata != NULL);
12620
12621 /* check whether upgrade method exists already */
12622 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12623 {
12624 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12625 {
12626#ifdef SCIP_DEBUG
12627 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12628#endif
12629 return SCIP_OKAY;
12630 }
12631 }
12632
12633 /* create a nonlinear constraint upgrade data object */
12634 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12635 consupgrade->consupgd = nlconsupgd;
12636 consupgrade->priority = priority;
12637 consupgrade->active = active;
12638
12639 /* insert nonlinear constraint upgrade method into constraint handler data */
12640 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12641 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12642
12643 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12644 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12645 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12646 conshdlrdata->consupgrades[i] = consupgrade;
12647 conshdlrdata->nconsupgrades++;
12648
12649 /* adds parameter to turn on and off the upgrading step */
12650 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12651 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12653 paramname, paramdesc,
12654 &consupgrade->active, FALSE, active, NULL, NULL) );
12655
12656 return SCIP_OKAY;
12657}
12658
12659/** creates and captures a nonlinear constraint
12660 *
12661 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12662 */
12664 SCIP* scip, /**< SCIP data structure */
12665 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12666 const char* name, /**< name of constraint */
12667 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12668 SCIP_Real lhs, /**< left hand side of constraint */
12669 SCIP_Real rhs, /**< right hand side of constraint */
12670 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12671 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12672 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12673 * Usually set to TRUE. */
12674 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12675 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12676 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12677 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12678 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12679 * Usually set to TRUE. */
12680 SCIP_Bool local, /**< is constraint only valid locally?
12681 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12682 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12683 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12684 * adds coefficients to this constraint. */
12685 SCIP_Bool dynamic, /**< is constraint subject to aging?
12686 * Usually set to FALSE. Set to TRUE for own cuts which
12687 * are separated as constraints. */
12688 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12689 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12690 )
12691{
12692 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12693 SCIP_CONSHDLR* conshdlr;
12694
12695 /* find the nonlinear constraint handler */
12696 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12697 if( conshdlr == NULL )
12698 {
12699 SCIPerrorMessage("nonlinear constraint handler not found\n");
12700 return SCIP_PLUGINNOTFOUND;
12701 }
12702
12703 /* create constraint */
12704 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12705 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12706
12707 return SCIP_OKAY;
12708}
12709
12710/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12711 *
12712 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12713 *
12714 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12715 *
12716 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12717 */
12719 SCIP* scip, /**< SCIP data structure */
12720 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12721 const char* name, /**< name of constraint */
12722 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12723 SCIP_Real lhs, /**< left hand side of constraint */
12724 SCIP_Real rhs /**< right hand side of constraint */
12725 )
12726{
12727 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12729
12730 return SCIP_OKAY;
12731}
12732
12733/** creates and captures a quadratic nonlinear constraint
12734 *
12735 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12736 */
12738 SCIP* scip, /**< SCIP data structure */
12739 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12740 const char* name, /**< name of constraint */
12741 int nlinvars, /**< number of linear terms */
12742 SCIP_VAR** linvars, /**< array with variables in linear part */
12743 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12744 int nquadterms, /**< number of quadratic terms */
12745 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12746 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12747 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12748 SCIP_Real lhs, /**< left hand side of quadratic equation */
12749 SCIP_Real rhs, /**< right hand side of quadratic equation */
12750 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12751 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12752 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12753 * Usually set to TRUE. */
12754 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12755 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12756 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12757 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12758 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12759 * Usually set to TRUE. */
12760 SCIP_Bool local, /**< is constraint only valid locally?
12761 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12762 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12763 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12764 * adds coefficients to this constraint. */
12765 SCIP_Bool dynamic, /**< is constraint subject to aging?
12766 * Usually set to FALSE. Set to TRUE for own cuts which
12767 * are separated as constraints. */
12768 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12769 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12770 )
12771{
12772 SCIP_CONSHDLR* conshdlr;
12773 SCIP_EXPR* expr;
12774
12775 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12776 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12777
12778 /* get nonlinear constraint handler */
12779 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12780 if( conshdlr == NULL )
12781 {
12782 SCIPerrorMessage("nonlinear constraint handler not found\n");
12783 return SCIP_PLUGINNOTFOUND;
12784 }
12785
12786 /* create quadratic expression */
12787 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12788 assert(expr != NULL);
12789
12790 /* create nonlinear constraint */
12791 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12792 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12793
12794 /* release quadratic expression (captured by constraint now) */
12795 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12796
12797 return SCIP_OKAY;
12798}
12799
12800/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12801 *
12802 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12803 *
12804 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12805 *
12806 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12807 */
12809 SCIP* scip, /**< SCIP data structure */
12810 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12811 const char* name, /**< name of constraint */
12812 int nlinvars, /**< number of linear terms */
12813 SCIP_VAR** linvars, /**< array with variables in linear part */
12814 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12815 int nquadterms, /**< number of quadratic terms */
12816 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12817 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12818 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12819 SCIP_Real lhs, /**< left hand side of quadratic equation */
12820 SCIP_Real rhs /**< right hand side of quadratic equation */
12821 )
12822{
12823 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12825
12826 return SCIP_OKAY;
12827}
12828
12829/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12830 *
12831 * \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$
12832 *
12833 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12834 */
12836 SCIP* scip, /**< SCIP data structure */
12837 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12838 const char* name, /**< name of constraint */
12839 int nvars, /**< number of variables on left hand side of constraint (n) */
12840 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12841 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12842 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12843 SCIP_Real constant, /**< constant on left hand side (gamma) */
12844 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12845 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12846 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12847 )
12848{
12849 SCIP_EXPR* expr;
12850 SCIP_EXPR* lhssum;
12851 SCIP_EXPR* terms[2];
12852 SCIP_Real termcoefs[2];
12853 int i;
12854
12855 assert(vars != NULL || nvars == 0);
12856
12857 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
12858 for( i = 0; i < nvars; ++i )
12859 {
12860 SCIP_EXPR* varexpr;
12861 SCIP_EXPR* powexpr;
12862
12863 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
12864 if( offsets != NULL && offsets[i] != 0.0 )
12865 {
12866 SCIP_EXPR* sum;
12867 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
12868 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
12869 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12870 }
12871 else
12872 {
12873 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
12874 }
12875
12876 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
12877 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12878 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
12879 }
12880
12881 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
12882 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
12883 termcoefs[0] = 1.0;
12884
12885 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
12886 termcoefs[1] = -rhscoeff;
12887
12888 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
12889
12890 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12891 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12892
12893 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
12894
12895 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12896
12897 return SCIP_OKAY;
12898}
12899
12900/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12901 *
12902 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12903 *
12904 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12905 */
12907 SCIP* scip, /**< SCIP data structure */
12908 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12909 const char* name, /**< name of constraint */
12910 SCIP_VAR* x, /**< nonlinear variable x in constraint */
12911 SCIP_VAR* z, /**< linear variable z in constraint */
12912 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
12913 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
12914 SCIP_Real zcoef, /**< coefficient of z in constraint */
12915 SCIP_Real lhs, /**< left hand side of constraint */
12916 SCIP_Real rhs /**< right hand side of constraint */
12917 )
12918{
12919 SCIP_EXPR* xexpr;
12920 SCIP_EXPR* terms[2];
12921 SCIP_Real coefs[2];
12922 SCIP_EXPR* sumexpr;
12923
12924 assert(x != NULL);
12925 assert(z != NULL);
12926
12927 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
12928 if( xoffset != 0.0 )
12929 {
12930 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12931 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12932
12933 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12934 }
12935 else
12936 {
12937 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
12938 }
12939 coefs[0] = 1.0;
12940
12941 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
12942 coefs[1] = zcoef;
12943
12944 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
12945
12946 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12947
12948 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12949 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12950 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12951 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
12952
12953 return SCIP_OKAY;
12954}
12955
12956/** gets tag indicating current local variable bounds */
12958 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12959 )
12960{
12961 SCIP_CONSHDLRDATA* conshdlrdata;
12962
12963 assert(conshdlr != NULL);
12964 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12965
12966 return conshdlrdata->curboundstag;
12967}
12968
12969/** gets the `curboundstag` from the last time where variable bounds were relaxed */
12971 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12972 )
12973{
12974 SCIP_CONSHDLRDATA* conshdlrdata;
12975
12976 assert(conshdlr != NULL);
12977 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12978
12979 return conshdlrdata->lastboundrelax;
12980}
12981
12982/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12983 *
12984 * @attention This method is not intended for normal use.
12985 * These tags are maintained by the event handler for variable bound change events.
12986 * This method is used by some unittests.
12987 */
12989 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12990 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12991 )
12992{
12993 SCIP_CONSHDLRDATA* conshdlrdata;
12994
12995 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12996 assert(conshdlrdata != NULL);
12997
12998 ++conshdlrdata->curboundstag;
12999 assert(conshdlrdata->curboundstag > 0);
13000
13001 if( boundrelax )
13002 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13003}
13004
13005/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13007 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13008 )
13009{
13010 assert(conshdlr != NULL);
13011
13012 return SCIPconshdlrGetData(conshdlr)->var2expr;
13013}
13014
13015/** processes a rowprep for cut addition and maybe report branchscores */
13017 SCIP* scip, /**< SCIP data structure */
13018 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13019 SCIP_CONS* cons, /**< nonlinear constraint */
13020 SCIP_EXPR* expr, /**< expression */
13021 SCIP_ROWPREP* rowprep, /**< cut to be added */
13022 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13023 SCIP_VAR* auxvar, /**< auxiliary variable */
13024 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13025 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13026 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13027 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13028 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13029 SCIP_RESULT* result /**< pointer to store the result */
13030 )
13031{
13032 SCIP_Real cutviol;
13033 SCIP_CONSHDLRDATA* conshdlrdata;
13034 SCIP_Real auxvarvalue = SCIP_INVALID;
13035 SCIP_Bool sepasuccess;
13036 SCIP_Real estimateval = SCIP_INVALID;
13037 SCIP_Real mincutviolation;
13038
13039 assert(nlhdlr != NULL);
13040 assert(cons != NULL);
13041 assert(expr != NULL);
13042 assert(rowprep != NULL);
13043 assert(auxvar != NULL);
13044 assert(result != NULL);
13045
13046 /* decide on minimal violation of cut */
13047 if( sol == NULL )
13048 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13049 else
13050 mincutviolation = SCIPfeastol(scip);
13051
13052 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13053 assert(conshdlrdata != NULL);
13054
13055 sepasuccess = TRUE;
13056
13057 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13058 if( cutviol > 0.0 )
13059 {
13060 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13061
13062 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13063 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13064 {
13065 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13066 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13067 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13068 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13069 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13070 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13071 *
13072 * if we are overestimating, we have z >= c'x-b >= f(x)
13073 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13074 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13075 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13076 *
13077 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13078 */
13079 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13080 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13081 {
13082 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13083 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13084 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13085 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13086 sepasuccess = FALSE;
13087 }
13088 }
13089
13090 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13091 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13092 }
13093 else
13094 {
13095 sepasuccess = FALSE;
13096 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13097 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13098 }
13099
13100 /* clean up estimator */
13101 if( sepasuccess )
13102 {
13103 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13104 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13105 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13106 SCIPprintRowprep(scip, rowprep, enfologfile); )
13107
13108 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13109 * instead, may even scale them down, that is, scale so that max coef is close to 1
13110 */
13111 if( !allowweakcuts )
13112 {
13113 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13114
13115 if( !sepasuccess )
13116 {
13117 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13118 }
13119 else
13120 {
13121 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13122 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13123 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13124 if( sepasuccess )
13125 sepasuccess = cutviol > mincutviolation;
13126 }
13127
13128 if( sepasuccess && auxvalue != SCIP_INVALID )
13129 {
13130 /* check whether cut is weak now
13131 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13132 * reconstructing estimateval from cutviol (TODO improve or remove?)
13133 */
13134 SCIP_Real auxvarcoef = 0.0;
13135 int i;
13136
13137 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13138 * it should be...
13139 */
13140 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13141 {
13142 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13143 {
13144 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13145 break;
13146 }
13147 }
13148
13149 if( auxvarcoef == 0.0 ||
13150 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13151 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13152 {
13153 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13154 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13155 sepasuccess = FALSE;
13156 }
13157 }
13158 }
13159 else
13160 {
13161 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13162
13163 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13164 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13165 */
13166 if( !branchscoresuccess )
13168
13169 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13170
13171 if( !sepasuccess )
13172 {
13173 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13174 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13175 }
13176
13177 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13178 * changed
13179 */
13180 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13181 {
13182 SCIP_Real violscore;
13183
13184#ifdef BRSCORE_ABSVIOL
13185 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13186#else
13187 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13188#endif
13189 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13190
13191 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13192 * - were fixed,
13193 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13194 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13195 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13196 * so I'm disabling the assert for now
13197 */
13198 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13199 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13200 }
13201 }
13202 }
13203
13204 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13205 if( sepasuccess )
13206 {
13207 SCIP_ROW* row;
13208
13209 if( conshdlrdata->branchdualweight > 0.0 )
13210 {
13211 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13212 * skip if gap is zero
13213 */
13214 if( auxvalue == SCIP_INVALID )
13215 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13216 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13217 {
13218 char gap[40];
13219 /* coverity[secure_coding] */
13220 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13221 strcat(SCIProwprepGetName(rowprep), gap);
13222 }
13223 }
13224
13225 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13226
13227 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13228 {
13229 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13231 }
13232 else if( !SCIPisCutApplicable(scip, row) )
13233 {
13234 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13235 }
13236 else
13237 {
13238 SCIP_Bool infeasible;
13239
13240 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13241 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13242
13243 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13244 * if we haven't found strong cuts before)
13245 */
13246 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13247
13248 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13249 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13251
13252 if( infeasible )
13253 {
13254 *result = SCIP_CUTOFF;
13256 }
13257 else
13258 {
13259 *result = SCIP_SEPARATED;
13261 }
13262 }
13263
13264 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13265 }
13266 else if( branchscoresuccess )
13267 {
13268 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13269 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13270
13271 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13272 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13273 */
13274 *result = SCIP_BRANCHED;
13275 }
13276 else
13277 {
13278 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13279 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13280 " (!)" : ""); )
13281 }
13282
13283 return SCIP_OKAY;
13284}
13285
13286/** returns whether all nonlinear constraints are assumed to be convex */
13288 SCIP_CONSHDLR* conshdlr
13289 )
13290{
13291 SCIP_CONSHDLRDATA* conshdlrdata;
13292
13293 assert(conshdlr != NULL);
13294
13295 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13296 assert(conshdlrdata != NULL);
13297
13298 return conshdlrdata->assumeconvex;
13299}
13300
13301/** collects all bilinear terms for a given set of constraints
13302 *
13303 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13304 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13305 */
13307 SCIP* scip, /**< SCIP data structure */
13308 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13309 SCIP_CONS** conss, /**< nonlinear constraints */
13310 int nconss /**< total number of nonlinear constraints */
13311 )
13312{
13313 assert(conshdlr != NULL);
13314 assert(conss != NULL || nconss == 0);
13315
13316 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13317
13318 return SCIP_OKAY;
13319}
13320
13321/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13322 *
13323 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13324 */
13326 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13327 )
13328{
13329 SCIP_CONSHDLRDATA* conshdlrdata;
13330
13331 assert(conshdlr != NULL);
13332
13333 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13334 assert(conshdlrdata != NULL);
13335
13336 return conshdlrdata->nbilinterms;
13337}
13338
13339/** returns all bilinear terms that are contained in all nonlinear constraints
13340 *
13341 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13342 * @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.
13343 */
13345 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13346 )
13347{
13348 SCIP_CONSHDLRDATA* conshdlrdata;
13349
13350 assert(conshdlr != NULL);
13351
13352 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13353 assert(conshdlrdata != NULL);
13354
13355 return conshdlrdata->bilinterms;
13356}
13357
13358/** returns the index of the bilinear term representing the product of the two given variables
13359 *
13360 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13361 * @return The method returns -1 if the variables do not appear bilinearly.
13362 */
13364 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13365 SCIP_VAR* x, /**< first variable */
13366 SCIP_VAR* y /**< second variable */
13367 )
13368{
13369 SCIP_CONSHDLRDATA* conshdlrdata;
13371 int idx;
13372
13373 assert(conshdlr != NULL);
13374 assert(x != NULL);
13375 assert(y != NULL);
13376
13377 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13378 assert(conshdlrdata != NULL);
13379
13380 if( conshdlrdata->bilinhashtable == NULL )
13381 {
13382 return -1;
13383 }
13384
13385 /* ensure that x.index <= y.index */
13386 if( SCIPvarCompare(x, y) == 1 )
13387 {
13388 SCIPswapPointers((void**)&x, (void**)&y);
13389 }
13390 assert(SCIPvarCompare(x, y) < 1);
13391
13392 /* use a new entry to find the image in the bilinear hash table */
13393 entry.x = x;
13394 entry.y = y;
13395 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13396 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13397 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13398 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13399
13400 return idx;
13401}
13402
13403/** returns the bilinear term that represents the product of two given variables
13404 *
13405 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13406 * @return The method returns NULL if the variables do not appear bilinearly.
13407 */
13409 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13410 SCIP_VAR* x, /**< first variable */
13411 SCIP_VAR* y /**< second variable */
13412 )
13413{
13414 SCIP_CONSHDLRDATA* conshdlrdata;
13415 int idx;
13416
13417 assert(conshdlr != NULL);
13418 assert(x != NULL);
13419 assert(y != NULL);
13420
13421 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13422 assert(conshdlrdata != NULL);
13423
13424 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13425 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13426
13427 if( idx >= 0 )
13428 {
13429 return &conshdlrdata->bilinterms[idx];
13430 }
13431
13432 return NULL;
13433}
13434
13435/** evaluates an auxiliary expression for a bilinear term */
13437 SCIP* scip, /**< SCIP data structure */
13438 SCIP_VAR* x, /**< first variable of the bilinear term */
13439 SCIP_VAR* y, /**< second variable of the bilinear term */
13440 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13441 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13442 )
13443{
13444 assert(scip != NULL);
13445 assert(x != NULL);
13446 assert(y != NULL);
13447 assert(auxexpr != NULL);
13448 assert(auxexpr->auxvar != NULL);
13449
13450 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13451 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13452}
13453
13454/** stores the variables of a bilinear term in the data of the constraint handler */
13456 SCIP* scip, /**< SCIP data structure */
13457 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13458 SCIP_VAR* x, /**< first variable */
13459 SCIP_VAR* y, /**< second variable */
13460 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13461 int nlockspos, /**< number of positive expression locks */
13462 int nlocksneg /**< number of negative expression locks */
13463 )
13464{
13465 SCIP_CONSHDLRDATA* conshdlrdata;
13467 int idx;
13468
13469 assert(conshdlr != NULL);
13470
13471 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13472 assert(conshdlrdata != NULL);
13473
13474 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13475
13476 term = &conshdlrdata->bilinterms[idx];
13477 assert(term != NULL);
13478 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13479 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) */
13480
13481 /* store and capture auxiliary variable */
13482 if( auxvar != NULL )
13483 {
13484 term->aux.var = auxvar;
13485 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13486 }
13487
13488 return SCIP_OKAY;
13489}
13490
13491/** stores the variables of a bilinear term in the data of the constraint handler */
13493 SCIP* scip, /**< SCIP data structure */
13494 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13495 SCIP_VAR* x, /**< first variable */
13496 SCIP_VAR* y, /**< second variable */
13497 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13498 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13499 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13500 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13501 SCIP_Real cst, /**< constant of the auxiliary expression */
13502 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13503 )
13504{
13505 SCIP_CONSHDLRDATA* conshdlrdata;
13508 int idx;
13509 int nlockspos;
13510 int nlocksneg;
13511 SCIP_Bool added;
13512
13513 assert(conshdlr != NULL);
13514
13515 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13516 assert(conshdlrdata != NULL);
13517
13518 nlockspos = overestimate ? 1 : 0;
13519 nlocksneg = overestimate ? 0 : 1;
13520
13521 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13522
13523 term = &conshdlrdata->bilinterms[idx];
13524 assert(term != NULL);
13525 assert(SCIPvarCompare(term->x, term->y) < 1);
13526
13527 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13528 {
13529 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13530 /* this is the case where we are adding an implicitly defined relation for a product that has already
13531 * been explicitly defined; convert auxvar into an auxexpr */
13532
13533 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13534 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13535 return SCIP_OKAY;
13536
13537 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13538 auxvarexpr->cst = 0.0;
13539 auxvarexpr->coefs[0] = 1.0;
13540 auxvarexpr->coefs[1] = 0.0;
13541 auxvarexpr->coefs[2] = 0.0;
13542 auxvarexpr->auxvar = term->aux.var;
13543 auxvarexpr->underestimate = term->nlocksneg > 0;
13544 auxvarexpr->overestimate = term->nlockspos > 0;
13545
13546 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13547 term->aux.exprs = NULL;
13548
13549 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13550
13551 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13552 assert(added);
13553 }
13554
13555 /* create and add auxexpr */
13556 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13557 auxexpr->underestimate = !overestimate;
13558 auxexpr->overestimate = overestimate;
13559 auxexpr->auxvar = auxvar;
13560 auxexpr->coefs[0] = coefaux;
13561 if( term->x == x )
13562 {
13563 assert(term->y == y);
13564 auxexpr->coefs[1] = coefx;
13565 auxexpr->coefs[2] = coefy;
13566 }
13567 else
13568 {
13569 assert(term->x == y);
13570 assert(term->y == x);
13571 auxexpr->coefs[1] = coefy;
13572 auxexpr->coefs[2] = coefx;
13573 }
13574 auxexpr->cst = cst;
13575 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13576
13577 if( !added )
13578 {
13579 SCIPfreeBlockMemory(scip, &auxexpr);
13580 }
13581 else if( auxvar != NULL )
13582 { /* capture auxiliary variable */
13583 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13584 }
13585
13586 return SCIP_OKAY;
13587}
13588
13589/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13591 SCIP* scip, /**< SCIP data structure */
13592 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13593 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13594 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13595 void* fundata, /**< data for function evaluation (can be NULL) */
13596 SCIP_Real* xstar, /**< point to be separated */
13597 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13598 int nallvars, /**< half of the length of box */
13599 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13600 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13601 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13602 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13603 )
13604{
13605 SCIP_Real* corner;
13606 SCIP_Real* funvals;
13607 int* nonfixedpos;
13608 SCIP_Real maxfaceterror;
13609 int nvars; /* number of nonfixed variables */
13610 unsigned int ncorners;
13611 unsigned int i;
13612 int j;
13613
13614 assert(scip != NULL);
13615 assert(conshdlr != NULL);
13616 assert(function != NULL);
13617 assert(xstar != NULL);
13618 assert(box != NULL);
13619 assert(success != NULL);
13620 assert(facetcoefs != NULL);
13621 assert(facetconstant != NULL);
13622
13623 *success = FALSE;
13624
13625 /* identify fixed variables */
13626 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13627 nvars = 0;
13628 for( j = 0; j < nallvars; ++j )
13629 {
13630 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13631 continue;
13632 nonfixedpos[nvars] = j;
13633 nvars++;
13634 }
13635
13636 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13637 * if too many variables are not fixed, then we do nothing currently
13638 */
13639 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13640 {
13641 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13642 SCIPfreeBufferArray(scip, &nonfixedpos);
13643 return SCIP_OKAY;
13644 }
13645
13646 /* compute f(v^i) for each corner v^i of [l,u] */
13647 ncorners = POWEROFTWO(nvars);
13648 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13649 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13650 for( j = 0; j < nallvars; ++j )
13651 {
13652 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13653 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13654 }
13655 for( i = 0; i < ncorners; ++i )
13656 {
13657 SCIPdebugMsg(scip, "corner %u: ", i);
13658 for( j = 0; j < nvars; ++j )
13659 {
13660 int varpos = nonfixedpos[j];
13661 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13662 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13663 */
13664 if( (i >> j) & 0x1 )
13665 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13666 else
13667 corner[varpos] = box[2 * varpos ]; /* lb of var */
13668 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13669 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13670 }
13671
13672 funvals[i] = function(corner, nallvars, fundata);
13673
13674 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13675
13676 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13677 {
13678 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13679 goto CLEANUP;
13680 }
13681 }
13682
13683 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13684 BMSclearMemoryArray(facetcoefs, nallvars);
13685
13686 if( nvars == 1 )
13687 {
13688 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13689
13690 /* check whether target has been missed */
13691 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13692 {
13693 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13694 *success = FALSE;
13695 }
13696 }
13697 else if( nvars == 2 && SCIPlapackIsAvailable() )
13698 {
13699 int idx1 = nonfixedpos[0];
13700 int idx2 = nonfixedpos[1];
13701 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13702 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13703 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13704 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13705 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13706 SCIP_Real coefs[2] = { 0.0, 0.0 };
13707
13708 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13709
13710 facetcoefs[idx1] = coefs[0];
13711 facetcoefs[idx2] = coefs[1];
13712 }
13713 else
13714 {
13715 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13716 }
13717 if( !*success )
13718 {
13719 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13720 goto CLEANUP;
13721 }
13722
13723 /*
13724 * check and adjust facet with the algorithm of Rikun et al.
13725 */
13726
13727 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13728
13729 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13730 if( maxfaceterror > 0.0 )
13731 {
13732 SCIP_CONSHDLRDATA* conshdlrdata;
13733 SCIP_Real midval;
13734 SCIP_Real feastol;
13735
13737
13738 /* evaluate function in middle point to get some idea for a scaling */
13739 for( j = 0; j < nvars; ++j )
13740 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13741 midval = function(corner, nallvars, fundata);
13742 if( midval == SCIP_INVALID )
13743 midval = 1.0;
13744
13745 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13746 assert(conshdlrdata != NULL);
13747
13748 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13749 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13750 {
13751 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13752 *success = FALSE;
13753 goto CLEANUP;
13754 }
13755
13756 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13757
13758 if( overestimate )
13759 *facetconstant += maxfaceterror;
13760 else
13761 *facetconstant -= maxfaceterror;
13762 }
13763
13764 /* if we made it until here, then we have a nice facet */
13765 assert(*success);
13766
13767CLEANUP:
13768 /* free allocated memory */
13769 SCIPfreeBufferArray(scip, &corner);
13770 SCIPfreeBufferArray(scip, &funvals);
13771 SCIPfreeBufferArray(scip, &nonfixedpos);
13772
13773 return SCIP_OKAY;
13774}
13775
13776/*
13777 * constraint specific interface methods
13778 */
13779
13780/** returns the expression of the given nonlinear constraint */
13782 SCIP_CONS* cons /**< constraint data */
13783 )
13784{
13785 SCIP_CONSDATA* consdata;
13786
13787 assert(cons != NULL);
13788 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13789
13790 consdata = SCIPconsGetData(cons);
13791 assert(consdata != NULL);
13792
13793 return consdata->expr;
13794}
13795
13796/** gets the left hand side of a nonlinear constraint */
13798 SCIP_CONS* cons /**< constraint data */
13799 )
13800{
13801 SCIP_CONSDATA* consdata;
13802
13803 assert(cons != NULL);
13804 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13805
13806 consdata = SCIPconsGetData(cons);
13807 assert(consdata != NULL);
13808
13809 return consdata->lhs;
13810}
13811
13812/** gets the right hand side of a nonlinear constraint */
13814 SCIP_CONS* cons /**< constraint data */
13815 )
13816{
13817 SCIP_CONSDATA* consdata;
13818
13819 assert(cons != NULL);
13820 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13821
13822 consdata = SCIPconsGetData(cons);
13823 assert(consdata != NULL);
13824
13825 return consdata->rhs;
13826}
13827
13828/** gets the nonlinear constraint as a nonlinear row representation. */
13830 SCIP* scip, /**< SCIP data structure */
13831 SCIP_CONS* cons, /**< constraint */
13832 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13833 )
13834{
13835 SCIP_CONSDATA* consdata;
13836
13837 assert(cons != NULL);
13838 assert(nlrow != NULL);
13839 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13840
13841 consdata = SCIPconsGetData(cons);
13842 assert(consdata != NULL);
13843
13844 if( consdata->nlrow == NULL )
13845 {
13846 SCIP_CALL( createNlRow(scip, cons) );
13847 }
13848 assert(consdata->nlrow != NULL);
13849 *nlrow = consdata->nlrow;
13850
13851 return SCIP_OKAY;
13852}
13853
13854/** returns the curvature of the expression of a given nonlinear constraint
13855 *
13856 * @note The curvature information is computed during CONSINITSOL.
13857 */
13859 SCIP_CONS* cons /**< constraint data */
13860 )
13861{
13862 SCIP_CONSDATA* consdata;
13863
13864 assert(cons != NULL);
13865 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13866
13867 consdata = SCIPconsGetData(cons);
13868 assert(consdata != NULL);
13869
13870 return consdata->curv;
13871}
13872
13873/** checks whether expression of constraint can be represented as quadratic form
13874 *
13875 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13876 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13877 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13878 */
13880 SCIP* scip, /**< SCIP data structure */
13881 SCIP_CONS* cons, /**< constraint data */
13882 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
13883 )
13884{
13885 SCIP_CONSDATA* consdata;
13886
13887 assert(scip != NULL);
13888 assert(cons != NULL);
13889 assert(isquadratic != NULL);
13890 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13891
13892 consdata = SCIPconsGetData(cons);
13893 assert(consdata != NULL);
13894 assert(consdata->expr != NULL);
13895
13896 /* check whether constraint expression is quadratic in extended formulation */
13897 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13898
13899 /* if not quadratic in non-extended formulation, then do indicate quadratic */
13900 if( *isquadratic )
13901 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
13902
13903 return SCIP_OKAY;
13904}
13905
13906/** changes left-hand-side of a nonlinear constraint
13907 *
13908 * @attention This method can only be called in the problem stage.
13909 */
13911 SCIP* scip, /**< SCIP data structure */
13912 SCIP_CONS* cons, /**< constraint data */
13913 SCIP_Real lhs /**< new left-hand-side */
13914 )
13915{
13916 SCIP_CONSDATA* consdata;
13917
13918 assert(scip != NULL);
13919 assert(cons != NULL);
13920 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13921
13923 {
13924 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13925 return SCIP_INVALIDCALL;
13926 }
13927
13928 /* we should have an original constraint */
13929 assert(SCIPconsIsOriginal(cons));
13930
13931 consdata = SCIPconsGetData(cons);
13932 assert(consdata != NULL);
13933
13934 if( consdata->lhs == lhs )
13935 return SCIP_OKAY;
13936
13937 consdata->lhs = lhs;
13938
13939 /* not sure we care about any of these flags for original constraints */
13940 consdata->ispropagated = FALSE;
13941
13942 return SCIP_OKAY;
13943}
13944
13945/** changes right-hand-side of a nonlinear constraint
13946 *
13947 * @attention This method can only be called in the problem stage.
13948 */
13950 SCIP* scip, /**< SCIP data structure */
13951 SCIP_CONS* cons, /**< constraint data */
13952 SCIP_Real rhs /**< new right-hand-side */
13953 )
13954{
13955 SCIP_CONSDATA* consdata;
13956
13957 assert(scip != NULL);
13958 assert(cons != NULL);
13959 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13960
13962 {
13963 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13964 return SCIP_INVALIDCALL;
13965 }
13966
13967 /* we should have an original constraint */
13968 assert(SCIPconsIsOriginal(cons));
13969
13970 consdata = SCIPconsGetData(cons);
13971 assert(consdata != NULL);
13972
13973 if( consdata->rhs == rhs )
13974 return SCIP_OKAY;
13975
13976 consdata->rhs = rhs;
13977
13978 /* not sure we care about any of these flags for original constraints */
13979 consdata->ispropagated = FALSE;
13980
13981 return SCIP_OKAY;
13982}
13983
13984/** changes expression of a nonlinear constraint
13985 *
13986 * @attention This method can only be called in the problem stage.
13987 */
13989 SCIP* scip, /**< SCIP data structure */
13990 SCIP_CONS* cons, /**< constraint data */
13991 SCIP_EXPR* expr /**< new expression */
13992 )
13993{
13994 SCIP_CONSHDLR* conshdlr;
13995 SCIP_CONSDATA* consdata;
13996
13997 assert(scip != NULL);
13998 assert(cons != NULL);
13999 assert(expr != NULL);
14000
14002 {
14003 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14004 return SCIP_INVALIDCALL;
14005 }
14006
14007 /* we should have an original constraint */
14008 assert(SCIPconsIsOriginal(cons));
14009
14010 conshdlr = SCIPconsGetHdlr(cons);
14011 assert(conshdlr != NULL);
14012 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14013
14014 consdata = SCIPconsGetData(cons);
14015 assert(consdata != NULL);
14016 assert(consdata->expr != NULL);
14017
14018 /* we should not have collected additional data for the expr
14019 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14020 */
14021 assert(consdata->nvarexprs == 0);
14022 assert(consdata->varexprs == NULL);
14023 assert(!consdata->catchedevents);
14024
14025 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14026
14027 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14028 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14029
14030 /* not sure we care about any of these flags for original constraints */
14031 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14032 consdata->issimplified = FALSE;
14033 consdata->ispropagated = FALSE;
14034
14035 return SCIP_OKAY;
14036}
14037
14038/** adds coef * var to nonlinear constraint
14039 *
14040 * @attention This method can only be called in the problem stage.
14041 */
14043 SCIP* scip, /**< SCIP data structure */
14044 SCIP_CONS* cons, /**< constraint data */
14045 SCIP_VAR* var, /**< variable */
14046 SCIP_Real coef /**< coefficient */
14047 )
14048{
14049 SCIP_CONSHDLR* conshdlr;
14050 SCIP_CONSDATA* consdata;
14051 SCIP_EXPR* varexpr;
14052
14053 assert(scip != NULL);
14054 assert(cons != NULL);
14055
14057 {
14058 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14059 return SCIP_INVALIDCALL;
14060 }
14061
14062 /* we should have an original constraint */
14063 assert(SCIPconsIsOriginal(cons));
14064
14065 if( coef == 0.0 )
14066 return SCIP_OKAY;
14067
14068 conshdlr = SCIPconsGetHdlr(cons);
14069 assert(conshdlr != NULL);
14070 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14071
14072 consdata = SCIPconsGetData(cons);
14073 assert(consdata != NULL);
14074 assert(consdata->expr != NULL);
14075
14076 /* we should not have collected additional data for it
14077 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14078 */
14079 assert(consdata->nvarexprs == 0);
14080 assert(consdata->varexprs == NULL);
14081 assert(!consdata->catchedevents);
14082
14083 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14084
14085 /* append to sum, if consdata->expr is sum and not used anywhere else */
14086 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14087 {
14088 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14089 }
14090 else
14091 {
14092 /* create new expression = 1 * consdata->expr + coef * var */
14093 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14094 SCIP_Real coefs[2] = { 1.0, coef };
14095
14096 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14097
14098 /* release old root expr */
14099 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14100 }
14101
14102 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14103
14104 /* not sure we care about any of these flags for original constraints */
14105 consdata->issimplified = FALSE;
14106 consdata->ispropagated = FALSE;
14107
14108 return SCIP_OKAY;
14109}
14110
14111/** adds coef * expr to nonlinear constraint
14112 *
14113 * @attention This method can only be called in the problem stage.
14114 */
14116 SCIP* scip, /**< SCIP data structure */
14117 SCIP_CONS* cons, /**< nonlinear constraint */
14118 SCIP_EXPR* expr, /**< expression */
14119 SCIP_Real coef /**< coefficient */
14120 )
14121{
14122 SCIP_CONSHDLR* conshdlr;
14123 SCIP_CONSDATA* consdata;
14124 SCIP_EXPR* exprowned;
14125
14126 assert(scip != NULL);
14127 assert(cons != NULL);
14128
14130 {
14131 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14132 return SCIP_INVALIDCALL;
14133 }
14134
14135 /* we should have an original constraint */
14136 assert(SCIPconsIsOriginal(cons));
14137
14138 if( coef == 0.0 )
14139 return SCIP_OKAY;
14140
14141 conshdlr = SCIPconsGetHdlr(cons);
14142 assert(conshdlr != NULL);
14143 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14144
14145 consdata = SCIPconsGetData(cons);
14146 assert(consdata != NULL);
14147 assert(consdata->expr != NULL);
14148
14149 /* free quadratic representation, if any is stored */
14150 SCIPfreeExprQuadratic(scip, consdata->expr);
14151
14152 /* free varexprs in consdata, in case they have been stored
14153 * (e.g., by a call to consGet(N)VarsNonlinear)
14154 */
14155 SCIP_CALL( freeVarExprs(scip, consdata) );
14156
14157 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14158 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14159
14160 /* append to sum, if consdata->expr is sum and not used anywhere else */
14161 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14162 {
14163 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14164 }
14165 else
14166 {
14167 /* create new expression = 1 * consdata->expr + coef * var */
14168 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14169 SCIP_Real coefs[2] = { 1.0, coef };
14170
14171 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14172
14173 /* release old root expr */
14174 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14175 }
14176
14177 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14178
14179 /* not sure we care about any of these flags for original constraints */
14180 consdata->issimplified = FALSE;
14181 consdata->ispropagated = FALSE;
14182
14183 return SCIP_OKAY;
14184}
14185
14186/** computes value of constraint expression in a given solution
14187 *
14188 * Stores value of constraint expression in sol in activity.
14189 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14190 */
14192 SCIP* scip, /**< SCIP data structure */
14193 SCIP_CONS* cons, /**< constraint */
14194 SCIP_SOL* sol, /**< solution */
14195 SCIP_Real* activity /**< buffer to store computed activity */
14196 )
14197{
14198 SCIP_CONSDATA* consdata;
14199
14200 assert(cons != NULL);
14201 assert(activity != NULL);
14202
14203 consdata = SCIPconsGetData(cons);
14204 assert(consdata != NULL);
14205
14206 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14207 *activity = SCIPexprGetEvalValue(consdata->expr);
14208
14209 return SCIP_OKAY;
14210}
14211
14212/** gets absolute violation of nonlinear constraint
14213 *
14214 * This function evaluates the constraints in the given solution.
14215 *
14216 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14217 */
14219 SCIP* scip, /**< SCIP data structure */
14220 SCIP_CONS* cons, /**< constraint */
14221 SCIP_SOL* sol, /**< solution to check */
14222 SCIP_Real* viol /**< buffer to store computed violation */
14223 )
14224{
14225 assert(cons != NULL);
14226 assert(viol != NULL);
14227
14228 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14229 *viol = getConsAbsViolation(cons);
14230
14231 return SCIP_OKAY;
14232}
14233
14234/** gets scaled violation of nonlinear constraint
14235 *
14236 * This function evaluates the constraints in the given solution.
14237 *
14238 * The scaling that is applied to the absolute violation of the constraint
14239 * depends on the setting of parameter constraints/nonlinear/violscale.
14240 */
14242 SCIP* scip, /**< SCIP data structure */
14243 SCIP_CONS* cons, /**< constraint */
14244 SCIP_SOL* sol, /**< solution to check */
14245 SCIP_Real* viol /**< buffer to store computed violation */
14246 )
14247{
14248 assert(cons != NULL);
14249 assert(viol != NULL);
14250
14251 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14252 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14253
14254 return SCIP_OKAY;
14255}
14256
14257/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14259 SCIP* scip, /**< SCIP data structure */
14260 SCIP_CONS* cons, /**< nonlinear constraint */
14261 SCIP_VAR** var, /**< pointer to store the variable */
14262 SCIP_Real* coef /**< pointer to store the coefficient */
14263 )
14264{
14265 SCIP_CONSDATA* consdata;
14266
14267 assert(cons != NULL);
14268 assert(var != NULL);
14269 assert(coef != NULL);
14270
14271 /* check for a linear variable that can be increased or decreased without harming feasibility */
14273
14274 consdata = SCIPconsGetData(cons);
14275 assert(consdata != NULL);
14276
14277 *var = consdata->linvardecr;
14278 *coef = consdata->linvardecrcoef;
14279}
14280
14281/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14283 SCIP* scip, /**< SCIP data structure */
14284 SCIP_CONS* cons, /**< nonlinear constraint */
14285 SCIP_VAR** var, /**< pointer to store the variable */
14286 SCIP_Real* coef /**< pointer to store the coefficient */
14287 )
14288{
14289 SCIP_CONSDATA* consdata;
14290
14291 assert(cons != NULL);
14292 assert(var != NULL);
14293 assert(coef != NULL);
14294
14295 /* check for a linear variable that can be increased or decreased without harming feasibility */
14297
14298 consdata = SCIPconsGetData(cons);
14299 assert(consdata != NULL);
14300
14301 *var = consdata->linvarincr;
14302 *coef = consdata->linvarincrcoef;
14303}
14304
14305
14306/*
14307 * Methods for Expressions in Nonlinear Constraints
14308 */
14309
14310/** returns the number of positive rounding locks of an expression */
14312 SCIP_EXPR* expr /**< expression */
14313 )
14314{
14315 assert(expr != NULL);
14316 assert(SCIPexprGetOwnerData(expr) != NULL);
14317
14318 return SCIPexprGetOwnerData(expr)->nlockspos;
14319}
14320
14321/** returns the number of negative rounding locks of an expression */
14323 SCIP_EXPR* expr /**< expression */
14324 )
14325{
14326 assert(expr != NULL);
14327 assert(SCIPexprGetOwnerData(expr) != NULL);
14328
14329 return SCIPexprGetOwnerData(expr)->nlocksneg;
14330}
14331
14332/** returns the variable used for linearizing a given expression (return value might be NULL)
14333 *
14334 * @note for variable expression it returns the corresponding variable
14335 */
14337 SCIP_EXPR* expr /**< expression */
14338 )
14339{
14340 SCIP_EXPR_OWNERDATA* ownerdata;
14341
14342 assert(expr != NULL);
14343
14344 ownerdata = SCIPexprGetOwnerData(expr);
14345 assert(ownerdata != NULL);
14346
14347 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14348}
14349
14350/** returns the number of enforcements for an expression */
14352 SCIP_EXPR* expr /**< expression */
14353 )
14354{
14355 assert(expr != NULL);
14356 assert(SCIPexprGetOwnerData(expr) != NULL);
14357
14358 return SCIPexprGetOwnerData(expr)->nenfos;
14359}
14360
14361/** returns the data for one of the enforcements of an expression */
14363 SCIP_EXPR* expr, /**< expression */
14364 int idx, /**< position of enforcement in enfos array */
14365 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14366 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14367 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14368 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14369 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14370 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14371 )
14372{
14373 SCIP_EXPR_OWNERDATA* ownerdata;
14374
14375 assert(expr != NULL);
14376
14377 ownerdata = SCIPexprGetOwnerData(expr);
14378 assert(ownerdata != NULL);
14379 assert(idx >= 0);
14380 assert(idx < ownerdata->nenfos);
14381 assert(ownerdata->enfos[idx] != NULL);
14382 assert(nlhdlr != NULL);
14383
14384 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14385
14386 if( nlhdlrexprdata != NULL )
14387 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14388
14389 if( nlhdlrparticipation != NULL )
14390 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14391
14392 if( sepabelowusesactivity != NULL )
14393 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14394
14395 if( sepaaboveusesactivity != NULL )
14396 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14397
14398 if( auxvalue != NULL )
14399 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14400}
14401
14402/** sets the auxiliary value of expression for one of the enforcements of an expression */
14404 SCIP_EXPR* expr, /**< expression */
14405 int idx, /**< position of enforcement in enfos array */
14406 SCIP_Real auxvalue /**< the new value of auxval */
14407 )
14408{
14409 SCIP_EXPR_OWNERDATA* ownerdata;
14410
14411 assert(expr != NULL);
14412
14413 ownerdata = SCIPexprGetOwnerData(expr);
14414 assert(ownerdata != NULL);
14415
14416 assert(idx >= 0);
14417 assert(idx < ownerdata->nenfos);
14418 assert(ownerdata->enfos[idx] != NULL);
14419
14420 ownerdata->enfos[idx]->auxvalue = auxvalue;
14421}
14422
14423/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14424 *
14425 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14426 */
14428 SCIP_EXPR* expr /**< expression */
14429 )
14430{
14431 assert(expr != NULL);
14432 assert(SCIPexprGetOwnerData(expr) != NULL);
14433
14434 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14435}
14436
14437/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14438 *
14439 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14440 */
14442 SCIP_EXPR* expr /**< expression */
14443 )
14444{
14445 assert(expr != NULL);
14446 assert(SCIPexprGetOwnerData(expr) != NULL);
14447
14448 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14449}
14450
14451/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14452 *
14453 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14454 */
14456 SCIP_EXPR* expr /**< expression */
14457 )
14458{
14459 assert(expr != NULL);
14460 assert(SCIPexprGetOwnerData(expr) != NULL);
14461
14462 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14463}
14464
14465/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14466 *
14467 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14468 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14469 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14470 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14471 * and also increments this count for all variables in the expression.
14472 *
14473 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14474 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14475 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14476 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14477 */
14479 SCIP* scip, /**< SCIP data structure */
14480 SCIP_EXPR* expr, /**< expression */
14481 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14482 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14483 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14484 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14485 )
14486{
14487 SCIP_EXPR_OWNERDATA* ownerdata;
14488
14489 assert(expr != NULL);
14490
14491 ownerdata = SCIPexprGetOwnerData(expr);
14492 assert(ownerdata != NULL);
14493
14494 /* do not store auxvar request for variable expressions */
14495 if( useauxvar && SCIPisExprVar(scip, expr) )
14496 useauxvar = FALSE;
14497
14498 if( ownerdata->nenfos >= 0 &&
14499 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14500 (ownerdata->nauxvaruses == 0 && useauxvar)
14501 ) )
14502 {
14503 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14504 * we require additional enforcement methods, that is,
14505 * - activity of expr was not used before but will be used now, or
14506 * - auxiliary variable of expr was not required before but will be used now
14507 */
14508 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14509 }
14510
14511 if( useauxvar )
14512 ++ownerdata->nauxvaruses;
14513
14514 if( useactivityforprop )
14515 ++ownerdata->nactivityusesprop;
14516
14517 if( useactivityforsepabelow || useactivityforsepaabove )
14518 ++ownerdata->nactivityusessepa;
14519
14520 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14521 * information is used in detectNlhdlr()
14522 */
14523 if( useactivityforsepabelow )
14524 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14525 if( useactivityforsepaabove )
14526 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14527
14528 if( useactivityforprop )
14529 {
14530 /* if activity will be used for propagation, then make sure there is a valid activity
14531 * this way, we can do a reversepropcall after detectNlhdlr
14532 */
14534 }
14535
14536 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14537 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14538 {
14539 SCIP_EXPRITER* it;
14540
14541 /* create and initialize iterator */
14544
14545 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14546 if( SCIPisExprVar(scip, expr) )
14547 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14548
14549 /* free iterator */
14550 SCIPfreeExpriter(&it);
14551 }
14552
14553 return SCIP_OKAY;
14554}
14555
14556/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14557 *
14558 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14559 * Assume that f(x) is associated with auxiliary variable z.
14560 *
14561 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14562 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14563 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14564 *
14565 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14566 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14567 */
14569 SCIP* scip, /**< SCIP data structure */
14570 SCIP_EXPR* expr, /**< expression */
14571 SCIP_SOL* sol, /**< solution */
14572 SCIP_Longint soltag, /**< tag of solution */
14573 SCIP_Real* viol, /**< buffer to store computed violation */
14574 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14575 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14576 )
14577{
14578 assert(scip != NULL);
14579 assert(expr != NULL);
14580 assert(viol != NULL);
14581
14582 /* make sure expression has been evaluated */
14583 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14584
14585 /* get violation from internal method */
14586 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14587
14588 return SCIP_OKAY;
14589}
14590
14591/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14592 *
14593 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14594 * Assume that f(w) is associated with auxiliary variable z.
14595 *
14596 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14597 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14598 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14599 *
14600 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14601 * both `violover` and `violunder` are set to TRUE.
14602 */
14604 SCIP* scip, /**< SCIP data structure */
14605 SCIP_EXPR* expr, /**< expression */
14606 SCIP_Real auxvalue, /**< the value of f(w) */
14607 SCIP_SOL* sol, /**< solution that has been evaluated */
14608 SCIP_Real* viol, /**< buffer to store computed violation */
14609 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14610 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14611 )
14612{
14613 assert(scip != NULL);
14614 assert(expr != NULL);
14615 assert(viol != NULL);
14616
14617 /* get violation from internal method */
14618 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14619
14620 return SCIP_OKAY;
14621}
14622
14623
14624/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14625 *
14626 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14627 * Assume that f(w) is associated with auxiliary variable z.
14628 *
14629 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14630 * the absolute violation divided by max(1,|f(w)|).
14631 *
14632 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14633 * both `violover` and `violunder` are set to TRUE.
14634 */
14636 SCIP* scip, /**< SCIP data structure */
14637 SCIP_EXPR* expr, /**< expression */
14638 SCIP_Real auxvalue, /**< the value of f(w) */
14639 SCIP_SOL* sol, /**< solution that has been evaluated */
14640 SCIP_Real* viol, /**< buffer to store computed violation */
14641 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14642 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14643 )
14644{
14645 assert(scip != NULL);
14646 assert(expr != NULL);
14647 assert(viol != NULL);
14648
14649 /* get violation from internal method */
14650 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14651
14652 if( !SCIPisInfinity(scip, *viol) )
14653 {
14654 assert(auxvalue != SCIP_INVALID);
14655 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14656 *viol /= MAX(1.0, REALABS(auxvalue));
14657 }
14658
14659 return SCIP_OKAY;
14660}
14661
14662/** returns bounds on the expression
14663 *
14664 * This gives an intersection of bounds from
14665 * - activity calculation (SCIPexprGetActivity()), if valid,
14666 * - auxiliary variable, if present,
14667 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14668 *
14669 * @note The returned interval can be empty!
14670 */
14672 SCIP* scip, /**< SCIP data structure */
14673 SCIP_EXPR* expr /**< expression */
14674 )
14675{
14676 SCIP_EXPR_OWNERDATA* ownerdata;
14677 SCIP_CONSHDLRDATA* conshdlrdata;
14678 SCIP_INTERVAL bounds;
14679
14680 assert(scip != NULL);
14681 assert(expr != NULL);
14682
14683 ownerdata = SCIPexprGetOwnerData(expr);
14684 assert(ownerdata != NULL);
14685
14686 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14687 assert(conshdlrdata != NULL);
14688
14689 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14690
14691 /* start with propbounds if they belong to current propagation */
14692 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14693 {
14694 bounds = ownerdata->propbounds;
14695 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14696 }
14697 else
14699
14700 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14701 {
14702 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14703 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14705 }
14706
14707 if( ownerdata->auxvar != NULL )
14708 {
14709 /* apply auxiliary variable bounds to bounds */
14710 SCIP_INTERVAL auxvarbounds;
14711
14712 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14713 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14714 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14715 }
14716
14717 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14718
14719 return bounds;
14720}
14721
14722/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14723 * corresponding (auxiliary) variable (if any)
14724 *
14725 * @attention this function should only be called during domain propagation in cons_nonlinear
14726 */
14728 SCIP* scip, /**< SCIP data structure */
14729 SCIP_EXPR* expr, /**< expression to be tightened */
14730 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14731 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14732 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14733 )
14734{
14735 SCIP_EXPR_OWNERDATA* ownerdata;
14736 SCIP_CONSHDLRDATA* conshdlrdata;
14737
14738 assert(scip != NULL);
14739 assert(expr != NULL);
14740 assert(cutoff != NULL);
14741
14742 ownerdata = SCIPexprGetOwnerData(expr);
14743 assert(ownerdata != NULL);
14744 assert(ownerdata->conshdlr != NULL);
14745
14746 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14747 assert(conshdlrdata != NULL);
14748
14749 /* the code below assumes that current activity is valid
14750 * if it turns out that we cannot ensure that, then we should change code
14751 */
14752 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14754
14755 *cutoff = FALSE;
14756
14757#ifdef DEBUG_PROP
14758 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14759 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14760 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14761#endif
14762
14763 if( SCIPexprIsIntegral(expr) )
14764 {
14765 /* apply integrality to new bounds
14766 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14767 */
14768 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14769 newbounds.inf = SCIPceil(scip, newbounds.inf);
14770 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14771 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14772#ifdef DEBUG_PROP
14773 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14774#endif
14775 }
14776
14778 {
14779 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14780
14781 *cutoff = TRUE;
14782 return SCIP_OKAY;
14783 }
14784
14785 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14786 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14787 {
14788 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14789
14790 *cutoff = TRUE;
14791 return SCIP_OKAY;
14792 }
14793
14794 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14795 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14796 {
14797 /* if already having propbounds in expr, then tighten newbounds by propbounds */
14798 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14799 }
14800 else
14801 {
14802 /* first time we have propbounds for expr in this propagation rounds:
14803 * intersect with activity (though don't let it become empty if very close intervals)
14804 */
14805 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
14806 }
14807#ifdef DEBUG_PROP
14808 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14809#endif
14810
14811 /* check if the new bounds lead to an empty interval */
14813 {
14814 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14815
14816 *cutoff = TRUE;
14817 return SCIP_OKAY;
14818 }
14819
14820 /* if expr is not constant or variable, then store newbounds in expr->propbounds
14821 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14822 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14823 */
14824 if( SCIPexprGetNChildren(expr) > 0 )
14825 {
14826 ownerdata->propbounds = newbounds;
14827 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14828 }
14829
14830 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14831 * propagation or update of auxvar bounds
14832 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14833 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14834 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14835 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14836 * one or should we not even update propbounds to newbounds if the update is small?
14837 */
14838 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14839 {
14840#ifdef DEBUG_PROP
14841 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);
14842#endif
14843 return SCIP_OKAY;
14844 }
14845
14846 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14847 {
14848 /* add expression to propagation queue if not there yet and not var or constant and
14849 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14850 */
14851#ifdef DEBUG_PROP
14852 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14853#endif
14854 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14855 ownerdata->inpropqueue = TRUE;
14856 }
14857
14858 /* update bounds on variable or auxiliary variable */
14859 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14860
14861 return SCIP_OKAY;
14862}
14863
14864/** mark constraints that include this expression to be propagated again
14865 *
14866 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14867 * a change of variable bounds, e.g., because new information on the expression is available
14868 * that could potentially lead to tighter expression activity values.
14869 *
14870 * Note, that this call marks also constraints for propagation which only share some variable
14871 * with this expression.
14872 */
14874 SCIP* scip, /**< SCIP data structure */
14875 SCIP_EXPR* expr /**< expression to propagate again */
14876 )
14877{
14878 SCIP_EXPRITER* it;
14879 SCIP_CONSDATA* consdata;
14880 SCIP_EXPR_OWNERDATA* ownerdata;
14881 int c;
14882
14883 assert(scip != NULL);
14884 assert(expr != NULL);
14885
14886 ownerdata = SCIPexprGetOwnerData(expr);
14887 assert(ownerdata != NULL);
14888
14889 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14890
14893
14894 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14895 {
14896 if( !SCIPisExprVar(scip, expr) )
14897 continue;
14898
14899 ownerdata = SCIPexprGetOwnerData(expr);
14900 assert(ownerdata != NULL);
14901
14902 for( c = 0; c < ownerdata->nconss; ++c )
14903 {
14904 consdata = SCIPconsGetData(ownerdata->conss[c]);
14905 assert(consdata != NULL);
14906 consdata->ispropagated = FALSE;
14907 }
14908 }
14909
14910 SCIPfreeExpriter(&it);
14911
14912 return SCIP_OKAY;
14913}
14914
14915/** adds violation-branching score to an expression
14916 *
14917 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14918 * The expression must either be a variable expression or have an aux-variable.
14919 * In the latter case, branching on auxiliary variables must have been enabled.
14920 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14921 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14922 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14923 *
14924 * @see SCIPaddExprsViolScoreNonlinear()
14925 */
14927 SCIP* scip, /**< SCIP data structure */
14928 SCIP_EXPR* expr, /**< expression where to add branching score */
14929 SCIP_Real violscore /**< violation score to add to expression */
14930 )
14931{
14932 SCIP_EXPR_OWNERDATA* ownerdata;
14933 SCIP_CONSHDLRDATA* conshdlrdata;
14934
14935 assert(scip != NULL);
14936 assert(expr != NULL);
14937 assert(violscore >= 0.0);
14938
14939 ownerdata = SCIPexprGetOwnerData(expr);
14940 assert(ownerdata != NULL);
14941
14942 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14943 assert(conshdlrdata != NULL);
14944
14945 /* if not allowing to branch on auxvars, then expr must be a var-expr */
14946 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14947 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14948 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14949
14950 /* reset branching score if we are in a different enfo round */
14951 if( ownerdata->violscoretag != conshdlrdata->enforound )
14952 {
14953 ownerdata->violscoresum = violscore;
14954 ownerdata->violscoremax = violscore;
14955 ownerdata->nviolscores = 1;
14956 ownerdata->violscoretag = conshdlrdata->enforound;
14957 return;
14958 }
14959
14960 ownerdata->violscoresum += violscore;
14961 if( violscore > ownerdata->violscoremax )
14962 ownerdata->violscoremax = violscore;
14963 ++ownerdata->nviolscores;
14964}
14965
14966/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14967 *
14968 * Each expression must either be a variable expression or have an aux-variable.
14969 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14970 * variables present in `exprs`.
14971 */
14973 SCIP* scip, /**< SCIP data structure */
14974 SCIP_EXPR** exprs, /**< expressions where to add branching score */
14975 int nexprs, /**< number of expressions */
14976 SCIP_Real violscore, /**< violation score to add to expression */
14977 SCIP_SOL* sol, /**< current solution */
14978 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
14979 )
14980{
14981 SCIP_EXPRITER* it;
14982 SCIP_EXPR** varexprs;
14983 SCIP_EXPR* e;
14984 int nvars;
14985 int varssize;
14986 int i;
14987
14988 assert(exprs != NULL || nexprs == 0);
14989 assert(success != NULL);
14990
14991 if( nexprs == 0 )
14992 {
14993 *success = FALSE;
14994 return SCIP_OKAY;
14995 }
14996
14997 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
14998 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
14999 {
15000 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15001 return SCIP_OKAY;
15002 }
15003
15004 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15005 nvars = 0;
15006 varssize = 5;
15007 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15008
15011
15012 for( i = 0; i < nexprs; ++i )
15013 {
15014 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15015 {
15016 assert(e != NULL);
15017
15018 if( SCIPisExprVar(scip, e) )
15019 {
15020 /* add variable expression to vars array */
15021 if( varssize == nvars )
15022 {
15023 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15024 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15025 }
15026 assert(varssize > nvars);
15027
15028 varexprs[nvars++] = e;
15029 }
15030 }
15031 }
15032
15033 SCIPfreeExpriter(&it);
15034
15035 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15036
15037 SCIPfreeBufferArray(scip, &varexprs);
15038
15039 return SCIP_OKAY;
15040}
15041
15042/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15044 SCIP_EXPR* expr /**< expression */
15045 )
15046{
15047 SCIP_EXPR_OWNERDATA* ownerdata;
15048 SCIP_CONSHDLRDATA* conshdlrdata;
15049
15050 assert(expr != NULL);
15051
15052 ownerdata = SCIPexprGetOwnerData(expr);
15053 assert(ownerdata != NULL);
15054
15055 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15056 assert(conshdlrdata != NULL);
15057
15058 if( conshdlrdata->enforound != ownerdata->violscoretag )
15059 return 0.0;
15060
15061 if( ownerdata->nviolscores == 0 )
15062 return 0.0;
15063
15064 switch( conshdlrdata->branchscoreagg )
15065 {
15066 case 'a' :
15067 /* average */
15068 return ownerdata->violscoresum / ownerdata->nviolscores;
15069
15070 case 'm' :
15071 /* maximum */
15072 return ownerdata->violscoremax;
15073
15074 case 's' :
15075 /* sum */
15076 return ownerdata->violscoresum;
15077
15078 default:
15079 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15080 SCIPABORT();
15081 return SCIP_INVALID;
15082 }
15083}
15084
15085/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15086 *
15087 * @see SCIPexprGetDerivative()
15088 */
15090 SCIP* scip, /**< SCIP data structure */
15091 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15092 SCIP_VAR* var /**< variable (needs to be in the expression) */
15093 )
15094{
15095 SCIP_EXPR_OWNERDATA* ownerdata;
15096 SCIP_CONSHDLRDATA* conshdlrdata;
15097 SCIP_EXPR* varexpr;
15098
15099 assert(scip != NULL);
15100 assert(expr != NULL);
15101 assert(var != NULL);
15102
15103 /* return 0.0 for value expression */
15104 if( SCIPisExprValue(scip, expr) )
15105 {
15106 assert(SCIPexprGetDerivative(expr) == 0.0);
15107 return 0.0;
15108 }
15109
15110 /* check if an error occurred during the last SCIPevalExprGradient() call */
15111 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15112 return SCIP_INVALID;
15113
15114 ownerdata = SCIPexprGetOwnerData(expr);
15115 assert(ownerdata != NULL);
15116
15117 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15118 assert(conshdlrdata != NULL);
15119
15120 /* use variable to expressions mapping which is stored in the constraint handler data */
15121 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15122
15123 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15124 assert(varexpr != NULL);
15125 assert(SCIPisExprVar(scip, varexpr));
15126
15127 /* use difftag to decide whether the variable belongs to the expression */
15128 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15129}
15130
15131/** 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)
15132 *
15133 * @see SCIPexprGetBardot()
15134 */
15136 SCIP* scip, /**< SCIP data structure */
15137 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15138 SCIP_VAR* var /**< variable (needs to be in the expression) */
15139 )
15140{
15141 SCIP_EXPR_OWNERDATA* ownerdata;
15142 SCIP_CONSHDLRDATA* conshdlrdata;
15143 SCIP_EXPR* varexpr;
15144
15145 assert(scip != NULL);
15146 assert(expr != NULL);
15147 assert(var != NULL);
15148
15149 /* return 0.0 for value expression */
15150 if( SCIPisExprValue(scip, expr) )
15151 return 0.0;
15152
15153 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15154 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15155 return SCIP_INVALID;
15156
15157 ownerdata = SCIPexprGetOwnerData(expr);
15158 assert(ownerdata != NULL);
15159
15160 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15161 assert(conshdlrdata != NULL);
15162
15163 /* use variable to expressions mapping which is stored in the constraint handler data;
15164 * if this fails it means that we are asking for the var's component of H*u for a var
15165 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15166 */
15167 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15168
15169 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15170 assert(varexpr != NULL);
15171 assert(SCIPisExprVar(scip, varexpr));
15172
15173 /* use difftag to decide whether the variable belongs to the expression */
15174 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15175}
15176
15177/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15178 *
15179 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15180 */
15182 SCIP* scip, /**< SCIP data structure */
15183 SCIP_EXPR* expr, /**< quadratic expression */
15184 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15185 )
15186{
15187 SCIP_Real auxvalue;
15188 int nlinexprs;
15189 SCIP_Real* lincoefs;
15190 SCIP_EXPR** linexprs;
15191 int nquadexprs;
15192 int nbilinexprs;
15193 int i;
15194
15195 assert(scip != NULL);
15196 assert(expr != NULL);
15197
15198 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15199
15200 /* linear terms */
15201 for( i = 0; i < nlinexprs; ++i )
15202 {
15203 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15204 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15205 }
15206
15207 /* quadratic terms */
15208 for( i = 0; i < nquadexprs; ++i )
15209 {
15210 SCIP_EXPR* quadexprterm;
15211 SCIP_Real lincoef;
15212 SCIP_Real sqrcoef;
15213 SCIP_Real solval;
15214
15215 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15216
15217 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15218
15219 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15220 auxvalue += (lincoef + sqrcoef * solval) * solval;
15221 }
15222
15223 /* bilinear terms */
15224 for( i = 0; i < nbilinexprs; ++i )
15225 {
15226 SCIP_EXPR* expr1;
15227 SCIP_EXPR* expr2;
15228 SCIP_Real coef;
15229
15230 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15231
15232 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
15233 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
15234 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
15235 }
15236
15237 return auxvalue;
15238}
15239
15240/**@addtogroup PublicNlhdlrInterfaceMethods
15241 * @{
15242 */
15243
15244/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15246 SCIP* scip, /**< SCIP data structure */
15247 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15248 const char* name, /**< name of nonlinear handler (must not be NULL) */
15249 const char* desc, /**< description of nonlinear handler (can be NULL) */
15250 int detectpriority, /**< detection priority of nonlinear handler */
15251 int enfopriority, /**< enforcement priority of nonlinear handler */
15252 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15253 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15254 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15255 )
15256{
15257 SCIP_CONSHDLR* conshdlr;
15258 SCIP_CONSHDLRDATA* conshdlrdata;
15259
15260 assert(scip != NULL);
15261 assert(nlhdlr != NULL);
15262 assert(detect != NULL);
15263
15264 /* find myself */
15265 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15266 if( conshdlr == NULL )
15267 {
15268 SCIPerrorMessage("nonlinear constraint handler not found");
15269 return SCIP_PLUGINNOTFOUND;
15270 }
15271
15272 /* create nlhdlr */
15273 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15274
15275 /* include into constraint handler */
15276 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15277 assert(conshdlrdata != NULL);
15278
15279 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15280
15281 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15282 ++conshdlrdata->nnlhdlrs;
15283
15284 /* sort nonlinear handlers by detection priority, in decreasing order
15285 * will happen in INIT, so only do when called late
15286 */
15287 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15288 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15289
15290 return SCIP_OKAY;
15291}
15292
15293/** get number of nonlinear handler */
15295 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15296 )
15297{
15298 SCIP_CONSHDLRDATA* conshdlrdata;
15299
15300 assert(conshdlr != NULL);
15301
15302 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15303 assert(conshdlrdata != NULL);
15304
15305 return conshdlrdata->nnlhdlrs;
15306}
15307
15308/** get nonlinear handlers */
15310 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15311 )
15312{
15313 SCIP_CONSHDLRDATA* conshdlrdata;
15314
15315 assert(conshdlr != NULL);
15316
15317 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15318 assert(conshdlrdata != NULL);
15319
15320 return conshdlrdata->nlhdlrs;
15321}
15322
15323/** returns a nonlinear handler of a given name (or NULL if not found) */
15325 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15326 const char* name /**< name of nonlinear handler */
15327 )
15328{
15329 SCIP_CONSHDLRDATA* conshdlrdata;
15330 int h;
15331
15332 assert(conshdlr != NULL);
15333 assert(name != NULL);
15334
15335 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15336 assert(conshdlrdata != NULL);
15337
15338 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15339 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15340 return conshdlrdata->nlhdlrs[h];
15341
15342 return NULL;
15343}
15344
15345/** gives expression data that a given nonlinear handler stored in an expression
15346 *
15347 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15348 */
15350 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15351 SCIP_EXPR* expr /**< expression */
15352 )
15353{
15354 SCIP_EXPR_OWNERDATA* ownerdata;
15355 int e;
15356
15357 assert(nlhdlr != NULL);
15358 assert(expr != NULL);
15359
15360 ownerdata = SCIPexprGetOwnerData(expr);
15361 assert(ownerdata != NULL);
15362
15363 for( e = 0; e < ownerdata->nenfos; ++e )
15364 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15365 return ownerdata->enfos[e]->nlhdlrexprdata;
15366
15367 return NULL;
15368}
15369
15370/** @} */
SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
static GRAPHNODE ** active
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_VAR * w
Definition: circlepacking.c:67
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** y
Definition: circlepacking.c:64
SCIP_Real * r
Definition: circlepacking.c:59
SCIP_VAR ** x
Definition: circlepacking.c:63
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)
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
#define ENFOLOG(x)
#define DIALOG_DESC
static SCIP_RETCODE tryAddGadgetEvenOperatorVariable(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_Bool *success)
static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
#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_DECL_EXPR_OWNERPRINT(exprownerPrint)
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_DECL_CONSCHECK(consCheckNonlinear)
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)
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
#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_DECL_CONSENABLE(consEnableNonlinear)
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_DECL_CONSPARSE(consParseNonlinear)
static SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
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)
static SCIP_DECL_CONSLOCK(consLockNonlinear)
#define TABLE_DESC_NLHDLR
static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
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)
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
static SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
#define TABLE_EARLIEST_STAGE_NLHDLR
#define VERTEXPOLY_RANDNUMINITSEED
static SCIP_DECL_CONSINIT(consInitNonlinear)
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_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
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)
static SCIP_DECL_EVENTEXEC(processVarEvent)
#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_DECL_CONSSEPASOL(consSepasolNonlinear)
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_DECL_CONSCOPY(consCopyNonlinear)
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
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
#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_DECL_CONSINITLP(consInitlpNonlinear)
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_DECL_CONSSEPALP(consSepalpNonlinear)
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 selectBranchingCandidate(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol, BRANCHCAND **selected)
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
static SCIP_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
static SCIP_DECL_CONSTRANS(consTransNonlinear)
static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
#define VERTEXPOLY_MAXPERTURBATION
static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
static SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
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)
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define DIALOG_ISSUBMENU
static SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
static SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
#define VERTEXPOLY_USEDUALSIMPLEX
#define CONSHDLR_PROPFREQ
static SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
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_DECL_TABLEOUTPUT(tableOutputNonlinear)
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_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
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 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
static SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
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
static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
static SCIP_DECL_SORTINDCOMP(branchcandCompare)
static SCIP_Bool branchingIntegralFirst(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol)
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_DECL_CONSFREE(consFreeNonlinear)
static SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
static SCIP_DECL_CONSEXIT(consExitNonlinear)
#define CONSHDLR_DELAYPROP
static SCIP_DECL_CONSPROP(consPropNonlinear)
static SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
#define BILIN_MAXNAUXEXPRS
constraint handler for nonlinear constraints specified by algebraic expressions
Constraint handler for variable bound constraints .
methods for debugging
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:299
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:298
#define NULL
Definition: def.h:267
#define SCIP_MAXSTRLEN
Definition: def.h:288
#define SCIP_Longint
Definition: def.h:158
#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 SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define MAX3(x, y, z)
Definition: def.h:247
#define SCIP_Real
Definition: def.h:173
#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)
Definition: expr_varidx.c:252
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)
Definition: scip_general.c:633
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
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,...)
Definition: scip_message.c:208
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:191
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
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)
Definition: heur_trysol.c:252
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:1943
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)
Definition: scip_branch.c:665
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
Definition: scip_branch.c:897
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1126
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:395
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:849
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)
Definition: scip_dialog.c:124
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)
Definition: scip_dialog.c:171
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
Definition: scip_dialog.c:157
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:4042
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:3860
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4204
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:3921
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3960
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:3947
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition: expr.c:4079
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4240
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:4119
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:4089
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:3934
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:4032
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:3988
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3870
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:4016
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:4164
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:3850
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:4003
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:3883
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:7493
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
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_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:841
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)
Definition: scip_timing.c:144
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:178
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:127
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:319
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:161
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_Bool SCIPisFeasIntegral(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:5203
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip_var.c:4317
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17789
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:8950
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c: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:5320
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:1248
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4645
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:8814
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4613
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17610
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8176
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c: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:8715
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:1439
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1214
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
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
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_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:639
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:699
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
Definition: misc_rowprep.c:972
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:649
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:709
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:689
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:669
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:913
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:629
void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:791
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)
Definition: misc_rowprep.c:583
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
Definition: misc_rowprep.c:801
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
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)
Definition: lapack_calls.c:121
SCIP_RETCODE SCIPlapackSolveLinearEquations(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
Definition: lapack_calls.c:386
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)
Definition: pub_message.h:102
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
int nlockspos[NLOCKTYPES]
Definition: struct_cons.h:63
SCIP_Real sup
Definition: intervalarith.h:56
SCIP_Real inf
Definition: intervalarith.h:55
structs for symmetry computations
methods for dealing with symmetry detection graphs
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:156
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition: type_cons.h:919
#define SCIP_DECL_CONSRESPROP(x)
Definition: type_cons.h:611
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#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_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
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
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
@ 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_EXPRITER_LEAVEEXPR
Definition: type_expr.h:695
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:692
@ SCIP_BRANCHDIR_DOWNWARDS
Definition: type_history.h:43
@ SCIP_BRANCHDIR_UPWARDS
Definition: type_history.h:44
@ 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_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:52
#define SCIP_DECL_NLHDLREVALAUX(x)
Definition: type_nlhdlr.h:202
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:452
#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)
Definition: type_nlhdlr.h:177
#define SCIP_NLHDLR_METHOD_NONE
Definition: type_nlhdlr.h:50
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:453
#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
Definition: type_retcode.h:49
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ 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
Definition: type_symmetry.h:64
@ SYM_CONSOPTYPE_SUM
Definition: type_symmetry.h:83
@ SYM_CONSOPTYPE_COEF
Definition: type_symmetry.h:85
@ SYM_CONSOPTYPE_SQDIFF
Definition: type_symmetry.h:86
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
#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