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-2025 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 && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && 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_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 if( nexprs == 0 )
6315 {
6316 *success = FALSE;
6317 return;
6318 }
6319
6320 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6321
6322 for( i = 0; i < nexprs; ++i )
6323 {
6324 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6325 assert(var != NULL);
6326
6328 ++nunbounded;
6329 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6330 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6331 }
6332
6333 *success = FALSE;
6334 for( i = 0; i < nexprs; ++i )
6335 {
6336 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6337 assert(var != NULL);
6338
6339 if( nunbounded > 0 )
6340 {
6342 {
6343 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6344 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6345 100.0/nunbounded, violscore,
6347 *success = TRUE;
6348 }
6349 }
6350 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6351 {
6352 assert(weightsum > 0.0);
6353
6354 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6355 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6356 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6357 100*weight / weightsum, violscore,
6359 *success = TRUE;
6360 }
6361 else
6362 {
6363 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6365 }
6366 }
6367}
6368
6369/** adds violation-branching score to children of expression for given auxiliary variables
6370 *
6371 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6372 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6373 *
6374 * @note This method may modify the given auxvars array by means of sorting.
6375 */
6376static
6378 SCIP* scip, /**< SCIP data structure */
6379 SCIP_EXPR* expr, /**< expression where to start searching */
6380 SCIP_Real violscore, /**< violation score to add to expression */
6381 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6382 int nauxvars, /**< number of auxiliary variables */
6383 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6384 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6385 )
6386{
6387 SCIP_EXPRITER* it;
6388 SCIP_VAR* auxvar;
6389 SCIP_EXPR** exprs;
6390 int nexprs;
6391 int pos;
6392
6393 assert(scip != NULL);
6394 assert(expr != NULL);
6395 assert(auxvars != NULL);
6396 assert(success != NULL);
6397
6398 /* sort variables to make lookup below faster */
6399 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6400
6403
6404 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6405 nexprs = 0;
6406
6407 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6408 {
6409 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6410 if( auxvar == NULL )
6411 continue;
6412
6413 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6414 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6415 {
6416 assert(auxvars[pos] == auxvar);
6417
6418 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6419 exprs[nexprs++] = expr;
6420
6421 if( nexprs == nauxvars )
6422 break;
6423 }
6424 }
6425
6426 SCIPfreeExpriter(&it);
6427
6428 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6429
6430 SCIPfreeBufferArray(scip, &exprs);
6431
6432 return SCIP_OKAY;
6433}
6434
6435/** registers all unfixed variables in violated constraints as branching candidates */
6436static
6438 SCIP* scip, /**< SCIP data structure */
6439 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6440 SCIP_CONS** conss, /**< constraints */
6441 int nconss, /**< number of constraints */
6442 int* nnotify /**< counter for number of notifications performed */
6443 )
6444{
6445 SCIP_CONSDATA* consdata;
6446 SCIP_VAR* var;
6447 int c;
6448 int i;
6449
6450 assert(conshdlr != NULL);
6451 assert(conss != NULL || nconss == 0);
6452 assert(nnotify != NULL);
6453
6454 *nnotify = 0;
6455
6456 for( c = 0; c < nconss; ++c )
6457 {
6458 assert(conss != NULL && conss[c] != NULL);
6459
6460 consdata = SCIPconsGetData(conss[c]);
6461 assert(consdata != NULL);
6462
6463 /* consider only violated constraints */
6464 if( !isConsViolated(scip, conss[c]) )
6465 continue;
6466
6467 /* register all variables that have not been fixed yet */
6468 assert(consdata->varexprs != NULL);
6469 for( i = 0; i < consdata->nvarexprs; ++i )
6470 {
6471 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6472 assert(var != NULL);
6473
6475 {
6477 ++(*nnotify);
6478 }
6479 }
6480 }
6481
6482 return SCIP_OKAY;
6483}
6484
6485/** registers all variables in violated constraints with branching scores as external branching candidates */
6486static
6488 SCIP* scip, /**< SCIP data structure */
6489 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6490 SCIP_CONS** conss, /**< constraints */
6491 int nconss, /**< number of constraints */
6492 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6493 )
6494{
6495 SCIP_CONSDATA* consdata;
6496 SCIP_EXPRITER* it = NULL;
6497 int c;
6498
6499 assert(conshdlr != NULL);
6500 assert(success != NULL);
6501
6502 *success = FALSE;
6503
6504 if( branchAuxNonlinear(scip, conshdlr) )
6505 {
6508 }
6509
6510 /* register external branching candidates */
6511 for( c = 0; c < nconss; ++c )
6512 {
6513 assert(conss != NULL && conss[c] != NULL);
6514
6515 consdata = SCIPconsGetData(conss[c]);
6516 assert(consdata != NULL);
6517 assert(consdata->varexprs != NULL);
6518
6519 /* consider only violated constraints */
6520 if( !isConsViolated(scip, conss[c]) )
6521 continue;
6522
6523 if( !branchAuxNonlinear(scip, conshdlr) )
6524 {
6525 int i;
6526
6527 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6528 * only, so we can loop over variable expressions
6529 */
6530 for( i = 0; i < consdata->nvarexprs; ++i )
6531 {
6532 SCIP_Real violscore;
6533 SCIP_Real lb;
6534 SCIP_Real ub;
6535 SCIP_VAR* var;
6536
6537 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6538
6539 /* skip variable expressions that do not have a violation score */
6540 if( violscore == 0.0 )
6541 continue;
6542
6543 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6544 assert(var != NULL);
6545
6546 lb = SCIPvarGetLbLocal(var);
6547 ub = SCIPvarGetUbLocal(var);
6548
6549 /* consider variable for branching if it has not been fixed yet */
6550 if( !SCIPisEQ(scip, lb, ub) )
6551 {
6552 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6554 *success = TRUE;
6555 }
6556 else
6557 {
6558 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6559 }
6560
6561 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6562 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6563 */
6564 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6565 }
6566 }
6567 else
6568 {
6569 SCIP_EXPR* expr;
6570 SCIP_VAR* var;
6571 SCIP_Real lb;
6572 SCIP_Real ub;
6573 SCIP_Real violscore;
6574
6575 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6576 {
6577 violscore = SCIPgetExprViolScoreNonlinear(expr);
6578 if( violscore == 0.0 )
6579 continue;
6580
6581 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6582 * variable, so this expression should either be an original variable or have an auxiliary variable
6583 */
6584 var = SCIPgetExprAuxVarNonlinear(expr);
6585 assert(var != NULL);
6586
6587 lb = SCIPvarGetLbLocal(var);
6588 ub = SCIPvarGetUbLocal(var);
6589
6590 /* consider variable for branching if it has not been fixed yet */
6591 if( !SCIPisEQ(scip, lb, ub) )
6592 {
6593 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6594
6596 *success = TRUE;
6597 }
6598 else
6599 {
6600 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6601 }
6602 }
6603 }
6604 }
6605
6606 if( it != NULL )
6607 SCIPfreeExpriter(&it);
6608
6609 return SCIP_OKAY;
6610}
6611
6612/** collect branching candidates from violated constraints
6613 *
6614 * Fills array with expressions that serve as branching candidates.
6615 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6616 * branching candidate.
6617 *
6618 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6619 * through variable-expressions only.
6620 */
6621static
6623 SCIP* scip, /**< SCIP data structure */
6624 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6625 SCIP_CONS** conss, /**< constraints to process */
6626 int nconss, /**< number of constraints */
6627 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6628 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6629 SCIP_Longint soltag, /**< tag of solution */
6630 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6631 int* ncands /**< number of candidates found */
6632 )
6633{
6634 SCIP_CONSHDLRDATA* conshdlrdata;
6635 SCIP_CONSDATA* consdata;
6636 SCIP_EXPRITER* it = NULL;
6637 int c;
6638 int attempt;
6639 SCIP_VAR* var;
6640
6641 assert(scip != NULL);
6642 assert(conshdlr != NULL);
6643 assert(cands != NULL);
6644 assert(ncands != NULL);
6645
6646 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6647 assert(conshdlrdata != NULL);
6648
6649 if( branchAuxNonlinear(scip, conshdlr) )
6650 {
6653 }
6654
6655 *ncands = 0;
6656 for( attempt = 0; attempt < 2; ++attempt )
6657 {
6658 /* collect branching candidates from violated constraints
6659 * in the first attempt, consider only constraints with large violation
6660 * in the second attempt, consider all remaining violated constraints
6661 */
6662 for( c = 0; c < nconss; ++c )
6663 {
6664 SCIP_Real consviol;
6665
6666 assert(conss != NULL && conss[c] != NULL);
6667
6668 /* consider only violated constraints */
6669 if( !isConsViolated(scip, conss[c]) )
6670 continue;
6671
6672 consdata = SCIPconsGetData(conss[c]);
6673 assert(consdata != NULL);
6674 assert(consdata->varexprs != NULL);
6675
6676 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6677
6678 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6679 continue;
6680 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6681 continue;
6682
6683 if( !branchAuxNonlinear(scip, conshdlr) )
6684 {
6685 int i;
6686
6687 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6688 * only, so we can loop over variable expressions
6689 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6690 * variable, therefore we invalidate the score of a variable after processing it.
6691 */
6692 for( i = 0; i < consdata->nvarexprs; ++i )
6693 {
6694 SCIP_Real lb;
6695 SCIP_Real ub;
6696
6697 /* skip variable expressions that do not have a valid violation score */
6698 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6699 continue;
6700
6701 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6702 assert(var != NULL);
6703
6704 lb = SCIPvarGetLbLocal(var);
6705 ub = SCIPvarGetUbLocal(var);
6706
6707 /* skip already fixed variable */
6708 if( SCIPisEQ(scip, lb, ub) )
6709 {
6710 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6711 continue;
6712 }
6713
6714 assert(*ncands + 1 < SCIPgetNVars(scip));
6715 cands[*ncands].expr = consdata->varexprs[i];
6716 cands[*ncands].var = var;
6717 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6718 cands[*ncands].fractionality = 0.0;
6719 ++(*ncands);
6720
6721 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6722 * several times as external branching candidate */
6723 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6724 }
6725 }
6726 else
6727 {
6728 SCIP_EXPR* expr;
6729 SCIP_Real lb;
6730 SCIP_Real ub;
6731
6732 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6733 {
6734 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6735 continue;
6736
6737 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6738 * variables, so this expression should either be an original variable or have an auxiliary variable
6739 */
6740 var = SCIPgetExprAuxVarNonlinear(expr);
6741 assert(var != NULL);
6742
6743 lb = SCIPvarGetLbLocal(var);
6744 ub = SCIPvarGetUbLocal(var);
6745
6746 /* skip already fixed variable */
6747 if( SCIPisEQ(scip, lb, ub) )
6748 {
6749 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6750 continue;
6751 }
6752
6753 assert(*ncands + 1 < SCIPgetNVars(scip));
6754 cands[*ncands].expr = expr;
6755 cands[*ncands].var = var;
6756 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6757 cands[*ncands].fractionality = 0.0;
6758 ++(*ncands);
6759 }
6760 }
6761 }
6762
6763 /* if we have branching candidates, then we don't need another attempt */
6764 if( *ncands > 0 )
6765 break;
6766 }
6767
6768 if( it != NULL )
6769 SCIPfreeExpriter(&it);
6770
6771 return SCIP_OKAY;
6772}
6773
6774/** computes a branching score for a variable that reflects how important branching on this variable would be for
6775 * improving the dual bound from the LP relaxation
6776 *
6777 * Assume the Lagrangian for the current LP is something of the form
6778 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6779 * where x are the original variables, z the auxiliary variables,
6780 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6781 *
6782 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6783 * If we could have used not only an estimator, but the actual function f(x), then this would
6784 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6785 * Using a lot of handwaving, we claim that
6786 * lambda_i * (f(x) - a_i'x + b_i)
6787 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6788 * If an estimator depended on local bounds, then it could be improved by branching.
6789 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6790 *
6791 * 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.
6792 * To scale, we divide by the LP objective value (if >1).
6793 *
6794 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6795 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6796 *
6797 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6798 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6799 * would also be branching candidates
6800 */
6801static
6803 SCIP* scip, /**< SCIP data structure */
6804 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6805 SCIP_VAR* var /**< variable */
6806 )
6807{
6808 SCIP_COL* col;
6809 SCIP_ROW** rows;
6810 int nrows;
6811 int r;
6812 SCIP_Real dualscore;
6813
6814 assert(scip != NULL);
6815 assert(conshdlr != NULL);
6816 assert(var != NULL);
6817
6818 /* if LP not solved, then the dual branching score is not available */
6820 return 0.0;
6821
6822 /* if var is not in the LP, then the dual branching score is not available */
6824 return 0.0;
6825
6826 col = SCIPvarGetCol(var);
6827 assert(col != NULL);
6828
6829 if( !SCIPcolIsInLP(col) )
6830 return 0.0;
6831
6832 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6833 rows = SCIPcolGetRows(col);
6834
6835 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6836
6837 /* aggregate duals from all rows from consexpr with non-zero dual
6838 * TODO: this is a quick-and-dirty implementation, and not used by default
6839 * in the long run, this should be either removed or replaced by a proper implementation
6840 */
6841 dualscore = 0.0;
6842 for( r = 0; r < nrows; ++r )
6843 {
6844 SCIP_Real estimategap;
6845 const char* estimategapstr;
6846
6847 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6848 * these would typically be local, unless they are created at the root node
6849 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6850 if( !SCIProwIsLocal(rows[r]) )
6851 continue;
6852 */
6853 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6854 continue;
6855 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6856 continue;
6857
6858 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6859 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6860 continue;
6861 estimategap = atof(estimategapstr + 13);
6862 assert(estimategap >= 0.0);
6863 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6864 estimategap = SCIPgetHugeValue(scip);
6865
6866 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6867 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6868
6869 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6870 }
6871
6872 /* divide by optimal value of LP for scaling */
6873 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6874
6875 return dualscore;
6876}
6877
6878/** computes branching scores (including weighted score) for a set of candidates
6879 *
6880 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6881 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6882 *
6883 * For each score, compute the maximum over all candidates.
6884 *
6885 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6886 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6887 * score of all candidates.
6888 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6889 *
6890 * For example:
6891 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6892 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6893 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6894 * - 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.
6895 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6896 */
6897static
6899 SCIP* scip, /**< SCIP data structure */
6900 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6901 BRANCHCAND* cands, /**< branching candidates */
6902 int ncands, /**< number of candidates */
6903 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6904 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6905 )
6906{
6907 SCIP_CONSHDLRDATA* conshdlrdata;
6908 BRANCHCAND maxscore;
6909 int c;
6910
6911 assert(scip != NULL);
6912 assert(conshdlr != NULL);
6913 assert(cands != NULL);
6914 assert(ncands > 0);
6915
6916 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6917 assert(conshdlrdata != NULL);
6918
6919 /* initialize counts to 0 */
6920 memset(&maxscore, 0, sizeof(BRANCHCAND));
6921
6922 for( c = 0; c < ncands; ++c )
6923 {
6924 if( conshdlrdata->branchviolweight > 0.0 )
6925 {
6926 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6927 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6928 }
6929
6930 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarGetType(cands[c].var) <= SCIP_VARTYPE_INTEGER )
6931 {
6932 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
6933 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
6934 */
6935 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
6936
6937 if( considerfracnl && cands[c].fractionality == 0.0 )
6938 {
6939 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
6940 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
6941 */
6942 SCIP_Real solval;
6943 SCIP_Real rounded;
6944
6945 solval = SCIPgetSolVal(scip, sol, cands[c].var);
6946 rounded = SCIPround(scip, solval);
6947
6948 cands[c].fractionality = REALABS(solval - rounded);
6949 }
6950
6951 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
6952 }
6953 else
6954 cands[c].fractionality = 0.0;
6955
6956 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
6957 {
6958 SCIP_Real domainwidth;
6959 SCIP_VAR* var;
6960
6961 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6962 assert(var != NULL);
6963
6964 /* get domain width, taking infinity at 1e20 on purpose */
6965 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6966
6967 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6968 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6969 * the idea is to penalize very large and very small domains
6970 */
6971 if( domainwidth >= 1.0 )
6972 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6973 else
6974 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6975
6976 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6977 }
6978 else
6979 cands[c].domain = 0.0;
6980
6981 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
6982 {
6983 SCIP_VAR* var;
6984
6985 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6986 assert(var != NULL);
6987
6988 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6989 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6990 }
6991 else
6992 cands[c].dual = 0.0;
6993
6994 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6995 {
6996 SCIP_VAR* var;
6997
6998 var = cands[c].var;
6999 assert(var != NULL);
7000
7001 if( cands[c].expr != NULL )
7002 {
7004 cands[c].pscost = SCIP_INVALID;
7005 else
7006 {
7007 SCIP_Real brpoint;
7008 SCIP_Real pscostdown;
7009 SCIP_Real pscostup;
7010 char strategy;
7011
7012 /* decide how to compute pseudo-cost scores
7013 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7014 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7015 */
7017 strategy = conshdlrdata->branchpscostupdatestrategy;
7018 else
7019 strategy = 'l';
7020
7021 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7022
7023 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7024 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7025 * For here, I use a simple #counts >= branchpscostreliable.
7026 * TODO use SCIPgetVarPseudocostCount() instead?
7027 */
7028 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7029 {
7030 switch( strategy )
7031 {
7032 case 's' :
7033 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7034 break;
7035 case 'd' :
7036 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7037 break;
7038 case 'l' :
7039 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7040 pscostdown = SCIP_INVALID;
7041 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7042 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7043 else
7044 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, sol, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7045 break;
7046 default :
7047 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7048 pscostdown = SCIP_INVALID;
7049 }
7050 }
7051 else
7052 pscostdown = SCIP_INVALID;
7053
7054 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7055 {
7056 switch( strategy )
7057 {
7058 case 's' :
7059 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7060 break;
7061 case 'd' :
7062 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7063 break;
7064 case 'l' :
7065 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7066 pscostup = SCIP_INVALID;
7067 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7068 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7069 else
7070 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, sol, var) );
7071 break;
7072 default :
7073 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7074 pscostup = SCIP_INVALID;
7075 }
7076 }
7077 else
7078 pscostup = SCIP_INVALID;
7079
7080 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7081 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7082 */
7083 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7084 cands[c].pscost = SCIP_INVALID;
7085 else if( pscostdown == SCIP_INVALID )
7086 cands[c].pscost = pscostup;
7087 else if( pscostup == SCIP_INVALID )
7088 cands[c].pscost = pscostdown;
7089 else
7090 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7091 }
7092 }
7093 else
7094 {
7095 SCIP_Real pscostdown;
7096 SCIP_Real pscostup;
7097 SCIP_Real solval;
7098
7099 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7100
7101 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7102 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7103 * and different between variable value and rounded up value for pscostup
7104 */
7105 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7106 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7107 else
7108 pscostdown = SCIP_INVALID;
7109
7110 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7111 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7112 else
7113 pscostup = SCIP_INVALID;
7114
7115 /* TODO see above for nonlinear variable case */
7116 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7117 cands[c].pscost = SCIP_INVALID;
7118 else if( pscostdown == SCIP_INVALID )
7119 cands[c].pscost = pscostup;
7120 else if( pscostup == SCIP_INVALID )
7121 cands[c].pscost = pscostdown;
7122 else
7123 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7124 }
7125
7126 if( cands[c].pscost != SCIP_INVALID )
7127 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7128 }
7129 else
7130 cands[c].pscost = SCIP_INVALID;
7131
7132 if( conshdlrdata->branchvartypeweight > 0.0 )
7133 {
7134 switch( SCIPvarGetType(cands[c].var) )
7135 {
7136 case SCIP_VARTYPE_BINARY :
7137 cands[c].vartype = 1.0;
7138 break;
7140 cands[c].vartype = 0.1;
7141 break;
7143 cands[c].vartype = 0.01;
7144 break;
7146 default:
7147 cands[c].vartype = 0.0;
7148 }
7149 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7150 }
7151 }
7152
7153 /* now compute a weighted score for each candidate from the single scores
7154 * the single scores are scaled to be in [0,1] for this
7155 */
7156 for( c = 0; c < ncands; ++c )
7157 {
7158 SCIP_Real weightsum;
7159
7160 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7161
7162 cands[c].weighted = 0.0;
7163 weightsum = 0.0;
7164
7165 if( maxscore.auxviol > 0.0 )
7166 {
7167 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7168 weightsum += conshdlrdata->branchviolweight;
7169
7170 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7171 }
7172
7173 if( maxscore.fractionality > 0.0 )
7174 {
7175 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7176 weightsum += conshdlrdata->branchfracweight;
7177
7178 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7179 }
7180
7181 if( maxscore.domain > 0.0 )
7182 {
7183 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7184 weightsum += conshdlrdata->branchdomainweight;
7185
7186 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7187 }
7188
7189 if( maxscore.dual > 0.0 )
7190 {
7191 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7192 weightsum += conshdlrdata->branchdualweight;
7193
7194 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7195 }
7196
7197 if( maxscore.pscost > 0.0 )
7198 {
7199 /* use pseudo-costs only if available */
7200 if( cands[c].pscost != SCIP_INVALID )
7201 {
7202 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7203 weightsum += conshdlrdata->branchpscostweight;
7204
7205 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7206 }
7207 else
7208 {
7209 /* do not add pscostscore, if not available, also do not add into weightsum */
7210 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7211 }
7212 }
7213
7214 if( maxscore.vartype > 0.0 )
7215 {
7216 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7217 weightsum += conshdlrdata->branchvartypeweight;
7218
7219 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7220 }
7221
7222 assert(weightsum > 0.0); /* we should have got at least one valid score */
7223 cands[c].weighted /= weightsum;
7224
7225 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7226 }
7227}
7228
7229/** compare two branching candidates by their weighted score
7230 *
7231 * if weighted score is equal, use variable index of (aux)var
7232 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7233 */
7234static
7235SCIP_DECL_SORTINDCOMP(branchcandCompare)
7236{
7237 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7238
7239 if( cands[ind1].weighted != cands[ind2].weighted )
7240 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7241
7242 if( cands[ind1].var != cands[ind2].var )
7243 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7244
7245 return cands[ind1].expr != NULL ? 1 : -1;
7246}
7247
7248/** picks a candidate from array of branching candidates */
7249static
7251 SCIP* scip, /**< SCIP data structure */
7252 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7253 BRANCHCAND* cands, /**< branching candidates */
7254 int ncands, /**< number of candidates */
7255 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7256 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
7257 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7258)
7259{
7260 SCIP_CONSHDLRDATA* conshdlrdata;
7261 int* perm;
7262 int c;
7263 int left;
7264 int right;
7265 SCIP_Real threshold;
7266
7267 assert(cands != NULL);
7268 assert(ncands >= 1);
7269 assert(selected != NULL);
7270
7271 if( ncands == 1 )
7272 {
7273 *selected = cands;
7274 return SCIP_OKAY;
7275 }
7276
7277 /* if there are more than one candidate, then compute scores and select */
7278
7279 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7280 assert(conshdlrdata != NULL);
7281
7282 /* compute additional scores on branching candidates and weighted score */
7283 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
7284
7285 /* sort candidates by weighted score */
7286 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7287 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7288
7289 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7290 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7291 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7292
7293 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7294 left = 0;
7295 right = ncands - 1;
7296 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7297 while( left < right )
7298 {
7299 int mid = (left + right) / 2;
7300 if( cands[perm[mid]].weighted >= threshold )
7301 left = mid + 1;
7302 else
7303 right = mid;
7304 }
7305 assert(left <= ncands);
7306
7307 if( left < ncands )
7308 {
7309 if( cands[perm[left]].weighted >= threshold )
7310 {
7311 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7312 ncands = left + 1;
7313 }
7314 else
7315 {
7316 assert(cands[perm[left]].weighted < threshold);
7317 ncands = left;
7318 }
7319 }
7320 assert(ncands > 0);
7321
7322 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7323 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7324 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7325
7326 if( ncands > 1 )
7327 {
7328 /* choose at random from candidates 0..ncands-1 */
7329 if( conshdlrdata->branchrandnumgen == NULL )
7330 {
7331 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7332 }
7333 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7334 *selected = &cands[perm[c]];
7335 }
7336 else
7337 *selected = &cands[perm[0]];
7338
7339 SCIPfreeBufferArray(scip, &perm);
7340
7341 return SCIP_OKAY;
7342}
7343
7344/** do spatial branching or register branching candidates */
7345static
7347 SCIP* scip, /**< SCIP data structure */
7348 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7349 SCIP_CONS** conss, /**< constraints to process */
7350 int nconss, /**< number of constraints */
7351 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7352 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7353 SCIP_Longint soltag, /**< tag of solution */
7354 SCIP_RESULT* result /**< pointer to store the result of branching */
7355 )
7356{
7357 SCIP_CONSHDLRDATA* conshdlrdata;
7358 BRANCHCAND* cands;
7359 int ncands;
7360 BRANCHCAND* selected = NULL;
7361 SCIP_NODE* downchild;
7362 SCIP_NODE* eqchild;
7363 SCIP_NODE* upchild;
7364
7365 assert(conshdlr != NULL);
7366 assert(result != NULL);
7367
7368 *result = SCIP_DIDNOTFIND;
7369
7370 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7371 assert(conshdlrdata != NULL);
7372
7373 if( conshdlrdata->branchexternal )
7374 {
7375 /* just register branching candidates as external */
7376 SCIP_Bool success;
7377
7378 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7379 if( success )
7380 *result = SCIP_INFEASIBLE;
7381
7382 return SCIP_OKAY;
7383 }
7384
7385 /* collect branching candidates and their auxviol-score */
7387 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7388
7389 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7390 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7391 */
7392 if( ncands == 0 )
7393 goto TERMINATE;
7394
7395 /* here we include fractionality of integer variables into the branching score
7396 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7397 */
7398 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
7399 assert(selected != NULL);
7400 assert(selected->expr != NULL);
7401
7402 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7403 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7404
7405 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7406 &upchild) );
7407 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7408 *result = SCIP_BRANCHED;
7409 else
7410 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7411 *result = SCIP_REDUCEDDOM;
7412
7413 TERMINATE:
7414 SCIPfreeBufferArray(scip, &cands);
7415
7416 return SCIP_OKAY;
7417}
7418
7419/** call enforcement or estimate callback of nonlinear handler
7420 *
7421 * Calls the enforcement callback, if available.
7422 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7423 *
7424 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7425 */
7426static
7428 SCIP* scip, /**< SCIP main data structure */
7429 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7430 SCIP_CONS* cons, /**< nonlinear constraint */
7431 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7432 SCIP_EXPR* expr, /**< expression */
7433 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7434 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7435 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7436 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7437 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7438 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7439 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7440 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7441 SCIP_RESULT* result /**< pointer to store the result */
7442 )
7443{
7444 assert(result != NULL);
7445
7446 /* call enforcement callback of the nlhdlr */
7447 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7448 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7449
7450 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7451 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7452 {
7453 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7454 SCIPnlhdlrGetName(nlhdlr), *result); )
7455 return SCIP_OKAY;
7456 }
7457 else
7458 {
7459 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7460 }
7461
7462 *result = SCIP_DIDNOTFIND;
7463
7464 /* now call the estimator callback of the nlhdlr */
7465 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7466 {
7467 SCIP_VAR* auxvar;
7468 SCIP_Bool sepasuccess = FALSE;
7469 SCIP_Bool branchscoresuccess = FALSE;
7470 SCIP_PTRARRAY* rowpreps;
7471 int minidx;
7472 int maxidx;
7473 int r;
7474 SCIP_ROWPREP* rowprep;
7475
7476 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7477
7478 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7479 assert(auxvar != NULL);
7480
7481 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7482 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7483
7484 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7485 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7486
7487 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7488
7489 if( !sepasuccess )
7490 {
7491 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7492 SCIPnlhdlrGetName(nlhdlr)); )
7493 }
7494
7495 for( r = minidx; r <= maxidx; ++r )
7496 {
7497 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7498
7499 assert(rowprep != NULL);
7500 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7501
7502 if( !branchcandonly )
7503 {
7504 /* complete estimator to cut */
7505 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7506
7507 /* add the cut and/or branching scores
7508 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7509 */
7510 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7511 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7512 }
7513
7514 SCIPfreeRowprep(scip, &rowprep);
7515 }
7516
7517 if( branchcandonly && branchscoresuccess )
7518 {
7519 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7520 *result = SCIP_BRANCHED;
7521 }
7522
7523 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7524 }
7525
7526 return SCIP_OKAY;
7527}
7528
7529/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7530 *
7531 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7532 */
7533static
7535 SCIP* scip, /**< SCIP data structure */
7536 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7537 SCIP_CONS* cons, /**< nonlinear constraint */
7538 SCIP_EXPR* expr, /**< expression */
7539 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7540 SCIP_Longint soltag, /**< tag of solution */
7541 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7542 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7543 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7544 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7545 )
7546{
7547 SCIP_CONSHDLRDATA* conshdlrdata;
7548 SCIP_EXPR_OWNERDATA* ownerdata;
7549 SCIP_Real origviol;
7550 SCIP_Bool underestimate;
7551 SCIP_Bool overestimate;
7552 SCIP_Real auxviol;
7553 SCIP_Bool auxunderestimate;
7554 SCIP_Bool auxoverestimate;
7555 SCIP_RESULT hdlrresult;
7556 int e;
7557
7558 assert(scip != NULL);
7559 assert(expr != NULL);
7560 assert(result != NULL);
7561
7562 ownerdata = SCIPexprGetOwnerData(expr);
7563 assert(ownerdata != NULL);
7564 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7565
7566 *result = SCIP_DIDNOTFIND;
7567
7568 /* make sure that this expression has been evaluated */
7569 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7570
7571 /* decide whether under- or overestimate is required and get amount of violation */
7572 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7573
7574 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7575 assert(conshdlrdata != NULL);
7576
7577 /* no sufficient violation w.r.t. the original variables -> skip expression */
7578 if( !overestimate && !underestimate )
7579 {
7580 return SCIP_OKAY;
7581 }
7582
7583 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7584 for( e = 0; e < ownerdata->nenfos; ++e )
7585 {
7586 SCIP_NLHDLR* nlhdlr;
7587
7588 /* skip nlhdlr that do not want to participate in any separation */
7589 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7590 continue;
7591
7592 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7593 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7594 continue;
7595
7596 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7597 assert(nlhdlr != NULL);
7598
7599 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7600 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7601 ENFOLOG(
7602 SCIPinfoMessage(scip, enfologfile, " expr ");
7603 SCIPprintExpr(scip, expr, enfologfile);
7604 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7605 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7606 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7607 )
7608
7609 /* TODO if expr is root of constraint (consdata->expr == expr),
7610 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7611 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7612 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7613 * so we should enforce in these auxiliaries first
7614 * if changing this here, we must also adapt analyzeViolation()
7615 */
7616
7617 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7618 assert(auxviol >= 0.0);
7619
7620 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7621 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7622 {
7623 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7624 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7625 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7626
7627 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7628 continue;
7629 }
7630
7631 /* 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 */
7632 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7633 {
7634 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7635 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7636 underestimate, overestimate); )
7637
7638 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7639 continue;
7640 }
7641
7642 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7643 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7644 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7645
7646 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7647 * wants to be called for separation on this side, then call separation of nlhdlr
7648 */
7649 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7650 {
7651 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7652 hdlrresult = SCIP_DIDNOTFIND;
7653 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7654 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7655
7656 if( hdlrresult == SCIP_CUTOFF )
7657 {
7658 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7659 *result = SCIP_CUTOFF;
7660 ownerdata->lastenforced = conshdlrdata->enforound;
7661 break;
7662 }
7663
7664 if( hdlrresult == SCIP_SEPARATED )
7665 {
7666 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7667 *result = SCIP_SEPARATED;
7668 ownerdata->lastenforced = conshdlrdata->enforound;
7669 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7670 break;
7671 }
7672
7673 if( hdlrresult == SCIP_REDUCEDDOM )
7674 {
7675 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7676 *result = SCIP_REDUCEDDOM;
7677 ownerdata->lastenforced = conshdlrdata->enforound;
7678 /* TODO or should we always just stop here? */
7679 }
7680
7681 if( hdlrresult == SCIP_BRANCHED )
7682 {
7683 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7684 assert(inenforcement);
7685
7686 /* separation and domain reduction takes precedence over branching */
7687 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7688 if( *result == SCIP_DIDNOTFIND )
7689 *result = SCIP_BRANCHED;
7690 ownerdata->lastenforced = conshdlrdata->enforound;
7691 }
7692 }
7693
7694 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7695 * wants to be called for separation on this side, then call separation of nlhdlr
7696 */
7697 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7698 {
7699 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7700 hdlrresult = SCIP_DIDNOTFIND;
7701 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7702 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7703
7704 if( hdlrresult == SCIP_CUTOFF )
7705 {
7706 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7707 *result = SCIP_CUTOFF;
7708 ownerdata->lastenforced = conshdlrdata->enforound;
7709 break;
7710 }
7711
7712 if( hdlrresult == SCIP_SEPARATED )
7713 {
7714 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7715 *result = SCIP_SEPARATED;
7716 ownerdata->lastenforced = conshdlrdata->enforound;
7717 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7718 break;
7719 }
7720
7721 if( hdlrresult == SCIP_REDUCEDDOM )
7722 {
7723 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7724 *result = SCIP_REDUCEDDOM;
7725 ownerdata->lastenforced = conshdlrdata->enforound;
7726 /* TODO or should we always just stop here? */
7727 }
7728
7729 if( hdlrresult == SCIP_BRANCHED )
7730 {
7731 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7732 assert(inenforcement);
7733
7734 /* separation takes precedence over branching */
7735 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7736 if( *result == SCIP_DIDNOTFIND )
7737 *result = SCIP_BRANCHED;
7738 ownerdata->lastenforced = conshdlrdata->enforound;
7739 }
7740 }
7741 }
7742
7743 return SCIP_OKAY;
7744}
7745
7746/** helper function to enforce a single constraint */
7747static
7749 SCIP* scip, /**< SCIP data structure */
7750 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7751 SCIP_CONS* cons, /**< constraint to process */
7752 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7753 SCIP_Longint soltag, /**< tag of solution */
7754 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7755 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7756 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7757 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7758 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7759 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7760 )
7761{
7762 SCIP_CONSDATA* consdata;
7763 SCIP_CONSHDLRDATA* conshdlrdata;
7764 SCIP_EXPR* expr;
7765
7766 assert(conshdlr != NULL);
7767 assert(cons != NULL);
7768 assert(it != NULL);
7769 assert(result != NULL);
7770 assert(success != NULL);
7771
7772 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7773 assert(conshdlrdata != NULL);
7774
7775 consdata = SCIPconsGetData(cons);
7776 assert(consdata != NULL);
7777 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7778
7779 *success = FALSE;
7780
7781 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7782 {
7783 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7784 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7785 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7786 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7787 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7788 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7789 * confuse the stalling check for how long to do separation).
7790 */
7791 SCIP_Bool infeasible;
7792 int ntightenings;
7793
7794 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7795 if( infeasible )
7796 {
7797 *result = SCIP_CUTOFF;
7798 return SCIP_OKAY;
7799 }
7800 /* if we tightened an auxvar bound, we better communicate that */
7801 if( ntightenings > 0 )
7802 *result = SCIP_REDUCEDDOM;
7803 }
7804
7805 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7806 {
7807 SCIP_EXPR_OWNERDATA* ownerdata;
7808 SCIP_RESULT resultexpr;
7809
7810 ownerdata = SCIPexprGetOwnerData(expr);
7811 assert(ownerdata != NULL);
7812
7813 /* we can only enforce if there is an auxvar to compare with */
7814 if( ownerdata->auxvar == NULL )
7815 continue;
7816
7817 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7818 if( ownerdata->lastenforced == conshdlrdata->enforound )
7819 {
7820 ENFOLOG(
7821 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7822 SCIPprintExpr(scip, expr, enfologfile);
7823 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7824 )
7825 *success = TRUE;
7826 continue;
7827 }
7828
7829 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7830
7831 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7832 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7833 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
7834 *success = TRUE;
7835
7836 if( resultexpr == SCIP_CUTOFF )
7837 {
7838 *result = SCIP_CUTOFF;
7839 break;
7840 }
7841
7842 if( resultexpr == SCIP_SEPARATED )
7843 *result = SCIP_SEPARATED;
7844
7845 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7846 *result = SCIP_REDUCEDDOM;
7847
7848 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7849 *result = SCIP_BRANCHED;
7850 }
7851
7852 return SCIP_OKAY;
7853}
7854
7855/** try to separate violated constraints and, if in enforcement, register branching scores
7856 *
7857 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7858 *
7859 * Sets result to
7860 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7861 * - SCIP_CUTOFF, if node can be cutoff,
7862 * - SCIP_SEPARATED, if a cut has been added,
7863 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7864 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7865 * - SCIP_INFEASIBLE, if external branching candidates were registered
7866 */
7867static
7869 SCIP* scip, /**< SCIP data structure */
7870 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7871 SCIP_CONS** conss, /**< constraints to process */
7872 int nconss, /**< number of constraints */
7873 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7874 SCIP_Longint soltag, /**< tag of solution */
7875 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7876 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7877 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7878 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7879 )
7880{
7881 SCIP_CONSHDLRDATA* conshdlrdata;
7882 SCIP_EXPRITER* it;
7883 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7884 int c;
7885
7886 assert(conshdlr != NULL);
7887 assert(conss != NULL || nconss == 0);
7888 assert(result != NULL);
7889
7890 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7891 assert(conshdlrdata != NULL);
7892
7893 /* increase tag to tell whether branching scores in expression belong to this sweep
7894 * and which expressions have already been enforced in this sweep
7895 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7896 */
7897 ++(conshdlrdata->enforound);
7898
7899 *result = SCIP_DIDNOTFIND;
7900
7903
7904 for( c = 0; c < nconss; ++c )
7905 {
7906 assert(conss != NULL && conss[c] != NULL);
7907
7908 /* skip constraints that are not enabled or deleted */
7909 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7910 continue;
7911 assert(SCIPconsIsActive(conss[c]));
7912
7913 /* skip constraints that have separation disabled if we are only in separation */
7914 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7915 continue;
7916
7917 /* skip non-violated constraints */
7918 if( !isConsViolated(scip, conss[c]) )
7919 continue;
7920
7921 ENFOLOG(
7922 {
7923 SCIP_CONSDATA* consdata;
7924 int i;
7925 consdata = SCIPconsGetData(conss[c]);
7926 assert(consdata != NULL);
7927 SCIPinfoMessage(scip, enfologfile, " constraint ");
7928 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7929 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7930 for( i = 0; i < consdata->nvarexprs; ++i )
7931 {
7932 SCIP_VAR* var;
7933 var = SCIPgetVarExprVar(consdata->varexprs[i]);
7934 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7935 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7936 }
7937 })
7938
7939 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
7940
7941 if( *result == SCIP_CUTOFF )
7942 break;
7943
7944 if( !consenforced && inenforcement && !branchcandonly )
7945 {
7946 SCIP_Real viol;
7947
7948 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7949 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7950 {
7951 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7952 "cuts allowed\n", SCIPconsGetName(conss[c])); )
7953
7954 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
7955
7956 if( consenforced )
7957 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7958
7959 if( *result == SCIP_CUTOFF )
7960 break;
7961 }
7962 }
7963 }
7964
7965 SCIPfreeExpriter(&it);
7966
7967 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7968
7969 if( *result == SCIP_BRANCHED && !branchcandonly )
7970 {
7971 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7972 * branching
7973 */
7974 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7975
7976 /* branching should either have branched: result == SCIP_BRANCHED,
7977 * or fixed a variable: result == SCIP_REDUCEDDOM,
7978 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7979 * or have not done anything: result == SCIP_DIDNOTFIND
7980 */
7981 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7982 }
7983
7984 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7985
7986 return SCIP_OKAY;
7987}
7988
7989/** decide whether to branch on fractional integer or nonlinear variable
7990 *
7991 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
7992 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
7993 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
7994 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
7995 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
7996 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
7997 */
7998static
8000 SCIP* scip, /**< SCIP data structure */
8001 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8002 SCIP_CONS** conss, /**< constraints to process */
8003 int nconss, /**< number of constraints */
8004 SCIP_Longint soltag, /**< tag of LP solution */
8005 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
8006 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
8007 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
8008 )
8009{
8010 SCIP_RESULT result;
8011 int nlpcands;
8012 SCIP_VAR** lpcands; /* fractional integer variables */
8013 SCIP_Real* lpcandsfrac; /* fractionalities */
8014 BRANCHCAND* cands;
8015 BRANCHCAND* selected;
8016 int ncands;
8017 int c;
8018
8019 assert(scip != NULL);
8020 assert(conshdlr != NULL);
8021 assert(conss != NULL);
8022 assert(nconss > 0);
8023 assert(branchintegral != NULL);
8024 assert(cutoff != NULL);
8025
8026 *branchintegral = FALSE;
8027 *cutoff = FALSE;
8028
8030 return SCIP_OKAY;
8031
8032 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
8033 switch( result )
8034 {
8035 case SCIP_DIDNOTFIND:
8036 /* no branching candidates found could mean that the LP solution is in a convex region */
8037 *branchintegral = TRUE;
8038 return SCIP_OKAY;
8039
8040 case SCIP_CUTOFF:
8041 /* probably cannot happen, but easy to handle */
8042 *cutoff = TRUE;
8043 return SCIP_OKAY;
8044
8045 case SCIP_SEPARATED:
8046 case SCIP_REDUCEDDOM:
8047 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8048 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8049 return SCIP_ERROR;
8050
8051 case SCIP_BRANCHED:
8052 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8053 break;
8054
8055 case SCIP_INFEASIBLE:
8056 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8057 * but this was disabled by branchcandonly = TRUE)
8058 */
8059 default:
8060 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8061 return SCIP_ERROR;
8062 } /*lint !e788*/
8063
8064 /* collect spatial branching candidates and their auxviol-score */
8066 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8067
8068 /* add fractional integer variables to branching candidates */
8069 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
8070
8071 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8072
8073 for( c = 0; c < nlpcands; ++c )
8074 {
8075 assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
8076 assert(SCIPvarGetType(lpcands[c]) <= SCIP_VARTYPE_INTEGER);
8077 cands[ncands].expr = NULL;
8078 cands[ncands].var = lpcands[c];
8079 cands[ncands].auxviol = 0.0;
8080 cands[ncands].fractionality = lpcandsfrac[c];
8081 ++ncands;
8082 }
8083
8084 /* select a variable for branching
8085 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8086 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
8087 */
8088 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
8089 assert(selected != NULL);
8090
8091 if( selected->expr == NULL )
8092 {
8093 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8094
8095 *branchintegral = TRUE;
8096 }
8097
8098 SCIPfreeBufferArray(scip, &cands);
8099
8100 return SCIP_OKAY;
8101}
8102
8103/** decide whether to consider spatial branching before integrality has been enforced
8104 *
8105 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8106 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8107 *
8108 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8109 */
8110static
8112 SCIP* scip, /**< SCIP data structure */
8113 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8114 SCIP_SOL* sol /**< solution to be enforced */
8115)
8116{
8117 SCIP_CONSHDLRDATA* conshdlrdata;
8118
8119 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8120 assert(conshdlrdata != NULL);
8121
8122 /* if LP still unbounded, then work on nonlinear constraints first */
8124 return FALSE;
8125
8126 /* no branching in cons_integral if no integer variables */
8128 return FALSE;
8129
8130 /* no branching in cons_integral if LP solution not fractional */
8131 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
8132 return FALSE;
8133
8134 /* no branching in cons_integral if relax solution not fractional */
8135 if( sol != NULL )
8136 {
8137 SCIP_Bool isfractional = FALSE;
8138 SCIP_VAR** vars;
8139 int nbinvars;
8140 int nintvars;
8141 int i;
8142
8143 vars = SCIPgetVars(scip);
8144 nbinvars = SCIPgetNBinVars(scip);
8145 nintvars = SCIPgetNIntVars(scip);
8146
8147 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
8148 {
8149 assert(vars[i] != NULL);
8150 assert(SCIPvarIsIntegral(vars[i]));
8151
8152 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[i])) )
8153 isfractional = TRUE;
8154 }
8155
8156 if( !isfractional )
8157 return FALSE;
8158 }
8159
8160 /* branchmixfractional being infinity means that integral should always go first */
8161 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8162 return TRUE;
8163
8164 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8165 if( conshdlrdata->branchmixfractional == 0.0 )
8166 return FALSE;
8167
8168 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8169 * @todo this gives the total pseudocost count divided by the number of discrete variables
8170 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8171 */
8172 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8173 return TRUE;
8174 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8175 return TRUE;
8176
8177 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8178 return FALSE;
8179}
8180
8181/** collect (and print (if debugging enfo)) information on violation in expressions
8182 *
8183 * assumes that constraint violations have been computed
8184 */
8185static
8187 SCIP* scip, /**< SCIP data structure */
8188 SCIP_CONS** conss, /**< constraints */
8189 int nconss, /**< number of constraints */
8190 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8191 SCIP_Longint soltag, /**< tag of solution */
8192 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8193 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8194 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8195 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8196 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8197 )
8198{
8199 SCIP_CONSDATA* consdata;
8200 SCIP_EXPRITER* it;
8201 SCIP_EXPR* expr;
8202 SCIP_Real v;
8203 int c;
8204
8205 assert(conss != NULL || nconss == 0);
8206 assert(maxabsconsviol != NULL);
8207 assert(maxrelconsviol != NULL);
8208 assert(maxauxviol != NULL);
8209 assert(maxvarboundviol != NULL);
8210
8213
8214 *maxabsconsviol = 0.0;
8215 *maxrelconsviol = 0.0;
8216 *minauxviol = SCIPinfinity(scip);
8217 *maxauxviol = 0.0;
8218 *maxvarboundviol = 0.0;
8219
8220 for( c = 0; c < nconss; ++c )
8221 {
8222 assert(conss != NULL && conss[c] != NULL);
8223
8224 consdata = SCIPconsGetData(conss[c]);
8225 assert(consdata != NULL);
8226
8227 /* skip constraints that are not enabled, deleted, or have separation disabled */
8228 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8229 continue;
8230 assert(SCIPconsIsActive(conss[c]));
8231
8232 v = getConsAbsViolation(conss[c]);
8233 *maxabsconsviol = MAX(*maxabsconsviol, v);
8234
8235 /* skip non-violated constraints */
8236 if( !isConsViolated(scip, conss[c]) )
8237 continue;
8238
8239 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8240 *maxrelconsviol = MAX(*maxrelconsviol, v);
8241
8242 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8243 {
8244 SCIP_EXPR_OWNERDATA* ownerdata;
8245 SCIP_Real auxvarvalue;
8246 SCIP_Real auxvarlb;
8247 SCIP_Real auxvarub;
8248 SCIP_Bool violunder;
8249 SCIP_Bool violover;
8250 SCIP_Real origviol;
8251 SCIP_Real auxviol;
8252 int e;
8253
8254 ownerdata = SCIPexprGetOwnerData(expr);
8255 assert(ownerdata != NULL);
8256
8257 if( ownerdata->auxvar == NULL )
8258 {
8259 /* check violation of variable bounds of original variable */
8260 if( SCIPisExprVar(scip, expr) )
8261 {
8262 SCIP_VAR* var;
8263 var = SCIPgetVarExprVar(expr);
8264 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8265 auxvarlb = SCIPvarGetLbLocal(var);
8266 auxvarub = SCIPvarGetUbLocal(var);
8267
8268 origviol = 0.0;
8269 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8270 origviol = auxvarlb - auxvarvalue;
8271 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8272 origviol = auxvarvalue - auxvarub;
8273 if( origviol <= 0.0 )
8274 continue;
8275
8276 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8277
8278 ENFOLOG(
8279 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8280 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8281 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8282 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8283 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8284 SCIPinfoMessage(scip, enfologfile, "\n");
8285 )
8286 }
8287
8288 continue;
8289 }
8290
8291 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8292 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8293 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8294
8295 /* check violation of variable bounds of auxiliary variable */
8296 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8297 *maxvarboundviol = auxvarlb - auxvarvalue;
8298 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8299 *maxvarboundviol = auxvarvalue - auxvarub;
8300
8301 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8302
8303 ENFOLOG(
8304 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8305 {
8306 SCIPinfoMessage(scip, enfologfile, "expr ");
8307 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8308 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8309
8310 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8311 if( origviol > 0.0 )
8312 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8313 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8314 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8315 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8316 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8317 SCIPinfoMessage(scip, enfologfile, "\n");
8318 }
8319 )
8320
8321 /* no violation w.r.t. the original variables -> skip expression */
8322 if( origviol == 0.0 )
8323 continue;
8324
8325 /* compute aux-violation for each nonlinear handlers */
8326 for( e = 0; e < ownerdata->nenfos; ++e )
8327 {
8328 SCIP_NLHDLR* nlhdlr;
8329
8330 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8331 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8332 continue;
8333
8334 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8335 assert(nlhdlr != NULL);
8336
8337 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8338 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8339
8340 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8341
8342 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8343
8344 if( auxviol > 0.0 )
8345 {
8346 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8347 *maxauxviol = MAX(*maxauxviol, auxviol);
8348 *minauxviol = MIN(*minauxviol, auxviol);
8349 }
8350 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8351 }
8352 }
8353 }
8354
8355 SCIPfreeExpriter(&it);
8356
8357 return SCIP_OKAY;
8358} /*lint !e715*/
8359
8360/** enforcement of constraints called by enfolp and enforelax */
8361static
8363 SCIP* scip, /**< SCIP data structure */
8364 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8365 SCIP_CONS** conss, /**< constraints to process */
8366 int nconss, /**< number of constraints */
8367 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8368 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8369 )
8370{
8371 SCIP_CONSHDLRDATA* conshdlrdata;
8372 SCIP_Real maxabsconsviol;
8373 SCIP_Real maxrelconsviol;
8374 SCIP_Real minauxviol;
8375 SCIP_Real maxauxviol;
8376 SCIP_Real maxvarboundviol;
8377 SCIP_Longint soltag;
8378 SCIP_Bool branchintegral;
8379 int nnotify;
8380 int c;
8381
8382 if( branchingIntegralFirst(scip, conshdlr, sol) )
8383 {
8384 /* let cons_integral handle enforcement */
8385 *result = SCIP_INFEASIBLE;
8386 return SCIP_OKAY;
8387 }
8388
8389 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8390 assert(conshdlr != NULL);
8391
8392 soltag = SCIPgetExprNewSoltag(scip);
8393
8394 *result = SCIP_FEASIBLE;
8395 for( c = 0; c < nconss; ++c )
8396 {
8397 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8398
8399 if( isConsViolated(scip, conss[c]) )
8400 *result = SCIP_INFEASIBLE;
8401 }
8402
8403 if( *result == SCIP_FEASIBLE )
8404 {
8405 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8407 return SCIP_OKAY;
8408 }
8409
8410 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8411 &minauxviol, &maxauxviol, &maxvarboundviol) );
8412
8413 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8414 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8415 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8416 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8417
8418 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8419
8420 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8421 if( sol == NULL )
8422 {
8423 SCIP_Bool cutoff;
8424
8425 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8426 if( cutoff )
8427 {
8428 *result = SCIP_CUTOFF;
8429 return SCIP_OKAY;
8430 }
8431 if( branchintegral )
8432 {
8433 /* let cons_integral handle enforcement */
8434 *result = SCIP_INFEASIBLE;
8435 return SCIP_OKAY;
8436 }
8437 }
8438
8439 /* try to propagate */
8440 if( conshdlrdata->propinenforce )
8441 {
8442 SCIP_RESULT propresult;
8443 int nchgbds = 0;
8444
8445 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8446
8447 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8448 {
8449 *result = propresult;
8450 return SCIP_OKAY;
8451 }
8452 }
8453
8454 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8455 * all violated expr/auxvar in violated constraints)
8456 */
8457 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8458 sol == NULL )
8459 {
8460 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8461 ++conshdlrdata->ntightenlp;
8462
8463 *result = SCIP_SOLVELP;
8464
8465 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8466 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8467
8468 return SCIP_OKAY;
8469 }
8470
8471 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8472 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8473 */
8474 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8475 {
8476 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8477 ++conshdlrdata->ntightenlp;
8478
8479 *result = SCIP_SOLVELP;
8480
8481 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8482
8483 return SCIP_OKAY;
8484 }
8485
8486 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8487
8488 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8489 *result == SCIP_INFEASIBLE )
8490 return SCIP_OKAY;
8491
8492 assert(*result == SCIP_DIDNOTFIND);
8493
8494 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8495 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8496
8497 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8498 {
8499 /* if there are still fractional integer variables, then let cons_integral go first */
8500 *result = SCIP_INFEASIBLE;
8501 return SCIP_OKAY;
8502 }
8503
8504 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8505 {
8506 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8507 ++conshdlrdata->ntightenlp;
8508
8509 *result = SCIP_SOLVELP;
8510
8511 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8512 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8513
8514 return SCIP_OKAY;
8515 }
8516
8517 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8518 SCIPgetLPFeastol(scip)) && sol == NULL )
8519 {
8520 /* try whether tighten the LP feasibility tolerance could help
8521 * maybe it is just some cut that hasn't been taken into account sufficiently
8522 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8523 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8524 * until the LP feastol reaches epsilon
8525 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8526 * when maxauxviol is above LP feastol)
8527 */
8528 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8529 ++conshdlrdata->ndesperatetightenlp;
8530
8531 *result = SCIP_SOLVELP;
8532
8533 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8534
8535 return SCIP_OKAY;
8536 }
8537
8538 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8539 if( !conshdlrdata->propinenforce )
8540 {
8541 SCIP_RESULT propresult;
8542 int nchgbds = 0;
8543
8544 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8545
8546 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8547 {
8548 *result = propresult;
8549 return SCIP_OKAY;
8550 }
8551 }
8552
8553 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8554 * now look if we find any unfixed variable that we could still branch on
8555 */
8556 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8557
8558 if( nnotify > 0 )
8559 {
8560 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8561 ++conshdlrdata->ndesperatebranch;
8562
8563 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8564
8565 return SCIP_OKAY;
8566 }
8567
8568 /* if everything is fixed in violated constraints, then let's cut off the node
8569 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8570 * result may not be conclusive (when constraint violations are small)
8571 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8572 * sufficiently (see st_e40)
8573 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8574 * not "desperate", but a pretty obvious thing to do
8575 */
8576 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8577 *result = SCIP_CUTOFF;
8578
8579 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8580 if( !SCIPisZero(scip, maxvarboundviol) )
8581 ++conshdlrdata->ndesperatecutoff;
8582
8583 return SCIP_OKAY;
8584}
8585
8586/** separation for all violated constraints to be used by SEPA callbacks */
8587static
8589 SCIP* scip, /**< SCIP data structure */
8590 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8591 SCIP_CONS** conss, /**< constraints to process */
8592 int nconss, /**< number of constraints */
8593 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8594 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8595 )
8596{
8597 SCIP_Longint soltag;
8598 SCIP_Bool haveviol = FALSE;
8599 int c;
8600
8601 *result = SCIP_DIDNOTFIND;
8602
8603 soltag = SCIPgetExprNewSoltag(scip);
8604
8605 /* compute violations */
8606 for( c = 0; c < nconss; ++c )
8607 {
8608 assert(conss[c] != NULL);
8609
8610 /* skip constraints that are not enabled, deleted, or have separation disabled */
8611 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8612 continue;
8613 assert(SCIPconsIsActive(conss[c]));
8614
8615 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8616
8617 if( isConsViolated(scip, conss[c]) )
8618 haveviol = TRUE;
8619 }
8620
8621 /* if none of our constraints are violated, don't attempt separation */
8622 if( !haveviol )
8623 {
8624 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8625 return SCIP_OKAY;
8626 }
8627
8628 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8629
8630 /* call separation */
8631 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8632
8633 return SCIP_OKAY;
8634}
8635
8636/** hash key retrieval function for bilinear term entries */
8637static
8638SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8639{ /*lint --e{715}*/
8640 SCIP_CONSHDLRDATA* conshdlrdata;
8641 int idx;
8642
8643 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8644 assert(conshdlrdata != NULL);
8645
8646 idx = ((int)(size_t)elem) - 1;
8647 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8648
8649 return (void*)&conshdlrdata->bilinterms[idx];
8650}
8651
8652/** returns TRUE iff the bilinear term entries are equal */
8653static
8654SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8655{ /*lint --e{715}*/
8658
8659 /* get corresponding entries */
8660 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8661 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8662 assert(entry1->x != NULL && entry1->y != NULL);
8663 assert(entry2->x != NULL && entry2->y != NULL);
8664 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8665 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8666
8667 return entry1->x == entry2->x && entry1->y == entry2->y;
8668}
8669
8670/** returns the hash value of the key */
8671static
8672SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8673{ /*lint --e{715}*/
8675
8676 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8677 assert(entry->x != NULL && entry->y != NULL);
8678 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8679
8680 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8681}
8682
8683/** compare two auxiliary expressions
8684 *
8685 * Compares auxiliary variables, followed by coefficients, and then constants.
8686 */
8687static
8689{
8692 int compvars;
8693 int i;
8694
8695 /* compare the auxiliary variables */
8696 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8697
8698 if( compvars != 0 )
8699 return compvars;
8700
8701 /* compare the coefficients and constants */
8702 for( i = 0; i < 3; ++i )
8703 {
8704 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8705 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8706 }
8707
8708 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8709}
8710
8711/* add an auxiliary expression to a bilinear term */
8712static
8714 SCIP* scip, /**< SCIP data structure */
8715 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8716 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8717 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8718 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8719 )
8720{
8721 SCIP_Bool found;
8722 int pos;
8723 int i;
8724
8725 *added = FALSE;
8726
8727 /* check if auxexpr has already been added to term */
8728 if( term->nauxexprs == 0 )
8729 {
8730 found = FALSE;
8731 pos = 0;
8732 }
8733 else
8734 {
8735 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8736 }
8737
8738 if( !found )
8739 {
8740 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8741 return SCIP_OKAY;
8742
8744 assert(term->auxexprssize >= term->nauxexprs + 1);
8745
8746 /* insert expression at the correct position */
8747 for( i = term->nauxexprs; i > pos; --i )
8748 {
8749 term->aux.exprs[i] = term->aux.exprs[i-1];
8750 }
8751 term->aux.exprs[pos] = auxexpr;
8752 ++(term->nauxexprs);
8753 *added = TRUE;
8754 }
8755 else
8756 {
8757 assert(term->aux.exprs != NULL);
8758 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8759 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8760 }
8761
8762 return SCIP_OKAY;
8763}
8764
8765/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8766static
8768 SCIP* scip, /**< SCIP data structure */
8769 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8770 SCIP_CONS** conss, /**< nonlinear constraints */
8771 int nconss /**< total number of nonlinear constraints */
8772 )
8773{
8774 SCIP_CONSHDLRDATA* conshdlrdata;
8775 SCIP_EXPRITER* it;
8776 int c;
8777
8778 assert(conss != NULL || nconss == 0);
8779
8780 if( nconss == 0 )
8781 return SCIP_OKAY;
8782
8783 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8784 assert(conshdlrdata != NULL);
8785
8786 /* check whether the bilinear terms have been stored already */
8787 if( conshdlrdata->bilinterms != NULL )
8788 return SCIP_OKAY;
8789
8790 /* create and initialize iterator */
8794
8795 /* iterate through all constraints */
8796 for( c = 0; c < nconss; ++c )
8797 {
8798 SCIP_CONSDATA* consdata;
8799 SCIP_EXPR* expr;
8800
8801 assert(conss != NULL && conss[c] != NULL);
8802 consdata = SCIPconsGetData(conss[c]);
8803 assert(consdata != NULL);
8804
8805 /* iterate through all expressions */
8806 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8807 {
8808 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8809 SCIP_VAR* x = NULL;
8810 SCIP_VAR* y = NULL;
8811
8812 /* check whether the expression is of the form f(..)^2 */
8813 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8814 {
8815 x = SCIPgetExprAuxVarNonlinear(children[0]);
8816 y = x;
8817 }
8818 /* check whether the expression is of the form f(..) * g(..) */
8819 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8820 {
8821 x = SCIPgetExprAuxVarNonlinear(children[0]);
8822 y = SCIPgetExprAuxVarNonlinear(children[1]);
8823 }
8824
8825 /* add variables to the hash table */
8826 if( x != NULL && y != NULL )
8827 {
8830 }
8831 }
8832 }
8833
8834 /* release iterator */
8835 SCIPfreeExpriter(&it);
8836
8837 return SCIP_OKAY;
8838}
8839
8840/** store x, y and the locks in a new bilinear term */
8841static
8843 SCIP* scip, /**< SCIP data structure */
8844 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8845 SCIP_VAR* x, /**< the first variable */
8846 SCIP_VAR* y, /**< the second variable */
8847 int nlockspos, /**< number of positive locks of the bilinear term */
8848 int nlocksneg, /**< number of negative locks of the bilinear term */
8849 int* idx, /**< pointer to store the position of the term in bilinterms array */
8850 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8851 )
8852{
8853 SCIP_CONSHDLRDATA* conshdlrdata;
8855
8856 assert(conshdlr != NULL);
8857 assert(x != NULL);
8858 assert(y != NULL);
8859 assert(nlockspos >= 0);
8860 assert(nlocksneg >= 0);
8861
8862 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8863 assert(conshdlrdata != NULL);
8864
8865 /* ensure that x.index <= y.index */
8866 if( SCIPvarCompare(x, y) == 1 )
8867 {
8868 SCIPswapPointers((void**)&x, (void**)&y);
8869 }
8870 assert(SCIPvarCompare(x, y) < 1);
8871
8872 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8873
8874 /* update or create the term */
8875 if( *idx >= 0 )
8876 { /* the term has already been added */
8877 assert(conshdlrdata->bilinterms[*idx].x == x);
8878 assert(conshdlrdata->bilinterms[*idx].y == y);
8879
8880 /* get term and add locks */
8881 term = &conshdlrdata->bilinterms[*idx];
8882 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8883 term->nlockspos += nlockspos;
8884 term->nlocksneg += nlocksneg;
8885 }
8886 else
8887 { /* this is the first time we encounter this product */
8888 /* ensure size of bilinterms array */
8889 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8890
8891 *idx = conshdlrdata->nbilinterms;
8892
8893 /* get term and set values in the created bilinear term */
8894 term = &conshdlrdata->bilinterms[*idx];
8895 assert(term != NULL);
8896 term->x = x;
8897 term->y = y;
8898 term->nauxexprs = 0;
8899 term->auxexprssize = 0;
8900 term->nlockspos = nlockspos;
8901 term->nlocksneg = nlocksneg;
8902 term->existing = existing;
8903 if( existing )
8904 term->aux.var = NULL;
8905 else
8906 term->aux.exprs = NULL;
8907
8908 /* increase the total number of bilinear terms */
8909 ++(conshdlrdata->nbilinterms);
8910
8911 /* save to the hashtable */
8912 if( conshdlrdata->bilinhashtable == NULL )
8913 {
8914 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8915 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8916 (void*)conshdlrdata) );
8917 }
8918 assert(conshdlrdata->bilinhashtable != NULL);
8919
8920 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8921 * because zero can not be inserted into hash table
8922 */
8923 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8924
8925 /* capture product variables */
8928 }
8929
8930 return SCIP_OKAY;
8931}
8932
8933/** frees array of bilinear terms and hash table */
8934static
8936 SCIP* scip, /**< SCIP data structure */
8937 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8938 )
8939{
8940 int i;
8941 int j;
8942
8943 assert(conshdlrdata != NULL);
8944
8945 /* check whether bilinear terms have been stored */
8946 if( conshdlrdata->bilinterms == NULL )
8947 {
8948 assert(conshdlrdata->bilinterms == NULL);
8949 assert(conshdlrdata->nbilinterms == 0);
8950 assert(conshdlrdata->bilintermssize == 0);
8951
8952 return SCIP_OKAY;
8953 }
8954
8955 /* release variables */
8956 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8957 {
8958 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8959 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8960
8961 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8962 {
8963 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8964 {
8965 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8966 }
8967 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8968 }
8969
8970 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8971 {
8972 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8973 continue;
8974 }
8975
8976 /* the rest is for simple terms with a single auxvar */
8977
8978 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8979 if( conshdlrdata->bilinterms[i].aux.var != NULL )
8980 {
8981 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8982 }
8983 }
8984
8985 /* free hash table */
8986 if( conshdlrdata->bilinhashtable != NULL )
8987 {
8988 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8989 }
8990
8991 /* free bilinterms array; reset counters */
8992 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8993 conshdlrdata->nbilinterms = 0;
8994 conshdlrdata->bilintermssize = 0;
8995
8996 return SCIP_OKAY;
8997}
8998
8999/*
9000 * vertex polyhedral separation
9001 */
9002
9003/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
9004static
9006 SCIP* scip, /**< SCIP data structure */
9007 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
9008 SCIP_LPI** lp /**< pointer to store created LP */
9009 )
9010{
9011 SCIP_Real* obj;
9012 SCIP_Real* lb;
9013 SCIP_Real* ub;
9014 SCIP_Real* val;
9015 int* beg;
9016 int* ind;
9017 unsigned int nnonz;
9018 unsigned int ncols;
9019 unsigned int nrows;
9020 unsigned int i;
9021 unsigned int k;
9022
9023 assert(scip != NULL);
9024 assert(lp != NULL);
9025 assert(nvars > 0);
9026 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9027
9028 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
9029
9030 /* create lpi to store the LP */
9032
9033 nrows = (unsigned int)nvars + 1;
9034 ncols = POWEROFTWO((unsigned int)nvars);
9035 nnonz = (ncols * (nrows + 1)) / 2;
9036
9037 /* allocate necessary memory; set obj, lb, and ub to zero */
9038 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
9040 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
9041 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
9042 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
9043 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
9044
9045 /* calculate nonzero entries in the LP */
9046 for( i = 0, k = 0; i < ncols; ++i )
9047 {
9048 int row;
9049 unsigned int a;
9050
9051 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
9052 ub[i] = SCIPlpiInfinity(*lp);
9053
9054 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
9055 beg[i] = (int)k;
9056 row = 0;
9057
9058 /* iterate through the bit representation of i */
9059 a = 1;
9060 while( a <= i )
9061 {
9062 if( (a & i) != 0 )
9063 {
9064 val[k] = 1.0;
9065 ind[k] = row;
9066
9067 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
9068
9069 ++k;
9070 }
9071
9072 a <<= 1;
9073 ++row;
9074 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
9075 assert(POWEROFTWO(row) == a);
9076 }
9077
9078 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
9079 val[k] = 1.0;
9080 ind[k] = (int)nrows - 1;
9081 ++k;
9082 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9083 }
9084 assert(k == nnonz);
9085
9086 /* load all data into LP interface
9087 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9088 */
9089 assert(nrows <= ncols);
9091 (int)ncols, obj, lb, ub, NULL,
9092 (int)nrows, lb, lb, NULL,
9093 (int)nnonz, beg, ind, val) );
9094
9095 /* for the last row, we can set the rhs to 1.0 already */
9096 ind[0] = (int)nrows - 1;
9097 val[0] = 1.0;
9098 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9099
9100 /* free allocated memory */
9107
9108 return SCIP_OKAY;
9109}
9110
9111/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9112 * \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
9113 * set of vertices of the domain
9114 */
9115static
9117 SCIP* scip, /**< SCIP data structure */
9118 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9119 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9120 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9121 int nallvars, /**< number of all variables */
9122 int nvars, /**< number of unfixed variables */
9123 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9124 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9125 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9126 )
9127{
9128 SCIP_Real maxerror;
9129 SCIP_Real facetval;
9130 SCIP_Real funval;
9131 SCIP_Real error;
9132 unsigned int i;
9133 unsigned int ncorners;
9134 unsigned int prev;
9135
9136 assert(scip != NULL);
9137 assert(funvals != NULL);
9138 assert(box != NULL);
9139 assert(nonfixedpos != NULL);
9140 assert(facetcoefs != NULL);
9141
9142 ncorners = POWEROFTWO(nvars);
9143 maxerror = 0.0;
9144
9145 /* check the origin (all variables at lower bound) */
9146 facetval = facetconstant;
9147 for( i = 0; i < (unsigned int) nallvars; ++i )
9148 facetval += facetcoefs[i] * box[2*i];
9149
9150 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9151 funval = funvals[0];
9152 if( overestimate )
9153 error = funval - facetval;
9154 else
9155 error = facetval - funval;
9156
9157 /* update maximum error */
9158 maxerror = MAX(error, maxerror);
9159
9160 prev = 0;
9161 for( i = 1; i < ncorners; ++i )
9162 {
9163 unsigned int gray;
9164 unsigned int diff;
9165 unsigned int pos;
9166 int origpos;
9167
9168 gray = i ^ (i >> 1);
9169 diff = gray ^ prev;
9170
9171 /* compute position of unique 1 of diff */
9172 pos = 0;
9173 while( (diff >>= 1) != 0 )
9174 ++pos;
9175 assert(pos < (unsigned int)nvars);
9176
9177 origpos = nonfixedpos[pos];
9178
9179 if( gray > prev )
9180 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9181 else
9182 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9183
9184 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9185 funval = funvals[gray];
9186 if( overestimate )
9187 error = funval - facetval;
9188 else
9189 error = facetval - funval;
9190
9191 /* update maximum error */
9192 maxerror = MAX(error, maxerror);
9193
9194 prev = gray;
9195 }
9196
9197 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9198
9199 return maxerror;
9200}
9201
9202/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9203static
9205 SCIP* scip, /**< SCIP data structure */
9206 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9207 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9208 SCIP_Real* xstar, /**< point to be separated */
9209 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9210 int nallvars, /**< half of the length of box */
9211 int* nonfixedpos, /**< indices of nonfixed variables */
9212 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9213 int nvars, /**< number of nonfixed variables */
9214 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9215 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9216 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9217 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9218 )
9219{ /*lint --e{715}*/
9220 SCIP_CONSHDLRDATA* conshdlrdata;
9221 SCIP_LPI* lp;
9222 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9223 int* inds;
9224 int ncols;
9225 int nrows;
9226 int i;
9227 SCIP_Real facetvalue;
9228 SCIP_Real mindomwidth;
9229 SCIP_RETCODE lpsolveretcode;
9230
9231 assert(scip != NULL);
9232 assert(conshdlr != NULL);
9233 assert(xstar != NULL);
9234 assert(box != NULL);
9235 assert(nonfixedpos != NULL);
9236 assert(funvals != NULL);
9237 assert(nvars >= 0);
9238 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9239 assert(success != NULL);
9240 assert(facetcoefs != NULL);
9241 assert(facetconstant != NULL);
9242
9243 *success = FALSE;
9244
9245 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9246 assert(conshdlrdata != NULL);
9247
9248 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9249 {
9250 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9251 }
9252
9253 /* construct an LP for this size, if not having one already */
9254 if( conshdlrdata->vp_lp[nvars] == NULL )
9255 {
9256 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9257 }
9258 lp = conshdlrdata->vp_lp[nvars];
9259 assert(lp != NULL);
9260
9261 /* get number of cols and rows of separation lp */
9262 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9263 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9264
9265 /* number of columns should equal the number of corners = 2^nvars */
9266 assert(ncols == (int)POWEROFTWO(nvars));
9267
9268 /* allocate necessary memory */
9269 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9270 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9271
9272 /*
9273 * set up the described LP on the transformed space
9274 */
9275
9276 for( i = 0; i < ncols; ++i )
9277 inds[i] = i;
9278
9279 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9280 mindomwidth = 2*SCIPinfinity(scip);
9281 for( i = 0; i < nrows-1; ++i )
9282 {
9283 SCIP_Real solval;
9284 SCIP_Real lb;
9285 SCIP_Real ub;
9286 int varpos;
9287
9288 assert(i < nvars);
9289
9290 varpos = nonfixedpos[i];
9291 lb = box[2 * varpos];
9292 ub = box[2 * varpos + 1];
9293 solval = xstar[varpos];
9294
9295 if( ub - lb < mindomwidth )
9296 mindomwidth = ub - lb;
9297
9298 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9299 if( solval <= lb )
9300 aux[i] = 0.0;
9301 else if( solval >= ub )
9302 aux[i] = 1.0;
9303 else
9304 aux[i] = (solval - lb) / (ub - lb);
9305
9306 /* perturb point to hopefully obtain a facet of the convex envelope */
9307 if( conshdlrdata->vp_maxperturb > 0.0 )
9308 {
9309 assert(conshdlrdata->vp_randnumgen != NULL);
9310
9311 if( aux[i] == 1.0 )
9312 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9313 else if( aux[i] == 0.0 )
9314 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9315 else
9316 {
9317 SCIP_Real perturbation;
9318
9319 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9320 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9321 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9322 }
9323 assert(0.0 < aux[i] && aux[i] < 1.0);
9324 }
9325
9326 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9327 }
9328
9329 /* update LP */
9330 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9331 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9333
9334 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9335 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9336 {
9337 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9338 }
9339 /* set an iteration limit so we do not run forever */
9341 /* 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 */
9343 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9344 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9345 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9346 */
9348
9349#ifdef SCIP_DEBUG
9351#endif
9352
9353 /*
9354 * solve the LP and store the resulting facet for the transformed space
9355 */
9356 if( conshdlrdata->vp_dualsimplex )
9357 {
9358 lpsolveretcode = SCIPlpiSolveDual(lp);
9359 }
9360 else
9361 {
9362 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9363 }
9364 if( lpsolveretcode == SCIP_LPERROR )
9365 {
9366 SCIPdebugMsg(scip, "LP error, aborting.\n");
9367 goto CLEANUP;
9368 }
9369 SCIP_CALL( lpsolveretcode );
9370
9371 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9372 if( !SCIPlpiIsDualFeasible(lp) )
9373 {
9374 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9375 goto CLEANUP;
9376 }
9377
9378 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9379 * columns than needed, in particular, \bar \beta is the last dual multiplier
9380 */
9381 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9382
9383 for( i = 0; i < nvars; ++i )
9384 facetcoefs[nonfixedpos[i]] = aux[i];
9385 /* last dual multiplier is the constant */
9386 *facetconstant = aux[nrows - 1];
9387
9388#ifdef SCIP_DEBUG
9389 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9390 for( i = 0; i < nallvars; ++i )
9391 {
9392 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9393 }
9394 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9395#endif
9396
9397 /*
9398 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9399 */
9400
9401 SCIPdebugMsg(scip, "facet in orig. space: ");
9402
9403 facetvalue = 0.0;
9404 for( i = 0; i < nvars; ++i )
9405 {
9406 SCIP_Real lb;
9407 SCIP_Real ub;
9408 int varpos;
9409
9410 varpos = nonfixedpos[i];
9411 lb = box[2 * varpos];
9412 ub = box[2 * varpos + 1];
9413 assert(!SCIPisEQ(scip, lb, ub));
9414
9415 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9416 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9417
9418 /* beta = beta_bar - sum_i alpha_i * lb_i */
9419 *facetconstant -= facetcoefs[varpos] * lb;
9420
9421 /* evaluate */
9422 facetvalue += facetcoefs[varpos] * xstar[varpos];
9423
9424 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9425 }
9426 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9427
9428 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9429 facetvalue += *facetconstant;
9430
9431 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9432
9433 /* if overestimate, then we want facetvalue < targetvalue
9434 * if underestimate, then we want facetvalue > targetvalue
9435 * if none holds, give up
9436 * so maybe here we should check against the minimal violation
9437 */
9438 if( overestimate == (facetvalue > targetvalue) )
9439 {
9440 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9441 goto CLEANUP;
9442 }
9443
9444 /* if we made it until here, then we have a nice facet */
9445 *success = TRUE;
9446
9447CLEANUP:
9448 /* free allocated memory */
9449 SCIPfreeBufferArray(scip, &inds);
9451
9452 return SCIP_OKAY;
9453}
9454
9455/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9456 *
9457 * In other words, compute the line that passes through two given points.
9458 */
9459static
9461 SCIP* scip, /**< SCIP data structure */
9462 SCIP_Real left, /**< left coordinate */
9463 SCIP_Real right, /**< right coordinate */
9464 SCIP_Real funleft, /**< value of function in left coordinate */
9465 SCIP_Real funright, /**< value of function in right coordinate */
9466 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9467 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9468 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9469 )
9470{
9471 assert(scip != NULL);
9472 assert(SCIPisLE(scip, left, right));
9473 assert(!SCIPisInfinity(scip, -left));
9474 assert(!SCIPisInfinity(scip, right));
9475 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9476 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9477 assert(success != NULL);
9478 assert(facetcoef != NULL);
9479 assert(facetconstant != NULL);
9480
9481 *facetcoef = (funright - funleft) / (right - left);
9482 *facetconstant = funleft - *facetcoef * left;
9483
9484 *success = TRUE;
9485
9486 return SCIP_OKAY;
9487}
9488
9489/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9490 *
9491 * Three points a, b, and c are given.
9492 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9493 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9494 */
9495static
9497 SCIP* scip, /**< SCIP data structure */
9498 SCIP_Real a1, /**< first coordinate of a */
9499 SCIP_Real a2, /**< second coordinate of a */
9500 SCIP_Real a3, /**< third coordinate of a */
9501 SCIP_Real b1, /**< first coordinate of b */
9502 SCIP_Real b2, /**< second coordinate of b */
9503 SCIP_Real b3, /**< third coordinate of b */
9504 SCIP_Real c1, /**< first coordinate of c */
9505 SCIP_Real c2, /**< second coordinate of c */
9506 SCIP_Real c3, /**< third coordinate of c */
9507 SCIP_Real* alpha, /**< coefficient of first coordinate */
9508 SCIP_Real* beta, /**< coefficient of second coordinate */
9509 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9510 SCIP_Real* delta /**< constant right-hand side */
9511 )
9512{
9513 assert(scip != NULL);
9514 assert(alpha != NULL);
9515 assert(beta != NULL);
9516 assert(gamma_ != NULL);
9517 assert(delta != NULL);
9518
9519 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9520 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9521 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9522 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9523
9524 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9525
9526 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9527 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9528 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9529 {
9530 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9531 *delta = 0.0;
9532 *alpha = 0.0;
9533 *beta = 0.0;
9534 *gamma_ = 0.0;
9535 return SCIP_OKAY;
9536 }
9537
9538 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9539 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9540 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9541 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9542 {
9543 SCIP_Real m[9];
9544 SCIP_Real rhs[3];
9545 SCIP_Real x[3];
9546 SCIP_Bool success;
9547
9548 /*
9549 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));
9550 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));
9551 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));
9552 */
9553
9554 /* initialize matrix column-wise */
9555 m[0] = a1;
9556 m[1] = b1;
9557 m[2] = c1;
9558 m[3] = a2;
9559 m[4] = b2;
9560 m[5] = c2;
9561 m[6] = a3;
9562 m[7] = b3;
9563 m[8] = c3;
9564
9565 rhs[0] = 1.0;
9566 rhs[1] = 1.0;
9567 rhs[2] = 1.0;
9568
9569 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9570
9571 /* solve the linear problem */
9572 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9573
9574 *delta = rhs[0];
9575 *alpha = x[0];
9576 *beta = x[1];
9577 *gamma_ = x[2];
9578
9579 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9580 * not add a cut to SCIP and that all assertions are trivially fulfilled
9581 */
9582 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9583 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9584 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9585 {
9586 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9587 *delta = 0.0;
9588 *alpha = 0.0;
9589 *beta = 0.0;
9590 *gamma_ = 0.0;
9591 }
9592 }
9593
9594 if( *gamma_ < 0.0 )
9595 {
9596 *alpha = -*alpha;
9597 *beta = -*beta;
9598 *gamma_ = -*gamma_;
9599 *delta = -*delta;
9600 }
9601
9602 return SCIP_OKAY;
9603}
9604
9605/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9606static
9608 SCIP* scip, /**< SCIP data structure */
9609 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9610 SCIP_Real p1[2], /**< first vertex of box */
9611 SCIP_Real p2[2], /**< second vertex of box */
9612 SCIP_Real p3[2], /**< third vertex of box */
9613 SCIP_Real p4[2], /**< forth vertex of box */
9614 SCIP_Real p1val, /**< value in p1 */
9615 SCIP_Real p2val, /**< value in p2 */
9616 SCIP_Real p3val, /**< value in p3 */
9617 SCIP_Real p4val, /**< value in p4 */
9618 SCIP_Real xstar[2], /**< point to be separated */
9619 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9620 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9621 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9622 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9623 )
9624{
9625 SCIP_Real alpha, beta, gamma_, delta;
9626 SCIP_Real xstarval, candxstarval = 0.0;
9627 int leaveout;
9628
9629 assert(scip != NULL);
9630 assert(success != NULL);
9631 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9632 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9633 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9634 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9635 assert(facetcoefs != NULL);
9636 assert(facetconstant != NULL);
9637
9638 *success = FALSE;
9639
9640 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9641 if( !overestimate )
9642 {
9643 p1val = -p1val;
9644 p2val = -p2val;
9645 p3val = -p3val;
9646 p4val = -p4val;
9647 targetvalue = -targetvalue;
9648 }
9649
9650 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9651 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9652 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9653 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9654
9655 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9656 * alpha*x + beta*y + gamma*z = delta
9657 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9658 * the fourth corner point lies below this hyperplane.
9659 * 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.,
9660 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9661 * or, equivalently,
9662 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9663 */
9664 for( leaveout = 1; leaveout <= 4; ++leaveout )
9665 {
9666 switch( leaveout)
9667 {
9668 case 1 :
9669 /* get hyperplane through p2, p3, p4 */
9670 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9671 &alpha, &beta, &gamma_, &delta) );
9672 /* if not underestimating in p1, then go to next candidate */
9673 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9674 continue;
9675 break;
9676
9677 case 2 :
9678 /* get hyperplane through p1, p3, p4 */
9679 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9680 &alpha, &beta, &gamma_, &delta) );
9681 /* if not underestimating in p2, then go to next candidate */
9682 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9683 continue;
9684 break;
9685
9686 case 3 :
9687 /* get hyperplane through p1, p2, p4 */
9688 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9689 &alpha, &beta, &gamma_, &delta) );
9690 /* if not underestimating in p3, then go to next candidate */
9691 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9692 continue;
9693 break;
9694
9695 case 4 :
9696 /* get hyperplane through p1, p2, p3 */
9697 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9698 &alpha, &beta, &gamma_, &delta) );
9699 /* if not underestimating in p4, then stop */
9700 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9701 continue;
9702 break;
9703
9704 default: /* only for lint */
9705 alpha = SCIP_INVALID;
9706 beta = SCIP_INVALID;
9707 gamma_ = SCIP_INVALID;
9708 delta = SCIP_INVALID;
9709 break;
9710 }
9711
9712 /* check if bad luck: should not happen if numerics are fine */
9713 if( SCIPisZero(scip, gamma_) )
9714 continue;
9715 assert(!SCIPisNegative(scip, gamma_));
9716
9717 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9718 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9719 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9720 continue;
9721
9722 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9723
9724 /* value of hyperplane candidate in xstar */
9725 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9726
9727 /* if reaching target and first or better than previous candidate, then update */
9728 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9729 {
9730 /* flip hyperplane */
9731 if( !overestimate )
9732 gamma_ = -gamma_;
9733
9734 facetcoefs[0] = -alpha/gamma_;
9735 facetcoefs[1] = -beta/gamma_;
9736 *facetconstant = delta/gamma_;
9737
9738 *success = TRUE;
9739 candxstarval = xstarval;
9740 }
9741 }
9742
9743 return SCIP_OKAY;
9744}
9745
9746/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9747 * graph yet) in an array
9748 */
9749static
9751 SCIP* scip, /**< SCIP pointer */
9752 int** openidx, /**< address of openidx array */
9753 int nelems, /**< number of elements that need to be stored */
9754 int* maxnelems /**< pointer to store maximum number that can be stored */
9755 )
9756{
9757 assert(scip != NULL);
9758 assert(openidx != NULL);
9759 assert(maxnelems != NULL);
9760
9761 if( nelems > *maxnelems )
9762 {
9763 int newsize;
9764
9765 newsize = SCIPcalcMemGrowSize(scip, nelems);
9766 assert(newsize >= nelems);
9767
9768 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9769
9770 *maxnelems = newsize;
9771 }
9772
9773 return SCIP_OKAY;
9774}
9775
9776/** ensures that we can store information about local variables in an array */
9777static
9779 SCIP* scip, /**< SCIP pointer */
9780 SCIP_VAR*** vars, /**< address of variable array */
9781 SCIP_Real** vals, /**< address of value array */
9782 int nelems, /**< number of elements that need to be stored */
9783 int* maxnelems /**< pointer to store maximum number that can be stored */
9784 )
9785{
9786 assert(scip != NULL);
9787 assert(vars != NULL);
9788 assert(vals != NULL);
9789 assert(maxnelems != NULL);
9790
9791 if( nelems > *maxnelems )
9792 {
9793 int newsize;
9794
9795 newsize = SCIPcalcMemGrowSize(scip, nelems);
9796 assert(newsize > *maxnelems);
9797
9798 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
9799 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9800
9801 *maxnelems = newsize;
9802 }
9803
9804 return SCIP_OKAY;
9805}
9806
9807/** tries to add gadget for finding signed permutations of bilinear products
9808 *
9809 * If a product has exactly two children being variables, negating both simultanteoulsy
9810 * is a signed permutation.
9811 */
9812static
9814 SCIP* scip, /**< SCIP pointer */
9815 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9816 SCIP_CONS* cons, /**< constraint containing product expression */
9817 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9818 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9819 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9820 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9821 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9822 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9823 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9824 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9825 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9826 )
9827{
9828 SYM_EXPRDATA* symdata;
9829 SCIP_EXPR** children;
9830 SCIP_VAR* var1 = NULL;
9831 SCIP_VAR* var2 = NULL;
9832 SCIP_Real val1 = 0.0;
9833 SCIP_Real val2 = 0.0;
9834 SCIP_Real coef;
9835 SCIP_Real prodval;
9836 SCIP_Real constant;
9837 int nlocvars;
9838 int optype;
9839 int nchildren;
9840 int prodidx;
9841 int coefidx1;
9842 int coefidx2;
9843 int childidx;
9844
9845 assert(scip != NULL);
9846 assert(expr != NULL);
9847 assert(SCIPisExprProduct(scip, expr));
9848 assert(graph != NULL);
9849 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9850 assert(consvars != NULL);
9851 assert(consvals != NULL);
9852 assert(maxnconsvars != NULL);
9853 assert(*maxnconsvars > 0);
9854 assert(handledexprs != NULL);
9855 assert(success != NULL);
9856
9857 *success = FALSE;
9858
9859 /* we require exactly two children being variables */
9860 nchildren = SCIPexprGetNChildren(expr);
9861 if( nchildren != 2 )
9862 return SCIP_OKAY;
9863
9864 children = SCIPexprGetChildren(expr);
9865 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9866 return SCIP_OKAY;
9867
9868 /* check whether each child is not multi-aggregated and is not shifted */
9869 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9870
9871 for( childidx = 0; childidx < 2; ++childidx )
9872 {
9873 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9874 (*consvals)[0] = 1.0;
9875 nlocvars = 1;
9876 constant = 0.0;
9877
9878 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9879 &constant, SCIPconsIsTransformed(cons)) );
9880
9881 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9882 return SCIP_OKAY;
9883
9884 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9885 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9886 return SCIP_OKAY;
9887
9888 /* store information about variables */
9889 if( childidx == 0 )
9890 {
9891 var1 = (*consvars)[0];
9892 val1 = (*consvals)[0];
9893 }
9894 else
9895 {
9896 var2 = (*consvars)[0];
9897 val2 = (*consvals)[0];
9898 }
9899 }
9900 assert(var1 != NULL);
9901 assert(var2 != NULL);
9902
9903 /* store the we handle the children */
9904 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9905 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9906
9907 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9908 assert(symdata != NULL);
9909 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9910
9911 coef = SCIPgetSymExprdataConstants(symdata)[0];
9912
9913 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9914
9915 /* add gadget modeling the product
9916 *
9917 * Since the constants are 0, each variable is centered at the origin, which leads to
9918 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9919 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9920 * negate both variables simulataneously.
9921 */
9923 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9924 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9925
9926 prodval = coef * val1 * val2;
9927
9928 /* introduce nodes for the product value and its negation; since flipping both variables
9929 * simultaneously is a signed symmetry, assign both nodes the same value
9930 */
9931 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
9932 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
9933
9934 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
9935 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
9936 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
9937
9938 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9939 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9940 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9941 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9942 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9943 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9944 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9945 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9946
9947 *success = TRUE;
9948
9949 return SCIP_OKAY;
9950}
9951
9952/** returns whether an operator is even and, if yes, stores data about operator */
9953static
9955 SCIP* scip, /**< SCIP pointer */
9956 SCIP_EXPR* expr, /**< expression corresponding to operator */
9957 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
9958 * needed for symmetry computation */
9959 SCIP_Real* value /**< pointer to store value for symmetry computation */
9960 )
9961{
9962 SYM_EXPRDATA* symdata;
9963
9964 assert(scip != NULL);
9965 assert(expr != NULL);
9966 assert(hasvalue != NULL);
9967 assert(value != NULL);
9968
9969 /* check for different operators known to be even */
9970 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9971 {
9972 /* get remaining information needed for symmetry detection */
9973 if( SCIPisExprSignpower(scip, expr) )
9974 {
9975 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9976 assert(symdata != NULL);
9977 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9978
9979 *value = SCIPgetSymExprdataConstants(symdata)[0];
9980 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9981
9983 }
9984 else
9985 {
9986 assert(SCIPisExprCos(scip, expr));
9987 *hasvalue = FALSE;
9988 }
9989
9990 return TRUE;
9991 }
9992 else if( SCIPisExprPower(scip, expr) )
9993 {
9994 SCIP_Real exponent;
9995 int safeexponent;
9996
9997 /* only consider expressions corresponding to an even power */
9998 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9999 assert(symdata != NULL);
10000 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10001
10002 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10004
10005 /* check whether the exponent is an even integer */
10006 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
10007 return FALSE;
10008
10009 /* deal with numerics */
10010 safeexponent = (int) (exponent + 0.5);
10011 if( safeexponent % 2 != 0 )
10012 return FALSE;
10013
10014 *hasvalue = TRUE;
10015 *value = exponent;
10016
10017 return TRUE;
10018 }
10019 else if( SCIPisExprAbs(scip, expr) )
10020 {
10021 *hasvalue = FALSE;
10022
10023 return TRUE;
10024 }
10025
10026 return FALSE;
10027}
10028
10029/** returns whether a variable is centered at 0 */
10030static
10032 SCIP* scip, /**< SCIP pointer */
10033 SCIP_VAR* var /**< variable to be checked */
10034 )
10035{
10036 assert(scip != NULL);
10037 assert(var != NULL);
10038
10040 return FALSE;
10041
10043 return TRUE;
10044
10046 return TRUE;
10047
10048 return FALSE;
10049}
10050
10051/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
10052static
10054 SCIP* scip, /**< SCIP pointer */
10055 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10056 SCIP_EXPR* child, /**< child expression of evenopexpr */
10057 SCIP_CONS* cons, /**< constraint containing expression */
10058 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10059 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10060 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10061 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10062 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10063 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10064 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10065 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10066 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10067 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10068 )
10069{
10070 SCIP_VAR* var;
10071 SCIP_Real constant;
10072 SCIP_Real edgeweight;
10073 int nlocvars;
10074 int nodeidx;
10075 int optype;
10076 int thisopidx;
10077
10078 assert(scip != NULL);
10079 assert(evenopexpr != NULL);
10080 assert(child != NULL);
10081 assert(SCIPisExprVar(scip, child));
10082 assert(cons != NULL);
10083 assert(graph != NULL);
10084 assert(parentidx >= 0);
10085 assert(consvars != NULL);
10086 assert(consvals != NULL);
10087 assert(maxnconsvars != NULL);
10088 assert(success != NULL);
10089
10090 *success = FALSE;
10091
10092 /* check whether child variable is (multi-)aggregated */
10093 var = SCIPgetVarExprVar(child);
10094 (*consvars)[0] = var;
10095 (*consvals)[0] = 1.0;
10096 constant = 0.0;
10097 nlocvars = 1;
10098
10099 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10100 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10101 SCIPconsIsTransformed(cons)) );
10102
10103 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10104 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10105 return SCIP_OKAY;
10106
10107 if( !varIsCenteredAt0(scip, var) )
10108 return SCIP_OKAY;
10109
10110 /* store partial information for gadget */
10111 var = (*consvars)[0];
10112 edgeweight = (*consvals)[0];
10113
10114 /* add gadget to graph for even univariate expression */
10115 *success = TRUE;
10116
10118
10119 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10120 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10121
10122 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10123 TRUE, edgeweight) );
10125 TRUE, edgeweight) );
10126
10127 if( hassymval )
10128 {
10129 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10130 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10131 }
10132
10133 return SCIP_OKAY;
10134}
10135
10136/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10137static
10139 SCIP* scip, /**< SCIP pointer */
10140 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10141 SCIP_EXPR* child, /**< child expression of evenopexpr */
10142 SCIP_CONS* cons, /**< constraint containing expression */
10143 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10144 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10145 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10146 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10147 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10148 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10149 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10150 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10151 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10152 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10153 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10154 )
10155{
10156 SCIP_VAR* var;
10157 SCIP_Real constant;
10158 SCIP_Real weight;
10159 int nlocvars;
10160 int nodeidx;
10161 int optype;
10162 int thisopidx;
10163 int i;
10164
10165 assert(scip != NULL);
10166 assert(evenopexpr != NULL);
10167 assert(child != NULL);
10168 assert(SCIPisExprSum(scip, child));
10169 assert(cons != NULL);
10170 assert(graph != NULL);
10171 assert(parentidx >= 0);
10172 assert(consvars != NULL);
10173 assert(consvals != NULL);
10174 assert(maxnconsvars != NULL);
10175 assert(handledexprs != NULL);
10176 assert(success != NULL);
10177
10178 *success = FALSE;
10179
10180 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10181 nlocvars = SCIPexprGetNChildren(child);
10182
10183 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10184
10185 for( i = 0; i < nlocvars; ++i)
10186 {
10187 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10188 {
10189 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10190 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10191 }
10192 else
10193 return SCIP_OKAY;
10194 }
10195 constant = SCIPgetConstantExprSum(child);
10196
10197 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10198 SCIPconsIsTransformed(cons)) );
10199
10200 /* we can only handle the case without constant and two variables with domain centered at origin */
10201 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10202 return SCIP_OKAY;
10203 assert(nlocvars > 0);
10204
10205 var = (*consvars)[0];
10206 if( !varIsCenteredAt0(scip, var) )
10207 return SCIP_OKAY;
10208
10209 if( nlocvars == 2 )
10210 {
10211 var = (*consvars)[1];
10212 if( !varIsCenteredAt0(scip, var) )
10213 return SCIP_OKAY;
10214 }
10215
10216 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10217 *success = TRUE;
10218 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10219 {
10220 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10221 }
10222
10224
10225 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10226 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10227
10228 if( hassymval )
10229 {
10230 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10231 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10232 }
10233
10234 if( nlocvars == 1 )
10235 {
10236 var = (*consvars)[0];
10237 weight = (*consvals)[0];
10238
10239 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10240 TRUE, weight) );
10242 TRUE, weight) );
10243 }
10244 else
10245 {
10246 int dummyidx1;
10247 int dummyidx2;
10248
10249 /* add dummy nodes for gadget */
10250 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10251 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10252
10253 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10254 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10255 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10256
10257 /* connect dummy nodes with variables */
10258 for( i = 0; i < 2; ++i)
10259 {
10260 var = (*consvars)[i];
10261 weight = ABS((*consvals)[i]);
10262
10263 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10264 TRUE, weight) );
10266 TRUE, weight) );
10267 }
10268 }
10269
10270 return SCIP_OKAY;
10271}
10272
10273/** tries to add gadget for finding signed permutations of even univariate operators
10274 *
10275 * We handle two cases. First, if a univariate operator is even and has a variable
10276 * as child, negating the child is signed permutation. Second, the univariate operator
10277 * is even and has a weighted sum of two variables as child.
10278 */
10279static
10281 SCIP* scip, /**< SCIP pointer */
10282 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10283 SCIP_CONS* cons, /**< constraint containing expression */
10284 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10285 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10286 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10287 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10288 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10289 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10290 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10291 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10292 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10293 )
10294{
10295 SCIP_EXPR* child;
10296 SCIP_Real val = 0.0;
10297 SCIP_Bool hasval = FALSE;
10298
10299 assert(scip != NULL);
10300 assert(expr != NULL);
10301 assert(graph != NULL);
10302 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10303 assert(consvars != NULL);
10304 assert(consvals != NULL);
10305 assert(maxnconsvars != NULL);
10306 assert(*maxnconsvars > 0);
10307 assert(handledexprs != NULL);
10308 assert(success != NULL);
10309
10310 *success = FALSE;
10311
10312 /* ignore variable or value expressions */
10313 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10314 return SCIP_OKAY;
10315 assert(SCIPexprGetNChildren(expr) > 0);
10316
10317 /* ignore operators with too many children */
10318 if( SCIPexprGetNChildren(expr) > 1 )
10319 return SCIP_OKAY;
10320
10321 /* check whether operator is even */
10322 if( !isEvenOperator(scip, expr, &hasval, &val) )
10323 return SCIP_OKAY;
10324
10325 /* we can only treat the operator if its child is a variable or a sum */
10326 child = SCIPexprGetChildren(expr)[0];
10327 if( SCIPisExprVar(scip, child) )
10328 {
10329 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10330 hasval, val, consvars, consvals, maxnconsvars, success) );
10331 }
10332 else if( SCIPisExprSum(scip, child) )
10333 {
10334 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10335 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10336 }
10337
10338 if( *success )
10339 {
10340 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10341 }
10342
10343 return SCIP_OKAY;
10344}
10345
10346/** compares two variable pointers */
10347static
10349{ /*lint --e{715}*/
10350 SCIP_VAR** vars;
10351 SCIP_VAR* var1;
10352 SCIP_VAR* var2;
10353
10354 vars = (SCIP_VAR**) dataptr;
10355
10356 var1 = vars[ind1];
10357 var2 = vars[ind2];
10358 assert(var1 != NULL);
10359 assert(var2 != NULL);
10360
10361 /* sort variables by their unique index */
10362 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10363 return -1;
10364 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10365 return 1;
10366
10367 return 0;
10368}
10369
10370/** gets domain center of a variable which has not semi-infinite domain */
10371static
10373 SCIP* scip, /**< SCIP pointer */
10374 SCIP_VAR* var /**< variable */
10375 )
10376{
10377 SCIP_Real ub;
10378 SCIP_Real lb;
10379
10380 ub = SCIPvarGetUbGlobal(var);
10381 lb = SCIPvarGetLbGlobal(var);
10382
10383 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10384
10385 if ( SCIPisInfinity(scip, ub) )
10386 return 0.0;
10387
10388 return (ub + lb) / 2;
10389}
10390
10391/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10392static
10394 SCIP* scip, /**< SCIP pointer */
10395 SCIP_EXPR* sumexpr, /**< sum expression */
10396 SCIP_CONS* cons, /**< constraint containing the sum expression */
10397 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10398 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10399 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10400 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10401 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10402 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10403 )
10404{
10405 SYM_EXPRDATA* symdata;
10406 SCIP_EXPR** children;
10407 SCIP_EXPR** powexprs;
10408 SCIP_EXPR** prodexprs;
10409 SCIP_EXPR* child;
10410 SCIP_VAR** powvars;
10411 SCIP_VAR** prodvars;
10412 SCIP_VAR* actvar;
10413 SCIP_VAR* actvar2;
10414 SCIP_VAR* var;
10415 SCIP_VAR* var2;
10416 SCIP_Real* sumcoefs;
10417 SCIP_Real constant;
10418 SCIP_Real constant2;
10419 SCIP_Real val;
10420 SCIP_Real val2;
10421 SCIP_Bool* powexprused = NULL;
10422 int* powperm = NULL;
10423 int* prodperm = NULL;
10424 int nchildren;
10425 int nlocvars;
10426 int nodeidx;
10427 int coefnodeidx1;
10428 int coefnodeidx2;
10429 int cnt;
10430 int i;
10431 int j;
10432 int nterms;
10433 int npowexprs = 0;
10434 int nprodexprs = 0;
10435 int powcoef = 0;
10436
10437 assert(scip != NULL);
10438 assert(sumexpr != NULL);
10439 assert(cons != NULL);
10440 assert(SCIPisExprSum(scip, sumexpr));
10441 assert(consvars != NULL);
10442 assert(consvals != NULL);
10443 assert(maxnconsvars != NULL);
10444 assert(*maxnconsvars > 0);
10445 assert(handledexprs != NULL);
10446
10447 /* iterate over sum expression and extract all power and product expressions */
10448 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10449 children = SCIPexprGetChildren(sumexpr);
10450 nchildren = SCIPexprGetNChildren(sumexpr);
10451 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10452 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10453 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10454 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10455
10456 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10457 /** @todo make this work in a more general case */
10458 for( i = 0; i < nchildren; ++i )
10459 {
10460 if( SCIPisExprPower(scip, children[i]) )
10461 {
10462 SCIP_Real exponent;
10463
10464 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10465 if( powcoef == 0 )
10466 {
10467 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10468 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10469 }
10470 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10471 continue;
10472
10473 /* we only store power expressions if their child is a variable */
10474 assert(SCIPexprGetNChildren(children[i]) == 1);
10475 child = SCIPexprGetChildren(children[i])[0];
10476 if( !SCIPisExprVar(scip, child) )
10477 continue;
10478
10479 /* the power is required to be a 2 */
10480 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10481 assert(symdata != NULL);
10482 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10483
10484 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10485 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10486
10487 if( !SCIPisEQ(scip, exponent, 2.0) )
10488 continue;
10489
10490 /* we only store power expressions if the child is not multi-aggregated */
10491 var = SCIPgetVarExprVar(child);
10493 {
10494 powexprs[npowexprs] = children[i];
10495 powvars[npowexprs++] = var;
10496 }
10497 }
10498 else if( SCIPisExprProduct(scip, children[i]) )
10499 {
10500 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10501 if( powcoef == 0 )
10502 {
10503 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10504 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10505 }
10506 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10507 continue;
10508
10509 /* we only store power expressions if they have exactly two children being variables */
10510 if( SCIPexprGetNChildren(children[i]) != 2 )
10511 continue;
10512 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10513 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10514 continue;
10515
10516 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10517 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10518
10519 /* we only store product expressions if the children are not multi-aggregated */
10522 {
10523 prodexprs[nprodexprs] = children[i];
10524 prodvars[nprodexprs++] = var;
10525 prodexprs[nprodexprs] = children[i];
10526 prodvars[nprodexprs++] = var2;
10527 }
10528 }
10529 }
10530
10531 if( npowexprs == 0 || nprodexprs != npowexprs )
10532 goto FREEMEMORY;
10533
10534 /* check whether the power variables and product variables match */
10535 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10536 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10537
10538 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10539 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10540
10541 for( i = 0; i < npowexprs; ++i )
10542 {
10543 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10544 goto FREEMEMORY;
10545 }
10546
10547 /* if we reach this line, the variables match: we have found a potential norm constraint */
10548 assert(npowexprs % 2 == 0);
10549 nterms = npowexprs / 2;
10550 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10551
10552 /* add gadget of each squared difference term */
10553 cnt = 0;
10554 for( i = 0; i < nterms; ++i )
10555 {
10556 SCIP_Bool var1found = FALSE;
10557 SCIP_Bool var2found = FALSE;
10558
10559 (*consvals)[0] = 1.0;
10560 (*consvars)[0] = prodvars[cnt++];
10561 constant = 0.0;
10562 nlocvars = 1;
10563
10565 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10566
10567 if( nlocvars != 1 )
10568 {
10569 ++cnt;
10570 continue;
10571 }
10572 actvar = (*consvars)[0];
10573 val = (*consvals)[0];
10574
10575 (*consvals)[0] = 1.0;
10576 (*consvars)[0] = prodvars[cnt++];
10577 constant2 = 0.0;
10578 nlocvars = 1;
10579
10581 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10582
10583 if( nlocvars != 1 )
10584 continue;
10585 actvar2 = (*consvars)[0];
10586 val2 = (*consvals)[0];
10587
10588 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10589 * cannot be centered at the origin or they are not centered around the same point
10590 */
10591 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10595 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10596 continue;
10597
10598 /* add gadget */
10599 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10600 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10601 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10602
10603 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10604 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10605 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10606 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10607 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10608 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10609 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10610 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10611 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10612 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10613 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10614
10615 /* mark product expression as handled */
10616 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10617
10618 /* find corresponding unused power expressions and mark them as handled */
10619 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10620 {
10621 if( powexprused[j] )
10622 continue;
10623 assert(cnt >= 2);
10624
10625 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10626 {
10627 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10628 powexprused[j] = TRUE;
10629 var1found = TRUE;
10630 }
10631 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10632 {
10633 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10634 powexprused[j] = TRUE;
10635 var2found = TRUE;
10636 }
10637 }
10638 }
10639
10640 FREEMEMORY:
10641 SCIPfreeBufferArrayNull(scip, &powexprused);
10642 SCIPfreeBufferArrayNull(scip, &prodperm);
10643 SCIPfreeBufferArrayNull(scip, &powperm);
10644 SCIPfreeBufferArray(scip, &prodvars);
10645 SCIPfreeBufferArray(scip, &powvars);
10646 SCIPfreeBufferArray(scip, &prodexprs);
10647 SCIPfreeBufferArray(scip, &powexprs);
10648
10649 return SCIP_OKAY;
10650}
10651
10652/** adds symmetry information of constraint to a symmetry detection graph */
10653static
10655 SCIP* scip, /**< SCIP pointer */
10656 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10657 SCIP_CONS* cons, /**< constraint */
10658 SYM_GRAPH* graph, /**< symmetry detection graph */
10659 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10660 )
10661{ /*lint --e{850}*/
10662 SCIP_EXPRITER* it;
10663 SCIP_HASHSET* handledexprs;
10664 SCIP_EXPR* rootexpr;
10665 SCIP_EXPR* expr;
10666 SCIP_VAR** consvars;
10667 SCIP_Real* consvals;
10668 SCIP_Real constant;
10669 SCIP_Real parentcoef = 0.0;
10670 int* openidx;
10671 int maxnopenidx;
10672 int parentidx;
10673 int nconsvars;
10674 int maxnconsvars;
10675 int nlocvars;
10676 int nopenidx = 0;
10677 int consnodeidx;
10678 int nodeidx;
10679 int i;
10680 SCIP_Bool iscolored;
10681 SCIP_Bool hasparentcoef;
10682
10683 assert(scip != NULL);
10684 assert(cons != NULL);
10685 assert(graph != NULL);
10686 assert(success != NULL);
10687
10688 /* store lhs/rhs */
10690 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10691
10692 rootexpr = SCIPgetExprNonlinear(cons);
10693 assert(rootexpr != NULL);
10694
10695 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10696 expr = SCIPgetExprNonlinear(cons);
10697 assert(expr != NULL);
10698
10702
10703 /* find potential number of nodes in graph */
10704 maxnopenidx = 0;
10705 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10706 {
10708 continue;
10709
10710 ++maxnopenidx;
10711 }
10712
10713 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10714
10715 maxnconsvars = SCIPgetNVars(scip);
10716 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10717 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10718
10719 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10720 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10721
10722 /* iterate over expression tree and store nodes/edges */
10723 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10726
10727 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10728 {
10729 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10730 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10731 {
10732 SCIP_EXPR* baseexpr;
10733
10734 baseexpr = expr;
10735 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10736 expr = SCIPexpriterGetNext(it);
10737
10738 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10739
10740 /* leave the expression */
10741 continue;
10742 }
10743
10744 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10746 {
10747 --nopenidx;
10748 continue;
10749 }
10751
10752 /* find parentidx */
10753 if( expr == rootexpr )
10754 parentidx = consnodeidx;
10755 else
10756 {
10757 assert(nopenidx >= 1);
10758 parentidx = openidx[nopenidx - 1];
10759 }
10760
10761 /* possibly find a coefficient assigned to the expression by the parent */
10762 hasparentcoef = FALSE;
10763 if ( expr != rootexpr )
10764 {
10765 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10766 }
10767
10768 /* deal with different kinds of expressions and store them in the symmetry data structure */
10769 if( SCIPisExprVar(scip, expr) )
10770 {
10771 /* needed to correctly reset value when leaving expression */
10772 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10773
10774 openidx[nopenidx++] = -1;
10775
10776 assert(maxnconsvars > 0);
10777 assert(parentidx > 0);
10778
10779 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10780 if( hasparentcoef )
10781 {
10782 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10783
10784 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10785 parentidx = nodeidx;
10786 }
10787
10788 /* connect (aggregation of) variable expression with its parent */
10789 nconsvars = 1;
10790 consvars[0] = SCIPgetVarExprVar(expr);
10791 consvals[0] = 1.0;
10792 constant = 0.0;
10793
10794 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10795 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10796
10797 /* check whether variable is aggregated */
10798 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10799 {
10800 int thisidx;
10801
10802 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10803 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10804
10805 parentidx = thisidx;
10806 }
10807 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10808 nconsvars, constant) );
10809 }
10810 else if( SCIPisExprValue(scip, expr) )
10811 {
10812 assert(parentidx > 0);
10813
10814 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10815
10816 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10817
10818 /* needed to correctly reset value when leaving expression */
10819 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10820
10821 openidx[nopenidx++] = -1;
10822 }
10823 else
10824 {
10825 SCIP_Bool usedefaultgadget = TRUE;
10826
10827 assert(expr == rootexpr || parentidx > 0);
10828 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10829
10830 if( SCIPisExprSum(scip, expr) )
10831 {
10832 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10833 SCIP_EXPR** children;
10834 int sumidx;
10835 int optype;
10836 int childidx;
10837
10838 /* sums are handled by a special gadget */
10839 usedefaultgadget = FALSE;
10840
10841 /* extract all children being variables and compute the sum of active variables expression */
10842 nlocvars = 0;
10843 children = SCIPexprGetChildren(expr);
10844
10845 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10846
10847 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10848 {
10849 if( !SCIPisExprVar(scip, children[childidx]) )
10850 continue;
10851
10852 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10853 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10854
10855 /* store that we have already handled this expression */
10856 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10857 }
10858
10859 constant = SCIPgetConstantExprSum(expr);
10860
10861 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10862 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10863
10865
10866 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10867 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10868
10869 /* add the linear part of the sum */
10870 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10871
10872 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10873
10874 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10875 if( symtype == SYM_SYMTYPE_SIGNPERM )
10876 {
10877 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10878 &consvars, &consvals, &maxnconsvars, handledexprs) );
10879 }
10880
10881 /* store sumidx for children that have not been treated */
10882 openidx[nopenidx++] = sumidx;
10883 }
10884 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10885 {
10886 SCIP_Bool succ;
10887
10888 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10889 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10890
10891 if( succ )
10892 {
10893 usedefaultgadget = FALSE;
10894 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10895 }
10896 }
10897 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10898 {
10899 SCIP_Bool succ;
10900
10901 /* we can find more signed permutations for even univariate operators */
10902 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10903 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10904
10905 if( succ )
10906 {
10907 usedefaultgadget = FALSE;
10908 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10909 }
10910 }
10911
10912 if( usedefaultgadget )
10913 {
10914 int opidx;
10915 int optype;
10916
10918 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10919 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10920
10921 /* possibly add constants of expression */
10923 {
10924 SYM_EXPRDATA* symdata;
10925
10926 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10927 assert(symdata != NULL);
10928
10929 /* if expression has multiple constants, assign colors to edges to distinguish them */
10930 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
10931 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10932 {
10933 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
10934 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10935 }
10936
10937 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10938 }
10939
10940 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10941
10942 openidx[nopenidx++] = opidx;
10943 }
10944 }
10945 }
10946
10947 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
10948 SCIPfreeBufferArray(scip, &consvals);
10949 SCIPfreeBufferArray(scip, &consvars);
10950 SCIPfreeBufferArray(scip, &openidx);
10951 SCIPfreeExpriter(&it);
10952
10953 *success = TRUE;
10954
10955 return SCIP_OKAY;
10956}
10957
10958/*
10959 * Callback methods of constraint handler
10960 */
10961
10962/** copy method for constraint handler plugins (called when SCIP copies plugins) */
10963static
10964SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
10965{ /*lint --e{715}*/
10966 SCIP_CONSHDLR* targetconshdlr;
10967 SCIP_CONSHDLRDATA* sourceconshdlrdata;
10968 int i;
10969
10970 assert(scip != NULL);
10971 assert(conshdlr != NULL);
10972 assert(valid != NULL);
10973 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10974
10975 /* create basic data of constraint handler and include it to scip */
10977
10978 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10979 assert(targetconshdlr != NULL);
10980 assert(targetconshdlr != conshdlr);
10981
10982 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
10983 assert(sourceconshdlrdata != NULL);
10984
10985 /* copy nonlinear handlers */
10986 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10987 {
10988 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
10989 }
10990
10991 *valid = TRUE;
10992
10993 return SCIP_OKAY;
10994}
10995
10996/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10997static
10998SCIP_DECL_CONSFREE(consFreeNonlinear)
10999{ /*lint --e{715}*/
11000 SCIP_CONSHDLRDATA* conshdlrdata;
11001 int i;
11002
11003 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11004 assert(conshdlrdata != NULL);
11005
11006 /* free nonlinear handlers */
11007 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11008 {
11009 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11010 assert(conshdlrdata->nlhdlrs[i] == NULL);
11011 }
11012 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11013 conshdlrdata->nlhdlrssize = 0;
11014
11015 /* free upgrade functions */
11016 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11017 {
11018 assert(conshdlrdata->consupgrades[i] != NULL);
11019 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11020 }
11021 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11022
11023 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11024
11025 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11026
11027 if( conshdlrdata->vp_randnumgen != NULL )
11028 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11029
11030 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11031 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11032 {
11033 if( conshdlrdata->vp_lp[i] != NULL )
11034 {
11035 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11036 }
11037 }
11038
11039 assert(conshdlrdata->branchrandnumgen == NULL);
11040
11041 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11042 SCIPhashmapFree(&conshdlrdata->var2expr);
11043
11044 SCIPfreeBlockMemory(scip, &conshdlrdata);
11045 SCIPconshdlrSetData(conshdlr, NULL);
11046
11047 return SCIP_OKAY;
11048}
11049
11050
11051/** initialization method of constraint handler (called after problem was transformed) */
11052static
11053SCIP_DECL_CONSINIT(consInitNonlinear)
11054{ /*lint --e{715}*/
11055 SCIP_CONSHDLRDATA* conshdlrdata;
11056 int i;
11057
11058 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11059 assert(conshdlrdata != NULL);
11060
11061 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11062 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11063 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11064 conshdlrdata->enforound = 1;
11065 /* reset numbering for auxiliary variables */
11066 conshdlrdata->auxvarid = 0;
11067
11068 for( i = 0; i < nconss; ++i )
11069 {
11070 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11071 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11072 }
11073
11074 /* sort nonlinear handlers by detection priority, in decreasing order */
11075 if( conshdlrdata->nnlhdlrs > 1 )
11076 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11077
11078 /* get heuristics for later use */
11079 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11080 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11081
11082 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11083 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11084 {
11085 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11086 }
11087
11088 /* reset statistics in constraint handler */
11089 conshdlrdata->nweaksepa = 0;
11090 conshdlrdata->ntightenlp = 0;
11091 conshdlrdata->ndesperatebranch = 0;
11092 conshdlrdata->ndesperatecutoff = 0;
11093 conshdlrdata->ndesperatetightenlp = 0;
11094 conshdlrdata->nforcelp = 0;
11095 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11096 conshdlrdata->ncanonicalizecalls = 0;
11097
11098#ifdef ENFOLOGFILE
11099 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11100#endif
11101
11102 return SCIP_OKAY;
11103}
11104
11105
11106/** deinitialization method of constraint handler (called before transformed problem is freed) */
11107static
11108SCIP_DECL_CONSEXIT(consExitNonlinear)
11109{ /*lint --e{715}*/
11110 SCIP_CONSHDLRDATA* conshdlrdata;
11111 SCIP_CONS** consssorted;
11112 int i;
11113
11114 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11115 assert(conshdlrdata != NULL);
11116
11117 if( nconss > 0 )
11118 {
11119 /* for better performance of dropVarEvents, we sort by index, descending */
11120 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11121 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11122
11123 for( i = 0; i < nconss; ++i )
11124 {
11125 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11126 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11127 }
11128
11129 SCIPfreeBufferArray(scip, &consssorted);
11130 }
11131
11132 conshdlrdata->subnlpheur = NULL;
11133 conshdlrdata->trysolheur = NULL;
11134
11135 if( conshdlrdata->vp_randnumgen != NULL )
11136 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11137
11138 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11139 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11140 {
11141 if( conshdlrdata->vp_lp[i] != NULL )
11142 {
11143 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11144 }
11145 }
11146
11147 if( conshdlrdata->branchrandnumgen != NULL )
11148 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11149
11150 /* deinitialize nonlinear handlers */
11151 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11152 {
11153 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11154 }
11155
11156 ENFOLOG(
11157 if( enfologfile != NULL )
11158 {
11159 fclose(enfologfile);
11160 enfologfile = NULL;
11161 })
11162
11163 return SCIP_OKAY;
11164}
11165
11166
11167/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11168#ifdef SCIP_DISABLED_CODE
11169static
11171{ /*lint --e{715}*/
11172 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11173 SCIPABORT(); /*lint --e{527}*/
11174
11175 return SCIP_OKAY;
11176}
11177#else
11178#define consInitpreNonlinear NULL
11179#endif
11180
11181
11182/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11183static
11184SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11185{ /*lint --e{715}*/
11186 SCIP_Bool infeasible;
11187
11188 if( nconss == 0 )
11189 return SCIP_OKAY;
11190
11191 /* skip some extra work if already known to be infeasible */
11193 return SCIP_OKAY;
11194
11195 /* simplify constraints and replace common subexpressions */
11196 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11197
11198 /* currently SCIP does not offer to communicate this,
11199 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11200 * or if a constraint expression became constant
11201 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11202 */
11203 /* assert(!infeasible); */
11204
11205 /* tell SCIP that we have something nonlinear */
11207
11208 return SCIP_OKAY;
11209}
11210
11211
11212/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11213static
11214SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11215{ /*lint --e{715}*/
11216 SCIP_CONSHDLRDATA* conshdlrdata;
11217 int i;
11218
11219 /* skip remaining initializations if we have solved already
11220 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11221 * assumes nonempty activities in expressions
11222 */
11223 switch( SCIPgetStatus(scip) )
11224 {
11229 return SCIP_OKAY;
11230 default: ;
11231 } /*lint !e788 */
11232
11233 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11234 assert(conshdlrdata != NULL);
11235
11236 /* reset one of the number of detections counter to count only current round */
11237 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11238 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11239
11240 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11241
11242 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11243 if( conshdlrdata->branchpscostweight > 0.0 )
11244 {
11245 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11246 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11247 {
11248 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11249 SCIPABORT();
11250 return SCIP_INVALIDDATA;
11251 }
11252 }
11253
11254 return SCIP_OKAY;
11255}
11256
11257
11258/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11259static
11260SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11261{ /*lint --e{715}*/
11262 SCIP_CONSHDLRDATA* conshdlrdata;
11263
11264 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11265
11266 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11267 assert(conshdlrdata != NULL);
11268
11269 /* free hash table for bilinear terms */
11270 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11271
11272 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11273 conshdlrdata->checkedvarlocks = FALSE;
11274
11275 /* drop catching new solution event, if catched before */
11276 if( conshdlrdata->newsoleventfilterpos >= 0 )
11277 {
11278 SCIP_EVENTHDLR* eventhdlr;
11279
11280 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11281 assert(eventhdlr != NULL);
11282
11283 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11284 conshdlrdata->newsoleventfilterpos = -1;
11285 }
11286
11287 return SCIP_OKAY;
11288}
11289
11290
11291/** frees specific constraint data */
11292static
11293SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11294{ /*lint --e{715}*/
11295 assert(consdata != NULL);
11296 assert(*consdata != NULL);
11297 assert((*consdata)->expr != NULL);
11298
11299 /* constraint locks should have been removed */
11300 assert((*consdata)->nlockspos == 0);
11301 assert((*consdata)->nlocksneg == 0);
11302
11303 /* free variable expressions */
11304 SCIP_CALL( freeVarExprs(scip, *consdata) );
11305
11306 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11307
11308 /* free nonlinear row representation */
11309 if( (*consdata)->nlrow != NULL )
11310 {
11311 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11312 }
11313
11314 SCIPfreeBlockMemory(scip, consdata);
11315
11316 return SCIP_OKAY;
11317}
11318
11319
11320/** transforms constraint data into data belonging to the transformed problem */
11321static
11322SCIP_DECL_CONSTRANS(consTransNonlinear)
11323{ /*lint --e{715}*/
11324 SCIP_EXPR* targetexpr;
11325 SCIP_CONSDATA* sourcedata;
11326
11327 sourcedata = SCIPconsGetData(sourcecons);
11328 assert(sourcedata != NULL);
11329
11330 /* get a copy of sourceexpr with transformed vars */
11331 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11332 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11333
11334 /* create transformed cons (only captures targetexpr, no need to copy again) */
11335 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11336 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11337 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11338 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11339 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11340 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11341
11342 /* release target expr */
11343 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11344
11345 return SCIP_OKAY;
11346}
11347
11348
11349/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11350static
11351SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11352{ /*lint --e{715}*/
11353 SCIP_CONSHDLRDATA* conshdlrdata;
11354
11355 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11356 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11357 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11358 * for now, there is an assert in detectNlhdlrs to require initial if separated
11359 */
11360 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11361
11362 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11363 assert(conshdlrdata != NULL);
11364
11365 /* catch new solution event */
11366 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11367 {
11368 SCIP_EVENTHDLR* eventhdlr;
11369
11370 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11371 assert(eventhdlr != NULL);
11372
11373 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11374 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11375 }
11376
11377 /* collect all bilinear terms for which an auxvar is present
11378 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11379 * addition (and removal?) of constraints during solve
11380 * this is typically the majority of constraints, but the method should be made more flexible
11381 */
11382 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11383
11384 return SCIP_OKAY;
11385}
11386
11387
11388/** separation method of constraint handler for LP solutions */
11389static
11390SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11391{ /*lint --e{715}*/
11392 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11393
11394 return SCIP_OKAY;
11395}
11396
11397
11398/** separation method of constraint handler for arbitrary primal solutions */
11399static
11400SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11401{ /*lint --e{715}*/
11402 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11403
11404 return SCIP_OKAY;
11405}
11406
11407
11408/** constraint enforcing method of constraint handler for LP solutions */
11409static
11410SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11411{ /*lint --e{715}*/
11412 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11413
11414 return SCIP_OKAY;
11415}
11416
11417
11418/** constraint enforcing method of constraint handler for relaxation solutions */
11419static
11420SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11421{ /*lint --e{715}*/
11422 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11423
11424 return SCIP_OKAY;
11425}
11426
11427
11428/** constraint enforcing method of constraint handler for pseudo solutions */
11429static
11430SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11431{ /*lint --e{715}*/
11432 SCIP_RESULT propresult;
11433 SCIP_Longint soltag;
11434 int nchgbds;
11435 int nnotify;
11436 int c;
11437
11438 soltag = SCIPgetExprNewSoltag(scip);
11439
11440 *result = SCIP_FEASIBLE;
11441 for( c = 0; c < nconss; ++c )
11442 {
11443 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11444
11445 if( isConsViolated(scip, conss[c]) )
11446 *result = SCIP_INFEASIBLE;
11447 }
11448
11449 if( *result == SCIP_FEASIBLE )
11450 return SCIP_OKAY;
11451
11452 /* try to propagate
11453 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11454 */
11455 nchgbds = 0;
11456 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11457
11458 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11459 {
11460 *result = propresult;
11461 return SCIP_OKAY;
11462 }
11463
11464 /* register all unfixed variables in all violated constraints as branching candidates */
11465 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11466 if( nnotify > 0 )
11467 {
11468 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11469
11470 return SCIP_OKAY;
11471 }
11472
11473 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11474 *result = SCIP_SOLVELP;
11475 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11476
11477 return SCIP_OKAY;
11478}
11479
11480
11481/** feasibility check method of constraint handler for integral solutions */
11482static
11483SCIP_DECL_CONSCHECK(consCheckNonlinear)
11484{ /*lint --e{715}*/
11485 SCIP_CONSHDLRDATA* conshdlrdata;
11486 SCIP_CONSDATA* consdata;
11487 SCIP_Real maxviol;
11488 SCIP_Bool maypropfeasible;
11489 SCIP_Longint soltag;
11490 int c;
11491
11492 assert(scip != NULL);
11493 assert(conshdlr != NULL);
11494 assert(conss != NULL || nconss == 0);
11495 assert(result != NULL);
11496
11497 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11498 assert(conshdlrdata != NULL);
11499
11500 *result = SCIP_FEASIBLE;
11501 soltag = SCIPgetExprNewSoltag(scip);
11502 maxviol = 0.0;
11503 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11505
11506 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
11507 maypropfeasible = FALSE;
11508
11509 /* check nonlinear constraints for feasibility */
11510 for( c = 0; c < nconss; ++c )
11511 {
11512 assert(conss != NULL && conss[c] != NULL);
11513 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11514
11515 if( isConsViolated(scip, conss[c]) )
11516 {
11517 *result = SCIP_INFEASIBLE;
11518 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11519
11520 consdata = SCIPconsGetData(conss[c]);
11521 assert(consdata != NULL);
11522
11523 /* print reason for infeasibility */
11524 if( printreason )
11525 {
11526 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11527 SCIPinfoMessage(scip, NULL, ";\n");
11528
11529 if( consdata->lhsviol > SCIPfeastol(scip) )
11530 {
11531 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11532 }
11533 if( consdata->rhsviol > SCIPfeastol(scip) )
11534 {
11535 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11536 }
11537 }
11538 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11539 {
11540 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11541 return SCIP_OKAY;
11542 }
11543
11544 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11545 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11546 maypropfeasible = FALSE;
11547
11548 if( maypropfeasible )
11549 {
11550 if( consdata->lhsviol > SCIPfeastol(scip) )
11551 {
11552 /* check if there is a variable which may help to get the left hand side satisfied
11553 * if there is no such variable, then we cannot get feasible
11554 */
11555 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11556 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11557 maypropfeasible = FALSE;
11558 }
11559 else
11560 {
11561 assert(consdata->rhsviol > SCIPfeastol(scip));
11562 /* check if there is a variable which may help to get the right hand side satisfied
11563 * if there is no such variable, then we cannot get feasible
11564 */
11565 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11566 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11567 maypropfeasible = FALSE;
11568 }
11569 }
11570 }
11571 }
11572
11573 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11574 {
11575 SCIP_Bool success;
11576
11577 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11578
11579 /* do not pass solution to NLP heuristic if we made it feasible this way */
11580 if( success )
11581 return SCIP_OKAY;
11582 }
11583
11584 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11585 {
11586 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11587 }
11588
11589 return SCIP_OKAY;
11590}
11591
11592
11593/** domain propagation method of constraint handler */
11594static
11595SCIP_DECL_CONSPROP(consPropNonlinear)
11596{ /*lint --e{715}*/
11597 int nchgbds = 0;
11598
11599 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11600 assert(nchgbds >= 0);
11601
11602 /* TODO would it make sense to check for redundant constraints? */
11603
11604 return SCIP_OKAY;
11605}
11606
11607
11608/** presolving method of constraint handler */
11609static
11610SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11611{ /*lint --e{715}*/
11612 SCIP_CONSHDLRDATA* conshdlrdata;
11613 SCIP_Bool infeasible;
11614 int c;
11615
11616 *result = SCIP_DIDNOTFIND;
11617
11618 if( nconss == 0 )
11619 {
11620 *result = SCIP_DIDNOTRUN;
11621 return SCIP_OKAY;
11622 }
11623
11624 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11625 assert(conshdlrdata != NULL);
11626
11627 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11628 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11629 if( infeasible )
11630 {
11631 *result = SCIP_CUTOFF;
11632 return SCIP_OKAY;
11633 }
11634
11635 /* merge constraints with the same root expression */
11636 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11637 {
11638 SCIP_Bool success;
11639
11640 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11641 if( success )
11642 *result = SCIP_SUCCESS;
11643 }
11644
11645 /* propagate constraints */
11646 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11647 if( *result == SCIP_CUTOFF )
11648 return SCIP_OKAY;
11649
11650 /* propagate function domains (TODO integrate with simplify?) */
11651 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11652 {
11653 SCIP_RESULT localresult;
11654 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11655 if( localresult == SCIP_CUTOFF )
11656 {
11657 *result = SCIP_CUTOFF;
11658 return SCIP_OKAY;
11659 }
11660 if( localresult == SCIP_REDUCEDDOM )
11661 *result = SCIP_REDUCEDDOM;
11662 }
11663
11664 /* check for redundant constraints, remove constraints that are a value expression */
11665 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11666 if( infeasible )
11667 {
11668 *result = SCIP_CUTOFF;
11669 return SCIP_OKAY;
11670 }
11671
11672 /* try to upgrade constraints */
11673 for( c = 0; c < nconss; ++c )
11674 {
11675 SCIP_Bool upgraded;
11676
11677 /* skip inactive and deleted constraints */
11678 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11679 continue;
11680
11681 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11682 }
11683
11684 /* try to change continuous variables that appear linearly to be implicit integer */
11685 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11686 {
11687 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11688
11689 if( infeasible )
11690 {
11691 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11692 *result = SCIP_CUTOFF;
11693 return SCIP_OKAY;
11694 }
11695 }
11696
11697 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11699 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11700 {
11701 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11702 * constraints multiple times
11703 */
11704 conshdlrdata->checkedvarlocks = TRUE;
11705
11706 for( c = 0; c < nconss; ++c )
11707 {
11708 int tmpnchgvartypes = 0;
11709 int tmpnaddconss = 0;
11710
11711 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11712 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11713 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11714
11715 if( infeasible )
11716 {
11717 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11718 *result = SCIP_CUTOFF;
11719 return SCIP_OKAY;
11720 }
11721
11722 (*nchgvartypes) += tmpnchgvartypes;
11723 (*naddconss) += tmpnaddconss;
11724 }
11725 }
11726
11727 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11728 *result = SCIP_SUCCESS;
11729 else
11730 *result = SCIP_DIDNOTFIND;
11731
11732 return SCIP_OKAY;
11733}
11734
11735
11736/** propagation conflict resolving method of constraint handler */
11737#ifdef SCIP_DISABLED_CODE
11738static
11740{ /*lint --e{715}*/
11741 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11742 SCIPABORT(); /*lint --e{527}*/
11743
11744 return SCIP_OKAY;
11745}
11746#else
11747#define consRespropNonlinear NULL
11748#endif
11749
11750
11751/** variable rounding lock method of constraint handler */
11752static
11753SCIP_DECL_CONSLOCK(consLockNonlinear)
11754{ /*lint --e{715}*/
11755 SCIP_CONSDATA* consdata;
11756 SCIP_EXPR_OWNERDATA* ownerdata;
11757 SCIP_Bool reinitsolve = FALSE;
11758
11759 assert(conshdlr != NULL);
11760 assert(cons != NULL);
11761
11762 consdata = SCIPconsGetData(cons);
11763 assert(consdata != NULL);
11764 assert(consdata->expr != NULL);
11765
11766 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11767
11768 /* check whether we need to initSolve again because
11769 * - we have enfo initialized (nenfos >= 0)
11770 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11771 */
11772 if( ownerdata->nenfos >= 0 )
11773 {
11774 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11775 reinitsolve = TRUE;
11776 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11777 reinitsolve = TRUE;
11778 }
11779
11780 if( reinitsolve )
11781 {
11782 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11783 }
11784
11785 /* add locks */
11786 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11787
11788 if( reinitsolve )
11789 {
11790 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11791 }
11792
11793 return SCIP_OKAY;
11794}
11795
11796
11797/** constraint activation notification method of constraint handler */
11798static
11799SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11800{ /*lint --e{715}*/
11801 SCIP_CONSDATA* consdata;
11802 SCIP_Bool infeasible = FALSE;
11803
11804 consdata = SCIPconsGetData(cons);
11805 assert(consdata != NULL);
11806
11807 /* simplify root expression if the constraint has been added after presolving */
11809 {
11810 SCIP_Bool replacedroot;
11811
11812 if( !consdata->issimplified )
11813 {
11814 SCIP_EXPR* simplified;
11815 SCIP_Bool changed;
11816
11817 /* simplify constraint */
11818 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11819 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11820 assert(simplified != NULL);
11821 consdata->expr = simplified;
11822 consdata->issimplified = TRUE;
11823 }
11824
11825 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11826 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11827 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11828
11829 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11830 {
11831 SCIP_CONSHDLRDATA* conshdlrdata;
11832 SCIP_EXPRITER* it;
11833 SCIP_EXPR* expr;
11834
11835 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11836 assert(conshdlrdata != NULL);
11837
11839 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11841 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11842 {
11843 SCIP_EXPR* child;
11844 SCIP_EXPR* hashmapexpr;
11845
11846 child = SCIPexpriterGetChildExprDFS(it);
11847 if( !SCIPisExprVar(scip, child) )
11848 continue;
11849
11850 /* check which expression is stored in the hashmap for the var of child */
11851 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11852 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11853 if( hashmapexpr != NULL && hashmapexpr != child )
11854 {
11856 }
11857 }
11858 SCIPfreeExpriter(&it);
11859 }
11860 }
11861
11862 /* store variable expressions */
11864 {
11865 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11866 }
11867
11868 /* add manually locks to constraints that are not checked for feasibility */
11869 if( !SCIPconsIsChecked(cons) )
11870 {
11871 assert(consdata->nlockspos == 0);
11872 assert(consdata->nlocksneg == 0);
11873
11874 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11875 }
11876
11877 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11878 {
11879 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11880 }
11881
11882 /* TODO deal with infeasibility */
11883 assert(!infeasible);
11884
11885 return SCIP_OKAY;
11886}
11887
11888
11889/** constraint deactivation notification method of constraint handler */
11890static
11891SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11892{ /*lint --e{715}*/
11893 SCIP_CONSHDLRDATA* conshdlrdata;
11894
11895 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11896 assert(conshdlrdata != NULL);
11897
11899 {
11900 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11901 }
11902
11904 {
11905 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11907 }
11908
11909 /* remove locks that have been added in consActiveExpr() */
11910 if( !SCIPconsIsChecked(cons) )
11911 {
11912 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11913
11914 assert(SCIPconsGetData(cons)->nlockspos == 0);
11915 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11916 }
11917
11918 return SCIP_OKAY;
11919}
11920
11921
11922/** constraint enabling notification method of constraint handler */
11923static
11924SCIP_DECL_CONSENABLE(consEnableNonlinear)
11925{ /*lint --e{715}*/
11926 SCIP_CONSHDLRDATA* conshdlrdata;
11927
11928 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11929 assert(conshdlrdata != NULL);
11930
11932 {
11933 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11934 }
11935
11936 return SCIP_OKAY;
11937}
11938
11939
11940/** constraint disabling notification method of constraint handler */
11941static
11942SCIP_DECL_CONSDISABLE(consDisableNonlinear)
11943{ /*lint --e{715}*/
11944 SCIP_CONSHDLRDATA* conshdlrdata;
11945
11946 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11947 assert(conshdlrdata != NULL);
11948
11950 {
11951 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11952 }
11953
11954 return SCIP_OKAY;
11955}
11956
11957/** variable deletion of constraint handler */
11958#ifdef SCIP_DISABLED_CODE
11959static
11961{ /*lint --e{715}*/
11962 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11963 SCIPABORT(); /*lint --e{527}*/
11964
11965 return SCIP_OKAY;
11966}
11967#else
11968#define consDelvarsNonlinear NULL
11969#endif
11970
11971
11972/** constraint display method of constraint handler */
11973static
11974SCIP_DECL_CONSPRINT(consPrintNonlinear)
11975{ /*lint --e{715}*/
11976 SCIP_CONSDATA* consdata;
11977
11978 consdata = SCIPconsGetData(cons);
11979 assert(consdata != NULL);
11980 assert(consdata->expr != NULL);
11981
11982 /* print left hand side for ranged constraints */
11983 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11984 {
11985 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11986 }
11987
11988 /* print expression */
11989 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11990
11991 /* print right hand side */
11992 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11993 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11994 else if( !SCIPisInfinity(scip, consdata->rhs) )
11995 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11996 else if( !SCIPisInfinity(scip, -consdata->lhs) )
11997 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11998 else
11999 SCIPinfoMessage(scip, file, " [free]");
12000
12001 return SCIP_OKAY;
12002}
12003
12004
12005/** constraint copying method of constraint handler */
12006static
12007SCIP_DECL_CONSCOPY(consCopyNonlinear)
12008{ /*lint --e{715}*/
12009 SCIP_CONSHDLR* targetconshdlr;
12010 SCIP_EXPR* targetexpr = NULL;
12011 SCIP_CONSDATA* sourcedata;
12012
12013 assert(cons != NULL);
12014
12015 sourcedata = SCIPconsGetData(sourcecons);
12016 assert(sourcedata != NULL);
12017
12018 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12019 assert(targetconshdlr != NULL);
12020
12021 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12022
12023 if( targetexpr == NULL )
12024 *valid = FALSE;
12025
12026 *cons = NULL;
12027 if( *valid )
12028 {
12029 /* create copy (only capture targetexpr, no need to copy again) */
12030 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12031 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12032 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12033 }
12034
12035 if( targetexpr != NULL )
12036 {
12037 /* release target expr */
12038 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12039 }
12040
12041 return SCIP_OKAY;
12042}
12043
12044
12045/** constraint parsing method of constraint handler */
12046static
12047SCIP_DECL_CONSPARSE(consParseNonlinear)
12048{ /*lint --e{715}*/
12049 SCIP_Real lhs;
12050 SCIP_Real rhs;
12051 char* endptr;
12052 SCIP_EXPR* consexprtree;
12053
12054 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12055
12056 assert(scip != NULL);
12057 assert(success != NULL);
12058 assert(str != NULL);
12059 assert(name != NULL);
12060 assert(cons != NULL);
12061
12062 *success = FALSE;
12063
12064 /* return if string empty */
12065 if( !*str )
12066 return SCIP_OKAY;
12067
12068 endptr = (char*)str;
12069
12070 /* set left and right hand side to their default values */
12071 lhs = -SCIPinfinity(scip);
12072 rhs = SCIPinfinity(scip);
12073
12074 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12075
12076 /* check for left hand side */
12077 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12078 {
12079 /* there is a number coming, maybe it is a left-hand-side */
12080 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12081 {
12082 SCIPerrorMessage("error parsing number from <%s>\n", str);
12083 return SCIP_READERROR;
12084 }
12085
12086 /* ignore whitespace */
12087 SCIP_CALL( SCIPskipSpace(&endptr) );
12088
12089 if( endptr[0] != '<' || endptr[1] != '=' )
12090 {
12091 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12092 lhs = -SCIPinfinity(scip);
12093 }
12094 else
12095 {
12096 /* it was indeed a left-hand-side, so continue parsing after it */
12097 str = endptr + 2;
12098
12099 /* ignore whitespace */
12100 SCIP_CALL( SCIPskipSpace((char**)&str) );
12101 }
12102 }
12103
12104 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12105
12106 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12107 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12108
12109 /* check for left or right hand side */
12110 SCIP_CALL( SCIPskipSpace((char**)&str) );
12111
12112 /* check for free constraint */
12113 if( strncmp(str, "[free]", 6) == 0 )
12114 {
12115 if( !SCIPisInfinity(scip, -lhs) )
12116 {
12117 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12118 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12119 return SCIP_OKAY;
12120 }
12121 *success = TRUE;
12122 }
12123 else
12124 {
12125 switch( *str )
12126 {
12127 case '<':
12128 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12129 break;
12130 case '=':
12131 if( !SCIPisInfinity(scip, -lhs) )
12132 {
12133 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12134 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12135 return SCIP_OKAY;
12136 }
12137 else
12138 {
12139 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12140 lhs = rhs;
12141 }
12142 break;
12143 case '>':
12144 if( !SCIPisInfinity(scip, -lhs) )
12145 {
12146 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12147 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12148 return SCIP_OKAY;
12149 }
12150 else
12151 {
12152 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12153 break;
12154 }
12155 case '\0':
12156 *success = TRUE;
12157 break;
12158 default:
12159 SCIPerrorMessage("unexpected character %c\n", *str);
12160 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12161 return SCIP_OKAY;
12162 }
12163 }
12164
12165 /* create constraint */
12166 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12167 consexprtree, lhs, rhs, FALSE,
12168 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12169 assert(*cons != NULL);
12170
12171 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12172
12173 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12174
12175 return SCIP_OKAY;
12176}
12177
12178
12179/** constraint method of constraint handler which returns the variables (if possible) */
12180static
12181SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12182{ /*lint --e{715}*/
12183 SCIP_CONSDATA* consdata;
12184 int i;
12185
12186 consdata = SCIPconsGetData(cons);
12187 assert(consdata != NULL);
12188
12189 /* store variable expressions if not done so far */
12190 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12191
12192 /* check whether array is too small in order to store all variables */
12193 if( varssize < consdata->nvarexprs )
12194 {
12195 *success = FALSE;
12196 return SCIP_OKAY;
12197 }
12198
12199 for( i = 0; i < consdata->nvarexprs; ++i )
12200 {
12201 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12202 assert(vars[i] != NULL);
12203 }
12204
12205 *success = TRUE;
12206
12207 return SCIP_OKAY;
12208}
12209
12210/** constraint method of constraint handler which returns the number of variables (if possible) */
12211static
12212SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12213{ /*lint --e{715}*/
12214 SCIP_CONSDATA* consdata;
12215
12216 consdata = SCIPconsGetData(cons);
12217 assert(consdata != NULL);
12218
12219 /* store variable expressions if not done so far */
12220 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12221
12222 *nvars = consdata->nvarexprs;
12223 *success = TRUE;
12224
12225 return SCIP_OKAY;
12226}
12227
12228/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12229#ifdef SCIP_DISABLED_CODE
12230static
12232{ /*lint --e{715}*/
12233 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12234 SCIPABORT(); /*lint --e{527}*/
12235
12236 return SCIP_OKAY;
12237}
12238#else
12239#define consGetDiveBdChgsNonlinear NULL
12240#endif
12241
12242/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12243static
12244SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12245{ /*lint --e{715}*/
12246 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12247
12248 return SCIP_OKAY;
12249}
12250
12251/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12252static
12253SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12254{ /*lint --e{715}*/
12255 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12256
12257 return SCIP_OKAY;
12258}
12259
12260/** output method of statistics table to output file stream 'file' */
12261static
12262SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12263{ /*lint --e{715}*/
12264 SCIP_CONSHDLR* conshdlr;
12265 SCIP_CONSHDLRDATA* conshdlrdata;
12266
12267 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12268 assert(conshdlr != NULL);
12269
12270 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12271 assert(conshdlrdata != NULL);
12272
12273 /* print statistics for constraint handler */
12274 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12275 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12276 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12277 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12278 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12279 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12280 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12281 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12282 SCIPinfoMessage(scip, file, "\n");
12283 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12284 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12285 SCIPinfoMessage(scip, file, "\n");
12286
12287 return SCIP_OKAY;
12288}
12289
12290/** output method of statistics table to output file stream 'file' */
12291static
12292SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12293{ /*lint --e{715}*/
12294 SCIP_CONSHDLR* conshdlr;
12295 SCIP_CONSHDLRDATA* conshdlrdata;
12296
12297 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12298 assert(conshdlr != NULL);
12299
12300 /* skip nlhdlr table if there never were active nonlinear constraints */
12301 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12302 return SCIP_OKAY;
12303
12304 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12305 assert(conshdlrdata != NULL);
12306
12307 /* print statistics for nonlinear handlers */
12308 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12309
12310 return SCIP_OKAY;
12311}
12312
12313/** execution method of display nlhdlrs dialog */
12314static
12315SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12316{ /*lint --e{715}*/
12317 SCIP_CONSHDLR* conshdlr;
12318 SCIP_CONSHDLRDATA* conshdlrdata;
12319 int i;
12320
12321 /* add dialog to history of dialogs that have been executed */
12322 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12323
12324 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12325 assert(conshdlr != NULL);
12326
12327 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12328 assert(conshdlrdata != NULL);
12329
12330 /* display list of nonlinear handler */
12331 SCIPdialogMessage(scip, NULL, "\n");
12332 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12333 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12334 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12335 {
12336 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12337 assert(nlhdlr != NULL);
12338
12339 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12340 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12343 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12344 SCIPdialogMessage(scip, NULL, "\n");
12345 }
12346 SCIPdialogMessage(scip, NULL, "\n");
12347
12348 /* next dialog will be root dialog again */
12349 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12350
12351 return SCIP_OKAY;
12352}
12353
12354/*
12355 * constraint handler specific interface methods
12356 */
12357
12358/** creates the handler for nonlinear constraints and includes it in SCIP */
12360 SCIP* scip /**< SCIP data structure */
12361 )
12362{
12363 SCIP_CONSHDLRDATA* conshdlrdata;
12364 SCIP_DIALOG* parentdialog;
12365
12366 /* create nonlinear constraint handler data */
12367 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12368 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12369 conshdlrdata->curboundstag = 1;
12370 conshdlrdata->lastboundrelax = 1;
12371 conshdlrdata->curpropboundstag = 1;
12372 conshdlrdata->newsoleventfilterpos = -1;
12373 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12374 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12375 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12376
12377 /* include constraint handler */
12383 conshdlrCopyNonlinear,
12384 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12385 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12386 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12387 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12388 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12389 consActiveNonlinear, consDeactiveNonlinear,
12390 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12391 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12392 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12393 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12394
12395 /* add nonlinear constraint handler parameters */
12396 /* TODO organize into more subcategories */
12397 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12398 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12399 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12400
12401 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12402 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12403 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12404
12405 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12406 "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",
12407 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12408
12409 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12410 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12411 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12412
12413 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12414 "by how much to relax constraint sides during bound tightening",
12415 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12416
12417 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12418 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12419 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12420
12421 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12422 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12423 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12424
12425 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12426 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12427 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12428
12429 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12430 "maximal number of auxiliary expressions per bilinear term",
12431 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12432
12433 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12434 "whether to reformulate products of binary variables during presolving",
12435 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12436
12437 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12438 "whether to use the AND constraint handler for reformulating binary products",
12439 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12440
12441 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12442 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12443 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12444
12445 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12446 "whether to forbid multiaggregation of nonlinear variables",
12447 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12448
12449 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12450 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12451 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12452
12453 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12454 "whether to (re)run propagation in enforcement",
12455 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12456
12457 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12458 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12459 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12460
12461 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12462 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12463 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12464
12465 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12466 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12467 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12468
12469 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12470 "whether to force \"strong\" cuts in enforcement",
12471 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12472
12473 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12474 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12475 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12476
12477 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12478 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12479 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12480
12481 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12482 "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",
12483 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12484
12485 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12486 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12487 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12488
12489 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12490 "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)",
12491 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12492
12493 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12494 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12495 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12496
12497 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12498 "whether to use external branching candidates and branching rules for branching",
12499 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12500
12501 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12502 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12503 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12504
12505 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12506 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12507 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12508
12509 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12510 "weight by how much to consider the violation assigned to a variable for its branching score",
12511 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12512
12513 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12514 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12515 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12516
12517 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12518 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12519 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12520
12521 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12522 "weight by how much to consider the pseudo cost of a variable for its branching score",
12523 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12524
12525 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12526 "weight by how much to consider the domain width in branching score",
12527 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12528
12529 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12530 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12531 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12532
12533 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12534 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12535 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12536
12537 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12538 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12539 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12540
12541 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12542 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12543 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12544
12545 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12546 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12547 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12548
12549 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12550 "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)",
12551 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12552
12553 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12554 "whether to assume that any constraint in the presolved problem is convex",
12555 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
12556
12557 /* include handler for bound change events */
12558 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12559 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12560 assert(conshdlrdata->eventhdlr != NULL);
12561
12562 /* include tables for statistics */
12565 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
12567
12570 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
12572
12573 /* create, include, and release display nlhdlrs dialog */
12574 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12575 {
12576 SCIP_DIALOG* dialog;
12577
12578 assert(parentdialog != NULL);
12579 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12580
12582 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12584 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12585 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12586 }
12587
12588 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12589 processNewSolutionEvent, NULL) );
12590
12591 return SCIP_OKAY;
12592}
12593
12594/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12596 SCIP* scip, /**< SCIP data structure */
12597 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12598 int priority, /**< priority of upgrading method */
12599 SCIP_Bool active, /**< should the upgrading method by active by default? */
12600 const char* conshdlrname /**< name of the constraint handler */
12601 )
12602{
12603 SCIP_CONSHDLR* conshdlr;
12604 SCIP_CONSHDLRDATA* conshdlrdata;
12605 CONSUPGRADE* consupgrade;
12607 char paramdesc[SCIP_MAXSTRLEN];
12608 int i;
12609
12610 assert(conshdlrname != NULL );
12611 assert(nlconsupgd != NULL);
12612
12613 /* find the nonlinear constraint handler */
12614 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12615 if( conshdlr == NULL )
12616 {
12617 SCIPerrorMessage("nonlinear constraint handler not found\n");
12618 return SCIP_PLUGINNOTFOUND;
12619 }
12620
12621 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12622 assert(conshdlrdata != NULL);
12623
12624 /* check whether upgrade method exists already */
12625 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12626 {
12627 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12628 {
12629#ifdef SCIP_DEBUG
12630 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12631#endif
12632 return SCIP_OKAY;
12633 }
12634 }
12635
12636 /* create a nonlinear constraint upgrade data object */
12637 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12638 consupgrade->consupgd = nlconsupgd;
12639 consupgrade->priority = priority;
12640 consupgrade->active = active;
12641
12642 /* insert nonlinear constraint upgrade method into constraint handler data */
12643 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12644 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12645
12646 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12647 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12648 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12649 conshdlrdata->consupgrades[i] = consupgrade;
12650 conshdlrdata->nconsupgrades++;
12651
12652 /* adds parameter to turn on and off the upgrading step */
12653 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12654 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12656 paramname, paramdesc,
12657 &consupgrade->active, FALSE, active, NULL, NULL) );
12658
12659 return SCIP_OKAY;
12660}
12661
12662/** creates and captures a nonlinear constraint
12663 *
12664 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12665 */
12667 SCIP* scip, /**< SCIP data structure */
12668 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12669 const char* name, /**< name of constraint */
12670 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12671 SCIP_Real lhs, /**< left hand side of constraint */
12672 SCIP_Real rhs, /**< right hand side of constraint */
12673 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12674 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12675 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12676 * Usually set to TRUE. */
12677 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12678 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12679 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12680 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12681 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12682 * Usually set to TRUE. */
12683 SCIP_Bool local, /**< is constraint only valid locally?
12684 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12685 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12686 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12687 * adds coefficients to this constraint. */
12688 SCIP_Bool dynamic, /**< is constraint subject to aging?
12689 * Usually set to FALSE. Set to TRUE for own cuts which
12690 * are separated as constraints. */
12691 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12692 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12693 )
12694{
12695 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12696 SCIP_CONSHDLR* conshdlr;
12697
12698 /* find the nonlinear constraint handler */
12699 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12700 if( conshdlr == NULL )
12701 {
12702 SCIPerrorMessage("nonlinear constraint handler not found\n");
12703 return SCIP_PLUGINNOTFOUND;
12704 }
12705
12706 /* create constraint */
12707 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12708 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12709
12710 return SCIP_OKAY;
12711}
12712
12713/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12714 *
12715 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12716 *
12717 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12718 *
12719 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12720 */
12722 SCIP* scip, /**< SCIP data structure */
12723 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12724 const char* name, /**< name of constraint */
12725 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12726 SCIP_Real lhs, /**< left hand side of constraint */
12727 SCIP_Real rhs /**< right hand side of constraint */
12728 )
12729{
12730 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12732
12733 return SCIP_OKAY;
12734}
12735
12736/** creates and captures a quadratic nonlinear constraint
12737 *
12738 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12739 */
12741 SCIP* scip, /**< SCIP data structure */
12742 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12743 const char* name, /**< name of constraint */
12744 int nlinvars, /**< number of linear terms */
12745 SCIP_VAR** linvars, /**< array with variables in linear part */
12746 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12747 int nquadterms, /**< number of quadratic terms */
12748 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12749 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12750 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12751 SCIP_Real lhs, /**< left hand side of quadratic equation */
12752 SCIP_Real rhs, /**< right hand side of quadratic equation */
12753 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12754 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12755 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12756 * Usually set to TRUE. */
12757 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12758 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12759 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12760 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12761 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12762 * Usually set to TRUE. */
12763 SCIP_Bool local, /**< is constraint only valid locally?
12764 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12765 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12766 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12767 * adds coefficients to this constraint. */
12768 SCIP_Bool dynamic, /**< is constraint subject to aging?
12769 * Usually set to FALSE. Set to TRUE for own cuts which
12770 * are separated as constraints. */
12771 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12772 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12773 )
12774{
12775 SCIP_CONSHDLR* conshdlr;
12776 SCIP_EXPR* expr;
12777
12778 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12779 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12780
12781 /* get nonlinear constraint handler */
12782 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12783 if( conshdlr == NULL )
12784 {
12785 SCIPerrorMessage("nonlinear constraint handler not found\n");
12786 return SCIP_PLUGINNOTFOUND;
12787 }
12788
12789 /* create quadratic expression */
12790 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12791 assert(expr != NULL);
12792
12793 /* create nonlinear constraint */
12794 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12795 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12796
12797 /* release quadratic expression (captured by constraint now) */
12798 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12799
12800 return SCIP_OKAY;
12801}
12802
12803/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12804 *
12805 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12806 *
12807 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12808 *
12809 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12810 */
12812 SCIP* scip, /**< SCIP data structure */
12813 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12814 const char* name, /**< name of constraint */
12815 int nlinvars, /**< number of linear terms */
12816 SCIP_VAR** linvars, /**< array with variables in linear part */
12817 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12818 int nquadterms, /**< number of quadratic terms */
12819 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12820 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12821 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12822 SCIP_Real lhs, /**< left hand side of quadratic equation */
12823 SCIP_Real rhs /**< right hand side of quadratic equation */
12824 )
12825{
12826 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12828
12829 return SCIP_OKAY;
12830}
12831
12832/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12833 *
12834 * \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$
12835 *
12836 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12837 */
12839 SCIP* scip, /**< SCIP data structure */
12840 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12841 const char* name, /**< name of constraint */
12842 int nvars, /**< number of variables on left hand side of constraint (n) */
12843 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12844 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12845 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12846 SCIP_Real constant, /**< constant on left hand side (gamma) */
12847 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12848 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12849 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12850 )
12851{
12852 SCIP_EXPR* expr;
12853 SCIP_EXPR* lhssum;
12854 SCIP_EXPR* terms[2];
12855 SCIP_Real termcoefs[2];
12856 int i;
12857
12858 assert(vars != NULL || nvars == 0);
12859
12860 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
12861 for( i = 0; i < nvars; ++i )
12862 {
12863 SCIP_EXPR* varexpr;
12864 SCIP_EXPR* powexpr;
12865
12866 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
12867 if( offsets != NULL && offsets[i] != 0.0 )
12868 {
12869 SCIP_EXPR* sum;
12870 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
12871 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
12872 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12873 }
12874 else
12875 {
12876 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
12877 }
12878
12879 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
12880 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12881 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
12882 }
12883
12884 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
12885 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
12886 termcoefs[0] = 1.0;
12887
12888 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
12889 termcoefs[1] = -rhscoeff;
12890
12891 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
12892
12893 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12894 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12895
12896 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
12897
12898 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12899
12900 return SCIP_OKAY;
12901}
12902
12903/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12904 *
12905 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12906 *
12907 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12908 */
12910 SCIP* scip, /**< SCIP data structure */
12911 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12912 const char* name, /**< name of constraint */
12913 SCIP_VAR* x, /**< nonlinear variable x in constraint */
12914 SCIP_VAR* z, /**< linear variable z in constraint */
12915 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
12916 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
12917 SCIP_Real zcoef, /**< coefficient of z in constraint */
12918 SCIP_Real lhs, /**< left hand side of constraint */
12919 SCIP_Real rhs /**< right hand side of constraint */
12920 )
12921{
12922 SCIP_EXPR* xexpr;
12923 SCIP_EXPR* terms[2];
12924 SCIP_Real coefs[2];
12925 SCIP_EXPR* sumexpr;
12926
12927 assert(x != NULL);
12928 assert(z != NULL);
12929
12930 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
12931 if( xoffset != 0.0 )
12932 {
12933 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12934 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12935
12936 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12937 }
12938 else
12939 {
12940 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
12941 }
12942 coefs[0] = 1.0;
12943
12944 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
12945 coefs[1] = zcoef;
12946
12947 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
12948
12949 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12950
12951 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12952 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12953 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12954 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
12955
12956 return SCIP_OKAY;
12957}
12958
12959/** gets tag indicating current local variable bounds */
12961 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12962 )
12963{
12964 SCIP_CONSHDLRDATA* conshdlrdata;
12965
12966 assert(conshdlr != NULL);
12967 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12968
12969 return conshdlrdata->curboundstag;
12970}
12971
12972/** gets the `curboundstag` from the last time where variable bounds were relaxed */
12974 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12975 )
12976{
12977 SCIP_CONSHDLRDATA* conshdlrdata;
12978
12979 assert(conshdlr != NULL);
12980 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12981
12982 return conshdlrdata->lastboundrelax;
12983}
12984
12985/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12986 *
12987 * @attention This method is not intended for normal use.
12988 * These tags are maintained by the event handler for variable bound change events.
12989 * This method is used by some unittests.
12990 */
12992 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12993 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12994 )
12995{
12996 SCIP_CONSHDLRDATA* conshdlrdata;
12997
12998 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12999 assert(conshdlrdata != NULL);
13000
13001 ++conshdlrdata->curboundstag;
13002 assert(conshdlrdata->curboundstag > 0);
13003
13004 if( boundrelax )
13005 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13006}
13007
13008/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13010 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13011 )
13012{
13013 assert(conshdlr != NULL);
13014
13015 return SCIPconshdlrGetData(conshdlr)->var2expr;
13016}
13017
13018/** processes a rowprep for cut addition and maybe report branchscores */
13020 SCIP* scip, /**< SCIP data structure */
13021 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13022 SCIP_CONS* cons, /**< nonlinear constraint */
13023 SCIP_EXPR* expr, /**< expression */
13024 SCIP_ROWPREP* rowprep, /**< cut to be added */
13025 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13026 SCIP_VAR* auxvar, /**< auxiliary variable */
13027 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13028 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13029 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13030 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13031 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13032 SCIP_RESULT* result /**< pointer to store the result */
13033 )
13034{
13035 SCIP_Real cutviol;
13036 SCIP_CONSHDLRDATA* conshdlrdata;
13037 SCIP_Real auxvarvalue = SCIP_INVALID;
13038 SCIP_Bool sepasuccess;
13039 SCIP_Real estimateval = SCIP_INVALID;
13040 SCIP_Real mincutviolation;
13041
13042 assert(nlhdlr != NULL);
13043 assert(cons != NULL);
13044 assert(expr != NULL);
13045 assert(rowprep != NULL);
13046 assert(auxvar != NULL);
13047 assert(result != NULL);
13048
13049 /* decide on minimal violation of cut */
13050 if( sol == NULL )
13051 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13052 else
13053 mincutviolation = SCIPfeastol(scip);
13054
13055 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13056 assert(conshdlrdata != NULL);
13057
13058 sepasuccess = TRUE;
13059
13060 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13061 if( cutviol > 0.0 )
13062 {
13063 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13064
13065 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13066 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13067 {
13068 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13069 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13070 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13071 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13072 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13073 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13074 *
13075 * if we are overestimating, we have z >= c'x-b >= f(x)
13076 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13077 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13078 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13079 *
13080 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13081 */
13082 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13083 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13084 {
13085 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13086 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13087 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13088 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13089 sepasuccess = FALSE;
13090 }
13091 }
13092
13093 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13094 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13095 }
13096 else
13097 {
13098 sepasuccess = FALSE;
13099 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13100 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13101 }
13102
13103 /* clean up estimator */
13104 if( sepasuccess )
13105 {
13106 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13107 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13108 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13109 SCIPprintRowprep(scip, rowprep, enfologfile); )
13110
13111 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13112 * instead, may even scale them down, that is, scale so that max coef is close to 1
13113 */
13114 if( !allowweakcuts )
13115 {
13116 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13117
13118 if( !sepasuccess )
13119 {
13120 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13121 }
13122 else
13123 {
13124 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13125 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13126 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13127 if( sepasuccess )
13128 sepasuccess = cutviol > mincutviolation;
13129 }
13130
13131 if( sepasuccess && auxvalue != SCIP_INVALID )
13132 {
13133 /* check whether cut is weak now
13134 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13135 * reconstructing estimateval from cutviol (TODO improve or remove?)
13136 */
13137 SCIP_Real auxvarcoef = 0.0;
13138 int i;
13139
13140 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13141 * it should be...
13142 */
13143 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13144 {
13145 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13146 {
13147 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13148 break;
13149 }
13150 }
13151
13152 if( auxvarcoef == 0.0 ||
13153 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13154 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13155 {
13156 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13157 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13158 sepasuccess = FALSE;
13159 }
13160 }
13161 }
13162 else
13163 {
13164 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13165
13166 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13167 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13168 */
13169 if( !branchscoresuccess )
13171
13172 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13173
13174 if( !sepasuccess )
13175 {
13176 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13177 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13178 }
13179
13180 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13181 * changed
13182 */
13183 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13184 {
13185 SCIP_Real violscore;
13186
13187#ifdef BRSCORE_ABSVIOL
13188 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13189#else
13190 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13191#endif
13192 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13193
13194 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13195 * - were fixed,
13196 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13197 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13198 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13199 * so I'm disabling the assert for now
13200 */
13201 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13202 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13203 }
13204 }
13205 }
13206
13207 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13208 if( sepasuccess )
13209 {
13210 SCIP_ROW* row;
13211
13212 if( conshdlrdata->branchdualweight > 0.0 )
13213 {
13214 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13215 * skip if gap is zero
13216 */
13217 if( auxvalue == SCIP_INVALID )
13218 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13219 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13220 {
13221 char gap[40];
13222 /* coverity[secure_coding] */
13223 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13224 strcat(SCIProwprepGetName(rowprep), gap);
13225 }
13226 }
13227
13228 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13229
13230 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13231 {
13232 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13234 }
13235 else if( !SCIPisCutApplicable(scip, row) )
13236 {
13237 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13238 }
13239 else
13240 {
13241 SCIP_Bool infeasible;
13242
13243 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13244 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13245
13246 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13247 * if we haven't found strong cuts before)
13248 */
13249 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13250
13251 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13252 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13254
13255 if( infeasible )
13256 {
13257 *result = SCIP_CUTOFF;
13259 }
13260 else
13261 {
13262 *result = SCIP_SEPARATED;
13264 }
13265 }
13266
13267 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13268 }
13269 else if( branchscoresuccess )
13270 {
13271 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13272 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13273
13274 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13275 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13276 */
13277 *result = SCIP_BRANCHED;
13278 }
13279 else
13280 {
13281 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13282 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13283 " (!)" : ""); )
13284 }
13285
13286 return SCIP_OKAY;
13287}
13288
13289/** returns whether all nonlinear constraints are assumed to be convex */
13291 SCIP_CONSHDLR* conshdlr
13292 )
13293{
13294 SCIP_CONSHDLRDATA* conshdlrdata;
13295
13296 assert(conshdlr != NULL);
13297
13298 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13299 assert(conshdlrdata != NULL);
13300
13301 return conshdlrdata->assumeconvex;
13302}
13303
13304/** collects all bilinear terms for a given set of constraints
13305 *
13306 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13307 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13308 */
13310 SCIP* scip, /**< SCIP data structure */
13311 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13312 SCIP_CONS** conss, /**< nonlinear constraints */
13313 int nconss /**< total number of nonlinear constraints */
13314 )
13315{
13316 assert(conshdlr != NULL);
13317 assert(conss != NULL || nconss == 0);
13318
13319 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13320
13321 return SCIP_OKAY;
13322}
13323
13324/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13325 *
13326 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13327 */
13329 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13330 )
13331{
13332 SCIP_CONSHDLRDATA* conshdlrdata;
13333
13334 assert(conshdlr != NULL);
13335
13336 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13337 assert(conshdlrdata != NULL);
13338
13339 return conshdlrdata->nbilinterms;
13340}
13341
13342/** returns all bilinear terms that are contained in all nonlinear constraints
13343 *
13344 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13345 * @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.
13346 */
13348 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13349 )
13350{
13351 SCIP_CONSHDLRDATA* conshdlrdata;
13352
13353 assert(conshdlr != NULL);
13354
13355 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13356 assert(conshdlrdata != NULL);
13357
13358 return conshdlrdata->bilinterms;
13359}
13360
13361/** returns the index of the bilinear term representing the product of the two given variables
13362 *
13363 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13364 * @return The method returns -1 if the variables do not appear bilinearly.
13365 */
13367 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13368 SCIP_VAR* x, /**< first variable */
13369 SCIP_VAR* y /**< second variable */
13370 )
13371{
13372 SCIP_CONSHDLRDATA* conshdlrdata;
13374 int idx;
13375
13376 assert(conshdlr != NULL);
13377 assert(x != NULL);
13378 assert(y != NULL);
13379
13380 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13381 assert(conshdlrdata != NULL);
13382
13383 if( conshdlrdata->bilinhashtable == NULL )
13384 {
13385 return -1;
13386 }
13387
13388 /* ensure that x.index <= y.index */
13389 if( SCIPvarCompare(x, y) == 1 )
13390 {
13391 SCIPswapPointers((void**)&x, (void**)&y);
13392 }
13393 assert(SCIPvarCompare(x, y) < 1);
13394
13395 /* use a new entry to find the image in the bilinear hash table */
13396 entry.x = x;
13397 entry.y = y;
13398 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13399 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13400 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13401 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13402
13403 return idx;
13404}
13405
13406/** returns the bilinear term that represents the product of two given variables
13407 *
13408 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13409 * @return The method returns NULL if the variables do not appear bilinearly.
13410 */
13412 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13413 SCIP_VAR* x, /**< first variable */
13414 SCIP_VAR* y /**< second variable */
13415 )
13416{
13417 SCIP_CONSHDLRDATA* conshdlrdata;
13418 int idx;
13419
13420 assert(conshdlr != NULL);
13421 assert(x != NULL);
13422 assert(y != NULL);
13423
13424 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13425 assert(conshdlrdata != NULL);
13426
13427 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13428 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13429
13430 if( idx >= 0 )
13431 {
13432 return &conshdlrdata->bilinterms[idx];
13433 }
13434
13435 return NULL;
13436}
13437
13438/** evaluates an auxiliary expression for a bilinear term */
13440 SCIP* scip, /**< SCIP data structure */
13441 SCIP_VAR* x, /**< first variable of the bilinear term */
13442 SCIP_VAR* y, /**< second variable of the bilinear term */
13443 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13444 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13445 )
13446{
13447 assert(scip != NULL);
13448 assert(x != NULL);
13449 assert(y != NULL);
13450 assert(auxexpr != NULL);
13451 assert(auxexpr->auxvar != NULL);
13452
13453 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13454 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13455}
13456
13457/** stores the variables of a bilinear term in the data of the constraint handler */
13459 SCIP* scip, /**< SCIP data structure */
13460 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13461 SCIP_VAR* x, /**< first variable */
13462 SCIP_VAR* y, /**< second variable */
13463 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13464 int nlockspos, /**< number of positive expression locks */
13465 int nlocksneg /**< number of negative expression locks */
13466 )
13467{
13468 SCIP_CONSHDLRDATA* conshdlrdata;
13470 int idx;
13471
13472 assert(conshdlr != NULL);
13473
13474 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13475 assert(conshdlrdata != NULL);
13476
13477 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13478
13479 term = &conshdlrdata->bilinterms[idx];
13480 assert(term != NULL);
13481 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13482 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) */
13483
13484 /* store and capture auxiliary variable */
13485 if( auxvar != NULL )
13486 {
13487 term->aux.var = auxvar;
13488 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13489 }
13490
13491 return SCIP_OKAY;
13492}
13493
13494/** stores the variables of a bilinear term in the data of the constraint handler */
13496 SCIP* scip, /**< SCIP data structure */
13497 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13498 SCIP_VAR* x, /**< first variable */
13499 SCIP_VAR* y, /**< second variable */
13500 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13501 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13502 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13503 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13504 SCIP_Real cst, /**< constant of the auxiliary expression */
13505 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13506 )
13507{
13508 SCIP_CONSHDLRDATA* conshdlrdata;
13511 int idx;
13512 int nlockspos;
13513 int nlocksneg;
13514 SCIP_Bool added;
13515
13516 assert(conshdlr != NULL);
13517
13518 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13519 assert(conshdlrdata != NULL);
13520
13521 nlockspos = overestimate ? 1 : 0;
13522 nlocksneg = overestimate ? 0 : 1;
13523
13524 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13525
13526 term = &conshdlrdata->bilinterms[idx];
13527 assert(term != NULL);
13528 assert(SCIPvarCompare(term->x, term->y) < 1);
13529
13530 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13531 {
13532 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13533 /* this is the case where we are adding an implicitly defined relation for a product that has already
13534 * been explicitly defined; convert auxvar into an auxexpr */
13535
13536 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13537 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13538 return SCIP_OKAY;
13539
13540 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13541 auxvarexpr->cst = 0.0;
13542 auxvarexpr->coefs[0] = 1.0;
13543 auxvarexpr->coefs[1] = 0.0;
13544 auxvarexpr->coefs[2] = 0.0;
13545 auxvarexpr->auxvar = term->aux.var;
13546 auxvarexpr->underestimate = term->nlocksneg > 0;
13547 auxvarexpr->overestimate = term->nlockspos > 0;
13548
13549 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13550 term->aux.exprs = NULL;
13551
13552 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13553
13554 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13555 assert(added);
13556 }
13557
13558 /* create and add auxexpr */
13559 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13560 auxexpr->underestimate = !overestimate;
13561 auxexpr->overestimate = overestimate;
13562 auxexpr->auxvar = auxvar;
13563 auxexpr->coefs[0] = coefaux;
13564 if( term->x == x )
13565 {
13566 assert(term->y == y);
13567 auxexpr->coefs[1] = coefx;
13568 auxexpr->coefs[2] = coefy;
13569 }
13570 else
13571 {
13572 assert(term->x == y);
13573 assert(term->y == x);
13574 auxexpr->coefs[1] = coefy;
13575 auxexpr->coefs[2] = coefx;
13576 }
13577 auxexpr->cst = cst;
13578 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13579
13580 if( !added )
13581 {
13582 SCIPfreeBlockMemory(scip, &auxexpr);
13583 }
13584 else if( auxvar != NULL )
13585 { /* capture auxiliary variable */
13586 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13587 }
13588
13589 return SCIP_OKAY;
13590}
13591
13592/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13594 SCIP* scip, /**< SCIP data structure */
13595 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13596 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13597 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13598 void* fundata, /**< data for function evaluation (can be NULL) */
13599 SCIP_Real* xstar, /**< point to be separated */
13600 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13601 int nallvars, /**< half of the length of box */
13602 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13603 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13604 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13605 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13606 )
13607{
13608 SCIP_Real* corner;
13609 SCIP_Real* funvals;
13610 int* nonfixedpos;
13611 SCIP_Real maxfaceterror;
13612 int nvars; /* number of nonfixed variables */
13613 unsigned int ncorners;
13614 unsigned int i;
13615 int j;
13616
13617 assert(scip != NULL);
13618 assert(conshdlr != NULL);
13619 assert(function != NULL);
13620 assert(xstar != NULL);
13621 assert(box != NULL);
13622 assert(success != NULL);
13623 assert(facetcoefs != NULL);
13624 assert(facetconstant != NULL);
13625
13626 *success = FALSE;
13627
13628 /* identify fixed variables */
13629 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13630 nvars = 0;
13631 for( j = 0; j < nallvars; ++j )
13632 {
13633 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13634 continue;
13635 nonfixedpos[nvars] = j;
13636 nvars++;
13637 }
13638
13639 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13640 * if too many variables are not fixed, then we do nothing currently
13641 */
13642 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13643 {
13644 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13645 SCIPfreeBufferArray(scip, &nonfixedpos);
13646 return SCIP_OKAY;
13647 }
13648
13649 /* compute f(v^i) for each corner v^i of [l,u] */
13650 ncorners = POWEROFTWO(nvars);
13651 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13652 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13653 for( j = 0; j < nallvars; ++j )
13654 {
13655 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13656 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13657 }
13658 for( i = 0; i < ncorners; ++i )
13659 {
13660 SCIPdebugMsg(scip, "corner %u: ", i);
13661 for( j = 0; j < nvars; ++j )
13662 {
13663 int varpos = nonfixedpos[j];
13664 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13665 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13666 */
13667 if( (i >> j) & 0x1 )
13668 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13669 else
13670 corner[varpos] = box[2 * varpos ]; /* lb of var */
13671 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13672 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13673 }
13674
13675 funvals[i] = function(corner, nallvars, fundata);
13676
13677 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13678
13679 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13680 {
13681 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13682 goto CLEANUP;
13683 }
13684 }
13685
13686 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13687 BMSclearMemoryArray(facetcoefs, nallvars);
13688
13689 if( nvars == 1 )
13690 {
13691 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13692
13693 /* check whether target has been missed */
13694 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13695 {
13696 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13697 *success = FALSE;
13698 }
13699 }
13700 else if( nvars == 2 && SCIPlapackIsAvailable() )
13701 {
13702 int idx1 = nonfixedpos[0];
13703 int idx2 = nonfixedpos[1];
13704 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13705 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13706 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13707 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13708 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13709 SCIP_Real coefs[2] = { 0.0, 0.0 };
13710
13711 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13712
13713 facetcoefs[idx1] = coefs[0];
13714 facetcoefs[idx2] = coefs[1];
13715 }
13716 else
13717 {
13718 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13719 }
13720 if( !*success )
13721 {
13722 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13723 goto CLEANUP;
13724 }
13725
13726 /*
13727 * check and adjust facet with the algorithm of Rikun et al.
13728 */
13729
13730 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13731
13732 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13733 if( maxfaceterror > 0.0 )
13734 {
13735 SCIP_CONSHDLRDATA* conshdlrdata;
13736 SCIP_Real midval;
13737 SCIP_Real feastol;
13738
13740
13741 /* evaluate function in middle point to get some idea for a scaling */
13742 for( j = 0; j < nvars; ++j )
13743 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13744 midval = function(corner, nallvars, fundata);
13745 if( midval == SCIP_INVALID )
13746 midval = 1.0;
13747
13748 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13749 assert(conshdlrdata != NULL);
13750
13751 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13752 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13753 {
13754 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13755 *success = FALSE;
13756 goto CLEANUP;
13757 }
13758
13759 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13760
13761 if( overestimate )
13762 *facetconstant += maxfaceterror;
13763 else
13764 *facetconstant -= maxfaceterror;
13765 }
13766
13767 /* if we made it until here, then we have a nice facet */
13768 assert(*success);
13769
13770CLEANUP:
13771 /* free allocated memory */
13772 SCIPfreeBufferArray(scip, &corner);
13773 SCIPfreeBufferArray(scip, &funvals);
13774 SCIPfreeBufferArray(scip, &nonfixedpos);
13775
13776 return SCIP_OKAY;
13777}
13778
13779/*
13780 * constraint specific interface methods
13781 */
13782
13783/** returns the expression of the given nonlinear constraint */
13785 SCIP_CONS* cons /**< constraint data */
13786 )
13787{
13788 SCIP_CONSDATA* consdata;
13789
13790 assert(cons != NULL);
13791 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13792
13793 consdata = SCIPconsGetData(cons);
13794 assert(consdata != NULL);
13795
13796 return consdata->expr;
13797}
13798
13799/** gets the left hand side of a nonlinear constraint */
13801 SCIP_CONS* cons /**< constraint data */
13802 )
13803{
13804 SCIP_CONSDATA* consdata;
13805
13806 assert(cons != NULL);
13807 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13808
13809 consdata = SCIPconsGetData(cons);
13810 assert(consdata != NULL);
13811
13812 return consdata->lhs;
13813}
13814
13815/** gets the right hand side of a nonlinear constraint */
13817 SCIP_CONS* cons /**< constraint data */
13818 )
13819{
13820 SCIP_CONSDATA* consdata;
13821
13822 assert(cons != NULL);
13823 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13824
13825 consdata = SCIPconsGetData(cons);
13826 assert(consdata != NULL);
13827
13828 return consdata->rhs;
13829}
13830
13831/** gets the nonlinear constraint as a nonlinear row representation. */
13833 SCIP* scip, /**< SCIP data structure */
13834 SCIP_CONS* cons, /**< constraint */
13835 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13836 )
13837{
13838 SCIP_CONSDATA* consdata;
13839
13840 assert(cons != NULL);
13841 assert(nlrow != NULL);
13842 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13843
13844 consdata = SCIPconsGetData(cons);
13845 assert(consdata != NULL);
13846
13847 if( consdata->nlrow == NULL )
13848 {
13849 SCIP_CALL( createNlRow(scip, cons) );
13850 }
13851 assert(consdata->nlrow != NULL);
13852 *nlrow = consdata->nlrow;
13853
13854 return SCIP_OKAY;
13855}
13856
13857/** returns the curvature of the expression of a given nonlinear constraint
13858 *
13859 * @note The curvature information is computed during CONSINITSOL.
13860 */
13862 SCIP_CONS* cons /**< constraint data */
13863 )
13864{
13865 SCIP_CONSDATA* consdata;
13866
13867 assert(cons != NULL);
13868 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13869
13870 consdata = SCIPconsGetData(cons);
13871 assert(consdata != NULL);
13872
13873 return consdata->curv;
13874}
13875
13876/** checks whether expression of constraint can be represented as quadratic form
13877 *
13878 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13879 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13880 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13881 */
13883 SCIP* scip, /**< SCIP data structure */
13884 SCIP_CONS* cons, /**< constraint data */
13885 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
13886 )
13887{
13888 SCIP_CONSDATA* consdata;
13889
13890 assert(scip != NULL);
13891 assert(cons != NULL);
13892 assert(isquadratic != NULL);
13893 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13894
13895 consdata = SCIPconsGetData(cons);
13896 assert(consdata != NULL);
13897 assert(consdata->expr != NULL);
13898
13899 /* check whether constraint expression is quadratic in extended formulation */
13900 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13901
13902 /* if not quadratic in non-extended formulation, then do indicate quadratic */
13903 if( *isquadratic )
13904 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
13905
13906 return SCIP_OKAY;
13907}
13908
13909/** changes left-hand-side of a nonlinear constraint
13910 *
13911 * @attention This method can only be called in the problem stage.
13912 */
13914 SCIP* scip, /**< SCIP data structure */
13915 SCIP_CONS* cons, /**< constraint data */
13916 SCIP_Real lhs /**< new left-hand-side */
13917 )
13918{
13919 SCIP_CONSDATA* consdata;
13920
13921 assert(scip != NULL);
13922 assert(cons != NULL);
13923 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13924
13926 {
13927 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13928 return SCIP_INVALIDCALL;
13929 }
13930
13931 /* we should have an original constraint */
13932 assert(SCIPconsIsOriginal(cons));
13933
13934 consdata = SCIPconsGetData(cons);
13935 assert(consdata != NULL);
13936
13937 if( consdata->lhs == lhs )
13938 return SCIP_OKAY;
13939
13940 consdata->lhs = lhs;
13941
13942 /* not sure we care about any of these flags for original constraints */
13943 consdata->ispropagated = FALSE;
13944
13945 return SCIP_OKAY;
13946}
13947
13948/** changes right-hand-side of a nonlinear constraint
13949 *
13950 * @attention This method can only be called in the problem stage.
13951 */
13953 SCIP* scip, /**< SCIP data structure */
13954 SCIP_CONS* cons, /**< constraint data */
13955 SCIP_Real rhs /**< new right-hand-side */
13956 )
13957{
13958 SCIP_CONSDATA* consdata;
13959
13960 assert(scip != NULL);
13961 assert(cons != NULL);
13962 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13963
13965 {
13966 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13967 return SCIP_INVALIDCALL;
13968 }
13969
13970 /* we should have an original constraint */
13971 assert(SCIPconsIsOriginal(cons));
13972
13973 consdata = SCIPconsGetData(cons);
13974 assert(consdata != NULL);
13975
13976 if( consdata->rhs == rhs )
13977 return SCIP_OKAY;
13978
13979 consdata->rhs = rhs;
13980
13981 /* not sure we care about any of these flags for original constraints */
13982 consdata->ispropagated = FALSE;
13983
13984 return SCIP_OKAY;
13985}
13986
13987/** changes expression of a nonlinear constraint
13988 *
13989 * @attention This method can only be called in the problem stage.
13990 */
13992 SCIP* scip, /**< SCIP data structure */
13993 SCIP_CONS* cons, /**< constraint data */
13994 SCIP_EXPR* expr /**< new expression */
13995 )
13996{
13997 SCIP_CONSHDLR* conshdlr;
13998 SCIP_CONSDATA* consdata;
13999
14000 assert(scip != NULL);
14001 assert(cons != NULL);
14002 assert(expr != NULL);
14003
14005 {
14006 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14007 return SCIP_INVALIDCALL;
14008 }
14009
14010 /* we should have an original constraint */
14011 assert(SCIPconsIsOriginal(cons));
14012
14013 conshdlr = SCIPconsGetHdlr(cons);
14014 assert(conshdlr != NULL);
14015 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14016
14017 consdata = SCIPconsGetData(cons);
14018 assert(consdata != NULL);
14019 assert(consdata->expr != NULL);
14020
14021 /* we should not have collected additional data for the expr
14022 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14023 */
14024 assert(consdata->nvarexprs == 0);
14025 assert(consdata->varexprs == NULL);
14026 assert(!consdata->catchedevents);
14027
14028 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14029
14030 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14031 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14032
14033 /* not sure we care about any of these flags for original constraints */
14034 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14035 consdata->issimplified = FALSE;
14036 consdata->ispropagated = FALSE;
14037
14038 return SCIP_OKAY;
14039}
14040
14041/** adds coef * var to nonlinear constraint
14042 *
14043 * @attention This method can only be called in the problem stage.
14044 */
14046 SCIP* scip, /**< SCIP data structure */
14047 SCIP_CONS* cons, /**< constraint data */
14048 SCIP_VAR* var, /**< variable */
14049 SCIP_Real coef /**< coefficient */
14050 )
14051{
14052 SCIP_CONSHDLR* conshdlr;
14053 SCIP_CONSDATA* consdata;
14054 SCIP_EXPR* varexpr;
14055
14056 assert(scip != NULL);
14057 assert(cons != NULL);
14058
14060 {
14061 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14062 return SCIP_INVALIDCALL;
14063 }
14064
14065 /* we should have an original constraint */
14066 assert(SCIPconsIsOriginal(cons));
14067
14068 if( coef == 0.0 )
14069 return SCIP_OKAY;
14070
14071 conshdlr = SCIPconsGetHdlr(cons);
14072 assert(conshdlr != NULL);
14073 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14074
14075 consdata = SCIPconsGetData(cons);
14076 assert(consdata != NULL);
14077 assert(consdata->expr != NULL);
14078
14079 /* we should not have collected additional data for it
14080 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14081 */
14082 assert(consdata->nvarexprs == 0);
14083 assert(consdata->varexprs == NULL);
14084 assert(!consdata->catchedevents);
14085
14086 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14087
14088 /* append to sum, if consdata->expr is sum and not used anywhere else */
14089 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14090 {
14091 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14092 }
14093 else
14094 {
14095 /* create new expression = 1 * consdata->expr + coef * var */
14096 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14097 SCIP_Real coefs[2] = { 1.0, coef };
14098
14099 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14100
14101 /* release old root expr */
14102 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14103 }
14104
14105 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14106
14107 /* not sure we care about any of these flags for original constraints */
14108 consdata->issimplified = FALSE;
14109 consdata->ispropagated = FALSE;
14110
14111 return SCIP_OKAY;
14112}
14113
14114/** adds coef * expr to nonlinear constraint
14115 *
14116 * @attention This method can only be called in the problem stage.
14117 */
14119 SCIP* scip, /**< SCIP data structure */
14120 SCIP_CONS* cons, /**< nonlinear constraint */
14121 SCIP_EXPR* expr, /**< expression */
14122 SCIP_Real coef /**< coefficient */
14123 )
14124{
14125 SCIP_CONSHDLR* conshdlr;
14126 SCIP_CONSDATA* consdata;
14127 SCIP_EXPR* exprowned;
14128
14129 assert(scip != NULL);
14130 assert(cons != NULL);
14131
14133 {
14134 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14135 return SCIP_INVALIDCALL;
14136 }
14137
14138 /* we should have an original constraint */
14139 assert(SCIPconsIsOriginal(cons));
14140
14141 if( coef == 0.0 )
14142 return SCIP_OKAY;
14143
14144 conshdlr = SCIPconsGetHdlr(cons);
14145 assert(conshdlr != NULL);
14146 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14147
14148 consdata = SCIPconsGetData(cons);
14149 assert(consdata != NULL);
14150 assert(consdata->expr != NULL);
14151
14152 /* free quadratic representation, if any is stored */
14153 SCIPfreeExprQuadratic(scip, consdata->expr);
14154
14155 /* free varexprs in consdata, in case they have been stored
14156 * (e.g., by a call to consGet(N)VarsNonlinear)
14157 */
14158 SCIP_CALL( freeVarExprs(scip, consdata) );
14159
14160 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14161 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14162
14163 /* append to sum, if consdata->expr is sum and not used anywhere else */
14164 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14165 {
14166 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14167 }
14168 else
14169 {
14170 /* create new expression = 1 * consdata->expr + coef * var */
14171 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14172 SCIP_Real coefs[2] = { 1.0, coef };
14173
14174 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14175
14176 /* release old root expr */
14177 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14178 }
14179
14180 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14181
14182 /* not sure we care about any of these flags for original constraints */
14183 consdata->issimplified = FALSE;
14184 consdata->ispropagated = FALSE;
14185
14186 return SCIP_OKAY;
14187}
14188
14189/** computes value of constraint expression in a given solution
14190 *
14191 * Stores value of constraint expression in sol in activity.
14192 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14193 */
14195 SCIP* scip, /**< SCIP data structure */
14196 SCIP_CONS* cons, /**< constraint */
14197 SCIP_SOL* sol, /**< solution */
14198 SCIP_Real* activity /**< buffer to store computed activity */
14199 )
14200{
14201 SCIP_CONSDATA* consdata;
14202
14203 assert(cons != NULL);
14204 assert(activity != NULL);
14205
14206 consdata = SCIPconsGetData(cons);
14207 assert(consdata != NULL);
14208
14209 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14210 *activity = SCIPexprGetEvalValue(consdata->expr);
14211
14212 return SCIP_OKAY;
14213}
14214
14215/** gets absolute violation of nonlinear constraint
14216 *
14217 * This function evaluates the constraints in the given solution.
14218 *
14219 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14220 */
14222 SCIP* scip, /**< SCIP data structure */
14223 SCIP_CONS* cons, /**< constraint */
14224 SCIP_SOL* sol, /**< solution to check */
14225 SCIP_Real* viol /**< buffer to store computed violation */
14226 )
14227{
14228 assert(cons != NULL);
14229 assert(viol != NULL);
14230
14231 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14232 *viol = getConsAbsViolation(cons);
14233
14234 return SCIP_OKAY;
14235}
14236
14237/** gets scaled violation of nonlinear constraint
14238 *
14239 * This function evaluates the constraints in the given solution.
14240 *
14241 * The scaling that is applied to the absolute violation of the constraint
14242 * depends on the setting of parameter constraints/nonlinear/violscale.
14243 */
14245 SCIP* scip, /**< SCIP data structure */
14246 SCIP_CONS* cons, /**< constraint */
14247 SCIP_SOL* sol, /**< solution to check */
14248 SCIP_Real* viol /**< buffer to store computed violation */
14249 )
14250{
14251 assert(cons != NULL);
14252 assert(viol != NULL);
14253
14254 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14255 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14256
14257 return SCIP_OKAY;
14258}
14259
14260/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14262 SCIP* scip, /**< SCIP data structure */
14263 SCIP_CONS* cons, /**< nonlinear constraint */
14264 SCIP_VAR** var, /**< pointer to store the variable */
14265 SCIP_Real* coef /**< pointer to store the coefficient */
14266 )
14267{
14268 SCIP_CONSDATA* consdata;
14269
14270 assert(cons != NULL);
14271 assert(var != NULL);
14272 assert(coef != NULL);
14273
14274 /* check for a linear variable that can be increased or decreased without harming feasibility */
14276
14277 consdata = SCIPconsGetData(cons);
14278 assert(consdata != NULL);
14279
14280 *var = consdata->linvardecr;
14281 *coef = consdata->linvardecrcoef;
14282}
14283
14284/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14286 SCIP* scip, /**< SCIP data structure */
14287 SCIP_CONS* cons, /**< nonlinear constraint */
14288 SCIP_VAR** var, /**< pointer to store the variable */
14289 SCIP_Real* coef /**< pointer to store the coefficient */
14290 )
14291{
14292 SCIP_CONSDATA* consdata;
14293
14294 assert(cons != NULL);
14295 assert(var != NULL);
14296 assert(coef != NULL);
14297
14298 /* check for a linear variable that can be increased or decreased without harming feasibility */
14300
14301 consdata = SCIPconsGetData(cons);
14302 assert(consdata != NULL);
14303
14304 *var = consdata->linvarincr;
14305 *coef = consdata->linvarincrcoef;
14306}
14307
14308
14309/*
14310 * Methods for Expressions in Nonlinear Constraints
14311 */
14312
14313/** returns the number of positive rounding locks of an expression */
14315 SCIP_EXPR* expr /**< expression */
14316 )
14317{
14318 assert(expr != NULL);
14319 assert(SCIPexprGetOwnerData(expr) != NULL);
14320
14321 return SCIPexprGetOwnerData(expr)->nlockspos;
14322}
14323
14324/** returns the number of negative rounding locks of an expression */
14326 SCIP_EXPR* expr /**< expression */
14327 )
14328{
14329 assert(expr != NULL);
14330 assert(SCIPexprGetOwnerData(expr) != NULL);
14331
14332 return SCIPexprGetOwnerData(expr)->nlocksneg;
14333}
14334
14335/** returns the variable used for linearizing a given expression (return value might be NULL)
14336 *
14337 * @note for variable expression it returns the corresponding variable
14338 */
14340 SCIP_EXPR* expr /**< expression */
14341 )
14342{
14343 SCIP_EXPR_OWNERDATA* ownerdata;
14344
14345 assert(expr != NULL);
14346
14347 ownerdata = SCIPexprGetOwnerData(expr);
14348 assert(ownerdata != NULL);
14349
14350 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14351}
14352
14353/** returns the number of enforcements for an expression */
14355 SCIP_EXPR* expr /**< expression */
14356 )
14357{
14358 assert(expr != NULL);
14359 assert(SCIPexprGetOwnerData(expr) != NULL);
14360
14361 return SCIPexprGetOwnerData(expr)->nenfos;
14362}
14363
14364/** returns the data for one of the enforcements of an expression */
14366 SCIP_EXPR* expr, /**< expression */
14367 int idx, /**< position of enforcement in enfos array */
14368 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14369 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14370 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14371 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14372 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14373 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14374 )
14375{
14376 SCIP_EXPR_OWNERDATA* ownerdata;
14377
14378 assert(expr != NULL);
14379
14380 ownerdata = SCIPexprGetOwnerData(expr);
14381 assert(ownerdata != NULL);
14382 assert(idx >= 0);
14383 assert(idx < ownerdata->nenfos);
14384 assert(ownerdata->enfos[idx] != NULL);
14385 assert(nlhdlr != NULL);
14386
14387 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14388
14389 if( nlhdlrexprdata != NULL )
14390 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14391
14392 if( nlhdlrparticipation != NULL )
14393 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14394
14395 if( sepabelowusesactivity != NULL )
14396 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14397
14398 if( sepaaboveusesactivity != NULL )
14399 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14400
14401 if( auxvalue != NULL )
14402 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14403}
14404
14405/** sets the auxiliary value of expression for one of the enforcements of an expression */
14407 SCIP_EXPR* expr, /**< expression */
14408 int idx, /**< position of enforcement in enfos array */
14409 SCIP_Real auxvalue /**< the new value of auxval */
14410 )
14411{
14412 SCIP_EXPR_OWNERDATA* ownerdata;
14413
14414 assert(expr != NULL);
14415
14416 ownerdata = SCIPexprGetOwnerData(expr);
14417 assert(ownerdata != NULL);
14418
14419 assert(idx >= 0);
14420 assert(idx < ownerdata->nenfos);
14421 assert(ownerdata->enfos[idx] != NULL);
14422
14423 ownerdata->enfos[idx]->auxvalue = auxvalue;
14424}
14425
14426/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14427 *
14428 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14429 */
14431 SCIP_EXPR* expr /**< expression */
14432 )
14433{
14434 assert(expr != NULL);
14435 assert(SCIPexprGetOwnerData(expr) != NULL);
14436
14437 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14438}
14439
14440/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14441 *
14442 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14443 */
14445 SCIP_EXPR* expr /**< expression */
14446 )
14447{
14448 assert(expr != NULL);
14449 assert(SCIPexprGetOwnerData(expr) != NULL);
14450
14451 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14452}
14453
14454/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14455 *
14456 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14457 */
14459 SCIP_EXPR* expr /**< expression */
14460 )
14461{
14462 assert(expr != NULL);
14463 assert(SCIPexprGetOwnerData(expr) != NULL);
14464
14465 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14466}
14467
14468/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14469 *
14470 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14471 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14472 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14473 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14474 * and also increments this count for all variables in the expression.
14475 *
14476 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14477 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14478 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14479 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14480 */
14482 SCIP* scip, /**< SCIP data structure */
14483 SCIP_EXPR* expr, /**< expression */
14484 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14485 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14486 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14487 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14488 )
14489{
14490 SCIP_EXPR_OWNERDATA* ownerdata;
14491
14492 assert(expr != NULL);
14493
14494 ownerdata = SCIPexprGetOwnerData(expr);
14495 assert(ownerdata != NULL);
14496
14497 /* do not store auxvar request for variable expressions */
14498 if( useauxvar && SCIPisExprVar(scip, expr) )
14499 useauxvar = FALSE;
14500
14501 if( ownerdata->nenfos >= 0 &&
14502 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14503 (ownerdata->nauxvaruses == 0 && useauxvar)
14504 ) )
14505 {
14506 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14507 * we require additional enforcement methods, that is,
14508 * - activity of expr was not used before but will be used now, or
14509 * - auxiliary variable of expr was not required before but will be used now
14510 */
14511 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14512 }
14513
14514 if( useauxvar )
14515 ++ownerdata->nauxvaruses;
14516
14517 if( useactivityforprop )
14518 ++ownerdata->nactivityusesprop;
14519
14520 if( useactivityforsepabelow || useactivityforsepaabove )
14521 ++ownerdata->nactivityusessepa;
14522
14523 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14524 * information is used in detectNlhdlr()
14525 */
14526 if( useactivityforsepabelow )
14527 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14528 if( useactivityforsepaabove )
14529 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14530
14531 if( useactivityforprop )
14532 {
14533 /* if activity will be used for propagation, then make sure there is a valid activity
14534 * this way, we can do a reversepropcall after detectNlhdlr
14535 */
14537 }
14538
14539 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14540 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14541 {
14542 SCIP_EXPRITER* it;
14543
14544 /* create and initialize iterator */
14547
14548 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14549 if( SCIPisExprVar(scip, expr) )
14550 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14551
14552 /* free iterator */
14553 SCIPfreeExpriter(&it);
14554 }
14555
14556 return SCIP_OKAY;
14557}
14558
14559/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14560 *
14561 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14562 * Assume that f(x) is associated with auxiliary variable z.
14563 *
14564 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14565 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14566 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14567 *
14568 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14569 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14570 */
14572 SCIP* scip, /**< SCIP data structure */
14573 SCIP_EXPR* expr, /**< expression */
14574 SCIP_SOL* sol, /**< solution */
14575 SCIP_Longint soltag, /**< tag of solution */
14576 SCIP_Real* viol, /**< buffer to store computed violation */
14577 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14578 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14579 )
14580{
14581 assert(scip != NULL);
14582 assert(expr != NULL);
14583 assert(viol != NULL);
14584
14585 /* make sure expression has been evaluated */
14586 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14587
14588 /* get violation from internal method */
14589 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14590
14591 return SCIP_OKAY;
14592}
14593
14594/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14595 *
14596 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14597 * Assume that f(w) is associated with auxiliary variable z.
14598 *
14599 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14600 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14601 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14602 *
14603 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14604 * both `violover` and `violunder` are set to TRUE.
14605 */
14607 SCIP* scip, /**< SCIP data structure */
14608 SCIP_EXPR* expr, /**< expression */
14609 SCIP_Real auxvalue, /**< the value of f(w) */
14610 SCIP_SOL* sol, /**< solution that has been evaluated */
14611 SCIP_Real* viol, /**< buffer to store computed violation */
14612 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14613 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14614 )
14615{
14616 assert(scip != NULL);
14617 assert(expr != NULL);
14618 assert(viol != NULL);
14619
14620 /* get violation from internal method */
14621 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14622
14623 return SCIP_OKAY;
14624}
14625
14626
14627/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14628 *
14629 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14630 * Assume that f(w) is associated with auxiliary variable z.
14631 *
14632 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14633 * the absolute violation divided by max(1,|f(w)|).
14634 *
14635 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14636 * both `violover` and `violunder` are set to TRUE.
14637 */
14639 SCIP* scip, /**< SCIP data structure */
14640 SCIP_EXPR* expr, /**< expression */
14641 SCIP_Real auxvalue, /**< the value of f(w) */
14642 SCIP_SOL* sol, /**< solution that has been evaluated */
14643 SCIP_Real* viol, /**< buffer to store computed violation */
14644 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14645 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14646 )
14647{
14648 assert(scip != NULL);
14649 assert(expr != NULL);
14650 assert(viol != NULL);
14651
14652 /* get violation from internal method */
14653 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14654
14655 if( !SCIPisInfinity(scip, *viol) )
14656 {
14657 assert(auxvalue != SCIP_INVALID);
14658 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14659 *viol /= MAX(1.0, REALABS(auxvalue));
14660 }
14661
14662 return SCIP_OKAY;
14663}
14664
14665/** returns bounds on the expression
14666 *
14667 * This gives an intersection of bounds from
14668 * - activity calculation (SCIPexprGetActivity()), if valid,
14669 * - auxiliary variable, if present,
14670 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14671 *
14672 * @note The returned interval can be empty!
14673 */
14675 SCIP* scip, /**< SCIP data structure */
14676 SCIP_EXPR* expr /**< expression */
14677 )
14678{
14679 SCIP_EXPR_OWNERDATA* ownerdata;
14680 SCIP_CONSHDLRDATA* conshdlrdata;
14681 SCIP_INTERVAL bounds;
14682
14683 assert(scip != NULL);
14684 assert(expr != NULL);
14685
14686 ownerdata = SCIPexprGetOwnerData(expr);
14687 assert(ownerdata != NULL);
14688
14689 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14690 assert(conshdlrdata != NULL);
14691
14692 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14693
14694 /* start with propbounds if they belong to current propagation */
14695 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14696 {
14697 bounds = ownerdata->propbounds;
14698 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14699 }
14700 else
14702
14703 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14704 {
14705 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14706 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14708 }
14709
14710 if( ownerdata->auxvar != NULL )
14711 {
14712 /* apply auxiliary variable bounds to bounds */
14713 SCIP_INTERVAL auxvarbounds;
14714
14715 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14716 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14717 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14718 }
14719
14720 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14721
14722 return bounds;
14723}
14724
14725/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14726 * corresponding (auxiliary) variable (if any)
14727 *
14728 * @attention this function should only be called during domain propagation in cons_nonlinear
14729 */
14731 SCIP* scip, /**< SCIP data structure */
14732 SCIP_EXPR* expr, /**< expression to be tightened */
14733 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14734 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14735 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14736 )
14737{
14738 SCIP_EXPR_OWNERDATA* ownerdata;
14739 SCIP_CONSHDLRDATA* conshdlrdata;
14740
14741 assert(scip != NULL);
14742 assert(expr != NULL);
14743 assert(cutoff != NULL);
14744
14745 ownerdata = SCIPexprGetOwnerData(expr);
14746 assert(ownerdata != NULL);
14747 assert(ownerdata->conshdlr != NULL);
14748
14749 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14750 assert(conshdlrdata != NULL);
14751
14752 /* the code below assumes that current activity is valid
14753 * if it turns out that we cannot ensure that, then we should change code
14754 */
14755 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14757
14758 *cutoff = FALSE;
14759
14760#ifdef DEBUG_PROP
14761 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14762 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14763 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14764#endif
14765
14766 if( SCIPexprIsIntegral(expr) )
14767 {
14768 /* apply integrality to new bounds
14769 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14770 */
14771 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14772 newbounds.inf = SCIPceil(scip, newbounds.inf);
14773 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14774 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14775#ifdef DEBUG_PROP
14776 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14777#endif
14778 }
14779
14781 {
14782 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14783
14784 *cutoff = TRUE;
14785 return SCIP_OKAY;
14786 }
14787
14788 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14789 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14790 {
14791 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14792
14793 *cutoff = TRUE;
14794 return SCIP_OKAY;
14795 }
14796
14797 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14798 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14799 {
14800 /* if already having propbounds in expr, then tighten newbounds by propbounds */
14801 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14802 }
14803 else
14804 {
14805 /* first time we have propbounds for expr in this propagation rounds:
14806 * intersect with activity (though don't let it become empty if very close intervals)
14807 */
14808 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
14809 }
14810#ifdef DEBUG_PROP
14811 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14812#endif
14813
14814 /* check if the new bounds lead to an empty interval */
14816 {
14817 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14818
14819 *cutoff = TRUE;
14820 return SCIP_OKAY;
14821 }
14822
14823 /* if expr is not constant or variable, then store newbounds in expr->propbounds
14824 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14825 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14826 */
14827 if( SCIPexprGetNChildren(expr) > 0 )
14828 {
14829 ownerdata->propbounds = newbounds;
14830 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14831 }
14832
14833 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14834 * propagation or update of auxvar bounds
14835 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14836 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14837 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14838 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14839 * one or should we not even update propbounds to newbounds if the update is small?
14840 */
14841 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14842 {
14843#ifdef DEBUG_PROP
14844 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);
14845#endif
14846 return SCIP_OKAY;
14847 }
14848
14849 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14850 {
14851 /* add expression to propagation queue if not there yet and not var or constant and
14852 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14853 */
14854#ifdef DEBUG_PROP
14855 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14856#endif
14857 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14858 ownerdata->inpropqueue = TRUE;
14859 }
14860
14861 /* update bounds on variable or auxiliary variable */
14862 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14863
14864 return SCIP_OKAY;
14865}
14866
14867/** mark constraints that include this expression to be propagated again
14868 *
14869 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14870 * a change of variable bounds, e.g., because new information on the expression is available
14871 * that could potentially lead to tighter expression activity values.
14872 *
14873 * Note, that this call marks also constraints for propagation which only share some variable
14874 * with this expression.
14875 */
14877 SCIP* scip, /**< SCIP data structure */
14878 SCIP_EXPR* expr /**< expression to propagate again */
14879 )
14880{
14881 SCIP_EXPRITER* it;
14882 SCIP_CONSDATA* consdata;
14883 SCIP_EXPR_OWNERDATA* ownerdata;
14884 int c;
14885
14886 assert(scip != NULL);
14887 assert(expr != NULL);
14888
14889 ownerdata = SCIPexprGetOwnerData(expr);
14890 assert(ownerdata != NULL);
14891
14892 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14893
14896
14897 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14898 {
14899 if( !SCIPisExprVar(scip, expr) )
14900 continue;
14901
14902 ownerdata = SCIPexprGetOwnerData(expr);
14903 assert(ownerdata != NULL);
14904
14905 for( c = 0; c < ownerdata->nconss; ++c )
14906 {
14907 consdata = SCIPconsGetData(ownerdata->conss[c]);
14908 assert(consdata != NULL);
14909 consdata->ispropagated = FALSE;
14910 }
14911 }
14912
14913 SCIPfreeExpriter(&it);
14914
14915 return SCIP_OKAY;
14916}
14917
14918/** adds violation-branching score to an expression
14919 *
14920 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14921 * The expression must either be a variable expression or have an aux-variable.
14922 * In the latter case, branching on auxiliary variables must have been enabled.
14923 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14924 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14925 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14926 *
14927 * @see SCIPaddExprsViolScoreNonlinear()
14928 */
14930 SCIP* scip, /**< SCIP data structure */
14931 SCIP_EXPR* expr, /**< expression where to add branching score */
14932 SCIP_Real violscore /**< violation score to add to expression */
14933 )
14934{
14935 SCIP_EXPR_OWNERDATA* ownerdata;
14936 SCIP_CONSHDLRDATA* conshdlrdata;
14937
14938 assert(scip != NULL);
14939 assert(expr != NULL);
14940 assert(violscore >= 0.0);
14941
14942 ownerdata = SCIPexprGetOwnerData(expr);
14943 assert(ownerdata != NULL);
14944
14945 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14946 assert(conshdlrdata != NULL);
14947
14948 /* if not allowing to branch on auxvars, then expr must be a var-expr */
14949 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14950 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14951 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14952
14953 /* reset branching score if we are in a different enfo round */
14954 if( ownerdata->violscoretag != conshdlrdata->enforound )
14955 {
14956 ownerdata->violscoresum = violscore;
14957 ownerdata->violscoremax = violscore;
14958 ownerdata->nviolscores = 1;
14959 ownerdata->violscoretag = conshdlrdata->enforound;
14960 return;
14961 }
14962
14963 ownerdata->violscoresum += violscore;
14964 if( violscore > ownerdata->violscoremax )
14965 ownerdata->violscoremax = violscore;
14966 ++ownerdata->nviolscores;
14967}
14968
14969/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14970 *
14971 * Each expression must either be a variable expression or have an aux-variable.
14972 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14973 * variables present in `exprs`.
14974 */
14976 SCIP* scip, /**< SCIP data structure */
14977 SCIP_EXPR** exprs, /**< expressions where to add branching score */
14978 int nexprs, /**< number of expressions */
14979 SCIP_Real violscore, /**< violation score to add to expression */
14980 SCIP_SOL* sol, /**< current solution */
14981 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
14982 )
14983{
14984 SCIP_EXPRITER* it;
14985 SCIP_EXPR** varexprs;
14986 SCIP_EXPR* e;
14987 int nvars;
14988 int varssize;
14989 int i;
14990
14991 assert(exprs != NULL || nexprs == 0);
14992 assert(success != NULL);
14993
14994 if( nexprs == 0 )
14995 {
14996 *success = FALSE;
14997 return SCIP_OKAY;
14998 }
14999
15000 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
15001 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
15002 {
15003 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15004 return SCIP_OKAY;
15005 }
15006
15007 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15008 nvars = 0;
15009 varssize = 5;
15010 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15011
15014
15015 for( i = 0; i < nexprs; ++i )
15016 {
15017 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15018 {
15019 assert(e != NULL);
15020
15021 if( SCIPisExprVar(scip, e) )
15022 {
15023 /* add variable expression to vars array */
15024 if( varssize == nvars )
15025 {
15026 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15027 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15028 }
15029 assert(varssize > nvars);
15030
15031 varexprs[nvars++] = e;
15032 }
15033 }
15034 }
15035
15036 SCIPfreeExpriter(&it);
15037
15038 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15039
15040 SCIPfreeBufferArray(scip, &varexprs);
15041
15042 return SCIP_OKAY;
15043}
15044
15045/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15047 SCIP_EXPR* expr /**< expression */
15048 )
15049{
15050 SCIP_EXPR_OWNERDATA* ownerdata;
15051 SCIP_CONSHDLRDATA* conshdlrdata;
15052
15053 assert(expr != NULL);
15054
15055 ownerdata = SCIPexprGetOwnerData(expr);
15056 assert(ownerdata != NULL);
15057
15058 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15059 assert(conshdlrdata != NULL);
15060
15061 if( conshdlrdata->enforound != ownerdata->violscoretag )
15062 return 0.0;
15063
15064 if( ownerdata->nviolscores == 0 )
15065 return 0.0;
15066
15067 switch( conshdlrdata->branchscoreagg )
15068 {
15069 case 'a' :
15070 /* average */
15071 return ownerdata->violscoresum / ownerdata->nviolscores;
15072
15073 case 'm' :
15074 /* maximum */
15075 return ownerdata->violscoremax;
15076
15077 case 's' :
15078 /* sum */
15079 return ownerdata->violscoresum;
15080
15081 default:
15082 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15083 SCIPABORT();
15084 return SCIP_INVALID;
15085 }
15086}
15087
15088/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15089 *
15090 * @see SCIPexprGetDerivative()
15091 */
15093 SCIP* scip, /**< SCIP data structure */
15094 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15095 SCIP_VAR* var /**< variable (needs to be in the expression) */
15096 )
15097{
15098 SCIP_EXPR_OWNERDATA* ownerdata;
15099 SCIP_CONSHDLRDATA* conshdlrdata;
15100 SCIP_EXPR* varexpr;
15101
15102 assert(scip != NULL);
15103 assert(expr != NULL);
15104 assert(var != NULL);
15105
15106 /* return 0.0 for value expression */
15107 if( SCIPisExprValue(scip, expr) )
15108 {
15109 assert(SCIPexprGetDerivative(expr) == 0.0);
15110 return 0.0;
15111 }
15112
15113 /* check if an error occurred during the last SCIPevalExprGradient() call */
15114 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15115 return SCIP_INVALID;
15116
15117 ownerdata = SCIPexprGetOwnerData(expr);
15118 assert(ownerdata != NULL);
15119
15120 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15121 assert(conshdlrdata != NULL);
15122
15123 /* use variable to expressions mapping which is stored in the constraint handler data */
15124 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15125
15126 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15127 assert(varexpr != NULL);
15128 assert(SCIPisExprVar(scip, varexpr));
15129
15130 /* use difftag to decide whether the variable belongs to the expression */
15131 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15132}
15133
15134/** 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)
15135 *
15136 * @see SCIPexprGetBardot()
15137 */
15139 SCIP* scip, /**< SCIP data structure */
15140 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15141 SCIP_VAR* var /**< variable (needs to be in the expression) */
15142 )
15143{
15144 SCIP_EXPR_OWNERDATA* ownerdata;
15145 SCIP_CONSHDLRDATA* conshdlrdata;
15146 SCIP_EXPR* varexpr;
15147
15148 assert(scip != NULL);
15149 assert(expr != NULL);
15150 assert(var != NULL);
15151
15152 /* return 0.0 for value expression */
15153 if( SCIPisExprValue(scip, expr) )
15154 return 0.0;
15155
15156 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15157 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15158 return SCIP_INVALID;
15159
15160 ownerdata = SCIPexprGetOwnerData(expr);
15161 assert(ownerdata != NULL);
15162
15163 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15164 assert(conshdlrdata != NULL);
15165
15166 /* use variable to expressions mapping which is stored in the constraint handler data;
15167 * if this fails it means that we are asking for the var's component of H*u for a var
15168 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15169 */
15170 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15171
15172 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15173 assert(varexpr != NULL);
15174 assert(SCIPisExprVar(scip, varexpr));
15175
15176 /* use difftag to decide whether the variable belongs to the expression */
15177 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15178}
15179
15180/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15181 *
15182 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15183 */
15185 SCIP* scip, /**< SCIP data structure */
15186 SCIP_EXPR* expr, /**< quadratic expression */
15187 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15188 )
15189{
15190 SCIP_Real auxvalue;
15191 int nlinexprs;
15192 SCIP_Real* lincoefs;
15193 SCIP_EXPR** linexprs;
15194 int nquadexprs;
15195 int nbilinexprs;
15196 int i;
15197
15198 assert(scip != NULL);
15199 assert(expr != NULL);
15200
15201 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15202
15203 /* linear terms */
15204 for( i = 0; i < nlinexprs; ++i )
15205 {
15206 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15207 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15208 }
15209
15210 /* quadratic terms */
15211 for( i = 0; i < nquadexprs; ++i )
15212 {
15213 SCIP_EXPR* quadexprterm;
15214 SCIP_Real lincoef;
15215 SCIP_Real sqrcoef;
15216 SCIP_Real solval;
15217
15218 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15219
15220 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15221
15222 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15223 auxvalue += (lincoef + sqrcoef * solval) * solval;
15224 }
15225
15226 /* bilinear terms */
15227 for( i = 0; i < nbilinexprs; ++i )
15228 {
15229 SCIP_EXPR* expr1;
15230 SCIP_EXPR* expr2;
15231 SCIP_Real coef;
15232
15233 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15234
15235 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
15236 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
15237 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
15238 }
15239
15240 return auxvalue;
15241}
15242
15243/**@addtogroup PublicNlhdlrInterfaceMethods
15244 * @{
15245 */
15246
15247/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15249 SCIP* scip, /**< SCIP data structure */
15250 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15251 const char* name, /**< name of nonlinear handler (must not be NULL) */
15252 const char* desc, /**< description of nonlinear handler (can be NULL) */
15253 int detectpriority, /**< detection priority of nonlinear handler */
15254 int enfopriority, /**< enforcement priority of nonlinear handler */
15255 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15256 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15257 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15258 )
15259{
15260 SCIP_CONSHDLR* conshdlr;
15261 SCIP_CONSHDLRDATA* conshdlrdata;
15262
15263 assert(scip != NULL);
15264 assert(nlhdlr != NULL);
15265 assert(detect != NULL);
15266
15267 /* find myself */
15268 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15269 if( conshdlr == NULL )
15270 {
15271 SCIPerrorMessage("nonlinear constraint handler not found");
15272 return SCIP_PLUGINNOTFOUND;
15273 }
15274
15275 /* create nlhdlr */
15276 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15277
15278 /* include into constraint handler */
15279 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15280 assert(conshdlrdata != NULL);
15281
15282 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15283
15284 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15285 ++conshdlrdata->nnlhdlrs;
15286
15287 /* sort nonlinear handlers by detection priority, in decreasing order
15288 * will happen in INIT, so only do when called late
15289 */
15290 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15291 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15292
15293 return SCIP_OKAY;
15294}
15295
15296/** get number of nonlinear handler */
15298 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15299 )
15300{
15301 SCIP_CONSHDLRDATA* conshdlrdata;
15302
15303 assert(conshdlr != NULL);
15304
15305 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15306 assert(conshdlrdata != NULL);
15307
15308 return conshdlrdata->nnlhdlrs;
15309}
15310
15311/** get nonlinear handlers */
15313 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15314 )
15315{
15316 SCIP_CONSHDLRDATA* conshdlrdata;
15317
15318 assert(conshdlr != NULL);
15319
15320 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15321 assert(conshdlrdata != NULL);
15322
15323 return conshdlrdata->nlhdlrs;
15324}
15325
15326/** returns a nonlinear handler of a given name (or NULL if not found) */
15328 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15329 const char* name /**< name of nonlinear handler */
15330 )
15331{
15332 SCIP_CONSHDLRDATA* conshdlrdata;
15333 int h;
15334
15335 assert(conshdlr != NULL);
15336 assert(name != NULL);
15337
15338 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15339 assert(conshdlrdata != NULL);
15340
15341 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15342 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15343 return conshdlrdata->nlhdlrs[h];
15344
15345 return NULL;
15346}
15347
15348/** gives expression data that a given nonlinear handler stored in an expression
15349 *
15350 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15351 */
15353 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15354 SCIP_EXPR* expr /**< expression */
15355 )
15356{
15357 SCIP_EXPR_OWNERDATA* ownerdata;
15358 int e;
15359
15360 assert(nlhdlr != NULL);
15361 assert(expr != NULL);
15362
15363 ownerdata = SCIPexprGetOwnerData(expr);
15364 assert(ownerdata != NULL);
15365
15366 for( e = 0; e < ownerdata->nenfos; ++e )
15367 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15368 return ownerdata->enfos[e]->nlhdlrexprdata;
15369
15370 return NULL;
15371}
15372
15373/** @} */
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:262
#define SCIP_MAXSTRLEN
Definition: def.h:283
#define SCIP_Longint
Definition: def.h:157
#define EPSROUND(x, eps)
Definition: def.h:207
#define EPSISINT(x, eps)
Definition: def.h:209
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_INTERVAL_INFINITY
Definition: def.h:194
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:238
#define MAX3(x, y, z)
Definition: def.h:242
#define SCIP_Real
Definition: def.h:172
#define ABS(x)
Definition: def.h:230
#define EPSFRAC(x, eps)
Definition: def.h:208
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:234
#define SCIP_CALL_ABORT(x)
Definition: def.h:348
#define SCIP_LONGINT_FORMAT
Definition: def.h:164
#define SCIPABORT()
Definition: def.h:341
#define REALABS(x)
Definition: def.h:196
#define SCIP_CALL(x)
Definition: def.h:369
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:5206
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:643
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:508
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:390
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:3110
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3283
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3263
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3158
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition: misc.c:3535
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3076
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3425
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3194
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3441
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition: misc.c:3792
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3819
SCIP_Bool SCIPhashsetIsEmpty(SCIP_HASHSET *hashset)
Definition: misc.c:3986
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition: misc.c:3802
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition: misc.c:3761
SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3860
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2349
#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:2299
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2611
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2550
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition: lpi_clp.cpp:1179
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3947
SCIP_RETCODE SCIPlpiChgObjsen(SCIP_LPI *lpi, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:1232
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition: lpi_clp.cpp:3861
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:643
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2637
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3720
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:2816
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1908
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1833
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:1252
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1447
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition: lpi_clp.cpp:1429
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3475
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:10397
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10384
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:672
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
Definition: scip_branch.c:904
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1133
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:435
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:856
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17180
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17169
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition: lp.c:17144
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4246
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4989
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4655
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4216
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4236
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:4612
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8263
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8492
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8253
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition: cons.c:8351
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8402
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8532
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8432
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8362
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8542
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8422
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8294
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:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8452
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8472
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8330
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8233
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition: cons.c:8340
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8482
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8412
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8502
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:994
SCIP_RETCODE SCIPdialoghdlrAddHistory(SCIP_DIALOGHDLR *dialoghdlr, SCIP_DIALOG *dialog, const char *command, SCIP_Bool escapecommand)
Definition: dialog.c:725
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:1027
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:111
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:241
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:361
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:407
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:293
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:327
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:4053
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:1040
SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
Definition: scip_expr.c:1798
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1642
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3871
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4215
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2021
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition: expr_pow.c:3456
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1471
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1673
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:969
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition: scip_expr.c:1658
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:930
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition: expr.c:3932
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3971
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1460
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition: scip_expr.c:2064
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition: expr.c:3958
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition: expr.c:4090
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4251
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:4130
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition: scip_expr.c:1255
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:1449
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2401
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1424
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:1438
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:1387
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:2343
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition: expr.c:4100
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1493
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:1482
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3945
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:4043
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition: scip_expr.c:1826
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:2383
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition: expr.c:3999
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3881
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:1325
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:4027
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:4175
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:707
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2357
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:1288
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition: scip_expr.c:1416
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:3861
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition: scip_expr.c:2102
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition: expr.c:4014
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:1779
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1723
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3894
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:721
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:263
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:169
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:248
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition: scip_lp.c:439
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition: scip_lp.c:429
#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:7531
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
Definition: lp.c:17485
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2216
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17380
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1566
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1872
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17341
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:345
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:470
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:837
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:222
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1042
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1170
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1073
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1213
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1343
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_Real SCIPgetAvgPseudocostCount(SCIP *scip, SCIP_BRANCHDIR dir)
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:99
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:61
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:672
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:5326
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip_var.c:4440
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17807
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:9043
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17556
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18162
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17944
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17742
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5443
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17602
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18106
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17776
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17437
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:4768
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:8907
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4736
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17628
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8281
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18448
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18152
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18459
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18096
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8808
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11960
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:1020
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition: misc.c:996
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition: misc.c:1082
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition: misc.c:1237
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition: misc.c:1133
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10131
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10109
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:6079
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:5540
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10878
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10867
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)
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:5171
#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