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