SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_nonlinear.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 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#include "scip/scip_datatree.h"
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 {
857 }
858 else
859 {
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 */
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 */
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 */
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 */
1024 && ( !EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) /*lint !e835*/
1025 || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0) ) ) /*lint !e835*/
1026 boundtightened = TRUE;
1027
1028 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1029 * - propagation can only find something new if a bound was tightened
1030 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1031 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1032 */
1033 if( boundtightened )
1034 {
1035 SCIP_CONSDATA* consdata;
1036 int c;
1037
1038 for( c = 0; c < ownerdata->nconss; ++c )
1039 {
1040 assert(ownerdata->conss[c] != NULL);
1041 consdata = SCIPconsGetData(ownerdata->conss[c]);
1042
1043 /* if bound tightening, then mark constraints to be propagated again
1044 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1045 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1046 * the locks don't help since they are not available separately for each constraint
1047 */
1048 consdata->ispropagated = FALSE;
1049 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1050
1051 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1053 {
1054 consdata->issimplified = FALSE;
1055 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1056 }
1057 }
1058 }
1059
1060 /* update curboundstag, lastboundrelax, and expr activity */
1061 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1062 {
1063 SCIP_CONSHDLRDATA* conshdlrdata;
1064 SCIP_INTERVAL activity;
1065
1066 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1067 assert(conshdlrdata != NULL);
1068
1069 /* increase tag on bounds */
1070 ++conshdlrdata->curboundstag;
1071 assert(conshdlrdata->curboundstag > 0);
1072
1073 /* remember also if we relaxed bounds now */
1074 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1075 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1076
1077 /* update the activity of the var-expr here immediately
1078 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1079 */
1080 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1081 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1082#ifdef DEBUG_PROP
1083 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1084#endif
1085 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1086 }
1087
1088 return SCIP_OKAY;
1089}
1090
1091/** registers event handler to catch variable events on variable
1092 *
1093 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1094 * When an event occurs, all stored constraints are notified.
1095 */
1096static
1098 SCIP* scip, /**< SCIP data structure */
1099 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1100 SCIP_EXPR* expr, /**< variable expression */
1101 SCIP_CONS* cons /**< nonlinear constraint */
1102 )
1103{
1104 SCIP_EXPR_OWNERDATA* ownerdata;
1105
1106 assert(eventhdlr != NULL);
1107 assert(expr != NULL);
1108 assert(SCIPisExprVar(scip, expr));
1109 assert(cons != NULL);
1110
1111 ownerdata = SCIPexprGetOwnerData(expr);
1112 assert(ownerdata != NULL);
1113
1114#ifndef NDEBUG
1115 /* assert that constraint does not double-catch variable */
1116 {
1117 int i;
1118 for( i = 0; i < ownerdata->nconss; ++i )
1119 assert(ownerdata->conss[i] != cons);
1120 }
1121#endif
1122
1123 /* append cons to ownerdata->conss */
1124 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1125 ownerdata->conss[ownerdata->nconss++] = cons;
1126 /* we're not capturing the constraint here to avoid circular references */
1127
1128 /* updated sorted flag */
1129 if( ownerdata->nconss <= 1 )
1130 ownerdata->consssorted = TRUE;
1131 else if( ownerdata->consssorted )
1132 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) < 0;
1133
1134 /* catch variable events, if not done so yet (first constraint) */
1135 if( ownerdata->filterpos < 0 )
1136 {
1137 SCIP_EVENTTYPE eventtype;
1138
1139 assert(ownerdata->nconss == 1);
1140
1142
1143 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1144 assert(ownerdata->filterpos >= 0);
1145 }
1146
1147 return SCIP_OKAY;
1148}
1149
1150/** catch variable events */
1151static
1153 SCIP* scip, /**< SCIP data structure */
1154 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1155 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1156 )
1157{
1158 SCIP_CONSHDLRDATA* conshdlrdata;
1159 SCIP_CONSDATA* consdata;
1160 SCIP_EXPR* expr;
1161 int i;
1162
1163 assert(eventhdlr != NULL);
1164 assert(cons != NULL);
1165
1166 consdata = SCIPconsGetData(cons);
1167 assert(consdata != NULL);
1168 assert(consdata->varexprs != NULL);
1169 assert(consdata->nvarexprs >= 0);
1170
1171 /* check if we have catched variable events already */
1172 if( consdata->catchedevents )
1173 return SCIP_OKAY;
1174
1175 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1176 assert(conshdlrdata != NULL);
1177#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1178 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1179#endif
1180
1181 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1182
1183 for( i = 0; i < consdata->nvarexprs; ++i )
1184 {
1185 expr = consdata->varexprs[i];
1186
1187 assert(expr != NULL);
1188 assert(SCIPisExprVar(scip, expr));
1189
1190 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1191
1192 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1193 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1194 */
1195 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1196 {
1197 SCIP_INTERVAL activity;
1198 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1199 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1200 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1201#ifdef DEBUG_PROP
1202 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1203#endif
1204 }
1205 }
1206
1207 consdata->catchedevents = TRUE;
1208
1209 return SCIP_OKAY;
1210}
1211
1212/** unregisters event handler to catch variable events on variable
1213 *
1214 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1215 * If this was the last constraint, then the event handler is unregistered for this variable.
1216 */
1217static
1219 SCIP* scip, /**< SCIP data structure */
1220 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1221 SCIP_EXPR* expr, /**< variable expression */
1222 SCIP_CONS* cons /**< expr constraint */
1223 )
1224{
1225 SCIP_EXPR_OWNERDATA* ownerdata;
1226 int pos;
1227
1228 assert(eventhdlr != NULL);
1229 assert(expr != NULL);
1230 assert(SCIPisExprVar(scip, expr));
1231 assert(cons != NULL);
1232
1233 ownerdata = SCIPexprGetOwnerData(expr);
1234 assert(ownerdata != NULL);
1235 assert(ownerdata->nconss > 0);
1236
1237 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1238 {
1239 pos = ownerdata->nconss-1;
1240 }
1241 else
1242 {
1243 if( !ownerdata->consssorted )
1244 {
1245 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1246 ownerdata->consssorted = TRUE;
1247 }
1248
1249 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1250 {
1251 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1252 return SCIP_ERROR;
1253 }
1254 assert(pos >= 0 && pos < ownerdata->nconss);
1255 }
1256 assert(ownerdata->conss[pos] == cons);
1257
1258 /* move last constraint into position of removed constraint */
1259 if( pos < ownerdata->nconss-1 )
1260 {
1261 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1262 ownerdata->consssorted = FALSE;
1263 }
1264 --ownerdata->nconss;
1265
1266 /* drop variable events if that was the last constraint */
1267 if( ownerdata->nconss == 0 )
1268 {
1269 SCIP_EVENTTYPE eventtype;
1270
1271 assert(ownerdata->filterpos >= 0);
1272
1274
1275 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1276 ownerdata->filterpos = -1;
1277 }
1278
1279 return SCIP_OKAY;
1280}
1281
1282/** drop variable events */
1283static
1285 SCIP* scip, /**< SCIP data structure */
1286 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1287 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1288 )
1289{
1290 SCIP_CONSDATA* consdata;
1291 int i;
1292
1293 assert(eventhdlr != NULL);
1294 assert(cons != NULL);
1295
1296 consdata = SCIPconsGetData(cons);
1297 assert(consdata != NULL);
1298
1299 /* check if we have catched variable events already */
1300 if( !consdata->catchedevents )
1301 return SCIP_OKAY;
1302
1303 assert(consdata->varexprs != NULL);
1304 assert(consdata->nvarexprs >= 0);
1305
1306 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1307
1308 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1309 {
1310 assert(consdata->varexprs[i] != NULL);
1311
1312 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1313 }
1314
1315 consdata->catchedevents = FALSE;
1316
1317 return SCIP_OKAY;
1318}
1319
1320/** creates and captures a nonlinear constraint
1321 *
1322 * @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
1323 */
1324static
1326 SCIP* scip, /**< SCIP data structure */
1327 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1328 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1329 const char* name, /**< name of constraint */
1330 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1331 SCIP_Real lhs, /**< left hand side of constraint */
1332 SCIP_Real rhs, /**< right hand side of constraint */
1333 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1334 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1335 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1336 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1337 * Usually set to TRUE. */
1338 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1339 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1340 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1341 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1342 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1343 * Usually set to TRUE. */
1344 SCIP_Bool local, /**< is constraint only valid locally?
1345 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1346 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1347 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1348 * adds coefficients to this constraint. */
1349 SCIP_Bool dynamic, /**< is constraint subject to aging?
1350 * Usually set to FALSE. Set to TRUE for own cuts which
1351 * are separated as constraints. */
1352 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1353 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1354 )
1355{
1356 SCIP_CONSHDLRDATA* conshdlrdata;
1357 SCIP_CONSDATA* consdata;
1358
1359 assert(conshdlr != NULL);
1360 assert(expr != NULL);
1361
1362 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1363 assert(conshdlrdata != NULL);
1364
1365 if( local && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
1366 {
1367 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1368 return SCIP_INVALIDCALL;
1369 }
1370
1371 /* TODO we should allow for non-initial nonlinear constraints */
1372 if( !initial )
1373 {
1374 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1375 return SCIP_INVALIDCALL;
1376 }
1377
1378 if( isnan(lhs) || isnan(rhs) )
1379 {
1380 SCIPerrorMessage("%s hand side of nonlinear constraint <%s> is nan\n",
1381 isnan(lhs) ? "left" : "right", name);
1382 return SCIP_INVALIDDATA;
1383 }
1384
1385 /* create constraint data */
1387
1388 if( copyexpr )
1389 {
1390 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1391 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1392 }
1393 else
1394 {
1395 consdata->expr = expr;
1396 SCIPcaptureExpr(consdata->expr);
1397 }
1398 consdata->lhs = lhs;
1399 consdata->rhs = rhs;
1400 consdata->consindex = conshdlrdata->lastconsindex++;
1401 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1402
1403 /* create constraint */
1404 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1405 local, modifiable, dynamic, removable, FALSE) );
1406
1407 return SCIP_OKAY;
1408}
1409
1410/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1411 *
1412 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1413 * Assume that f(x) is associated with auxiliary variable z.
1414 *
1415 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1416 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1417 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1418 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1419 *
1420 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1421 */
1422static
1424 SCIP* scip, /**< SCIP data structure */
1425 SCIP_EXPR* expr, /**< expression */
1426 SCIP_SOL* sol, /**< solution that has been evaluated */
1427 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1428 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1429 )
1430{
1431 SCIP_EXPR_OWNERDATA* ownerdata;
1432 SCIP_Real auxvarvalue;
1433
1434 assert(expr != NULL);
1435
1436 ownerdata = SCIPexprGetOwnerData(expr);
1437 assert(ownerdata != NULL);
1438 assert(ownerdata->auxvar != NULL);
1439
1440 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1441 {
1442 if( violunder != NULL )
1443 *violunder = TRUE;
1444 if( violover != NULL )
1445 *violover = TRUE;
1446 return SCIPinfinity(scip);
1447 }
1448
1449 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1450
1451 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1452 {
1453 if( violunder != NULL )
1454 *violunder = FALSE;
1455 if( violover != NULL )
1456 *violover = TRUE;
1457 return auxvarvalue - SCIPexprGetEvalValue(expr);
1458 }
1459
1460 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1461 {
1462 if( violunder != NULL )
1463 *violunder = TRUE;
1464 if( violover != NULL )
1465 *violover = FALSE;
1466 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1467 }
1468
1469 if( violunder != NULL )
1470 *violunder = FALSE;
1471 if( violover != NULL )
1472 *violover = FALSE;
1473 return 0.0;
1474}
1475
1476/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1477 *
1478 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1479 * Assume that f(w) is associated with auxiliary variable z.
1480 *
1481 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1482 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1483 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1484 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1485 *
1486 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1487 */
1488static
1490 SCIP* scip, /**< SCIP data structure */
1491 SCIP_EXPR* expr, /**< expression */
1492 SCIP_Real auxvalue, /**< value of f(w) */
1493 SCIP_SOL* sol, /**< solution that has been evaluated */
1494 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1495 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1496 )
1497{
1498 SCIP_EXPR_OWNERDATA* ownerdata;
1499 SCIP_Real auxvarvalue;
1500
1501 assert(expr != NULL);
1502
1503 ownerdata = SCIPexprGetOwnerData(expr);
1504 assert(ownerdata != NULL);
1505 assert(ownerdata->auxvar != NULL);
1506
1507 if( auxvalue == SCIP_INVALID )
1508 {
1509 if( violunder != NULL )
1510 *violunder = TRUE;
1511 if( violover != NULL )
1512 *violover = TRUE;
1513 return SCIPinfinity(scip);
1514 }
1515
1516 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1517
1518 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1519 {
1520 if( violunder != NULL )
1521 *violunder = FALSE;
1522 if( violover != NULL )
1523 *violover = TRUE;
1524 return auxvarvalue - auxvalue;
1525 }
1526
1527 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1528 {
1529 if( violunder != NULL )
1530 *violunder = TRUE;
1531 if( violover != NULL )
1532 *violover = FALSE;
1533 return auxvalue - auxvarvalue;
1534 }
1535
1536 if( violunder != NULL )
1537 *violunder = FALSE;
1538 if( violover != NULL )
1539 *violover = FALSE;
1540
1541 return 0.0;
1542}
1543
1544/** computes violation of a constraint */
1545static
1547 SCIP* scip, /**< SCIP data structure */
1548 SCIP_CONS* cons, /**< constraint */
1549 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1550 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1551 )
1552{
1553 SCIP_CONSDATA* consdata;
1554 SCIP_Real activity;
1555
1556 assert(scip != NULL);
1557 assert(cons != NULL);
1558
1559 consdata = SCIPconsGetData(cons);
1560 assert(consdata != NULL);
1561
1562 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1563 activity = SCIPexprGetEvalValue(consdata->expr);
1564
1565 /* consider constraint as violated if it is undefined in the current point */
1566 if( activity == SCIP_INVALID )
1567 {
1568 consdata->lhsviol = SCIPinfinity(scip);
1569 consdata->rhsviol = SCIPinfinity(scip);
1570 return SCIP_OKAY;
1571 }
1572
1573 /* compute violations */
1574 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1575 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1576
1577 return SCIP_OKAY;
1578}
1579
1580/** returns absolute violation of a constraint
1581 *
1582 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1583 */
1584static
1586 SCIP_CONS* cons /**< constraint */
1587 )
1588{
1589 SCIP_CONSDATA* consdata;
1590
1591 assert(cons != NULL);
1592
1593 consdata = SCIPconsGetData(cons);
1594 assert(consdata != NULL);
1595
1596 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1597}
1598
1599/** computes relative violation of a constraint
1600 *
1601 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1602 */
1603static
1605 SCIP* scip, /**< SCIP data structure */
1606 SCIP_CONS* cons, /**< constraint */
1607 SCIP_Real* viol, /**< buffer to store violation */
1608 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1609 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1610 )
1611{
1612 SCIP_CONSHDLR* conshdlr;
1613 SCIP_CONSHDLRDATA* conshdlrdata;
1614 SCIP_CONSDATA* consdata;
1615 SCIP_Real scale;
1616
1617 assert(cons != NULL);
1618 assert(viol != NULL);
1619
1620 conshdlr = SCIPconsGetHdlr(cons);
1621 assert(conshdlr != NULL);
1622
1623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1624 assert(conshdlrdata != NULL);
1625
1626 *viol = getConsAbsViolation(cons);
1627
1628 if( conshdlrdata->violscale == 'n' )
1629 return SCIP_OKAY;
1630
1631 if( SCIPisInfinity(scip, *viol) )
1632 return SCIP_OKAY;
1633
1634 consdata = SCIPconsGetData(cons);
1635 assert(consdata != NULL);
1636
1637 if( conshdlrdata->violscale == 'a' )
1638 {
1639 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1640
1641 /* consider value of side that is violated for scaling, too */
1642 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1643 {
1644 assert(!SCIPisInfinity(scip, -consdata->lhs));
1645 scale = REALABS(consdata->lhs);
1646 }
1647 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1648 {
1649 assert(!SCIPisInfinity(scip, consdata->rhs));
1650 scale = REALABS(consdata->rhs);
1651 }
1652
1653 *viol /= scale;
1654 return SCIP_OKAY;
1655 }
1656
1657 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1658 assert(conshdlrdata->violscale == 'g');
1659 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1660 {
1661 /* we need the varexprs to conveniently access the gradient */
1662 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1663
1664 /* update cached value of norm of gradient */
1665 consdata->gradnorm = 0.0;
1666
1667 /* compute gradient */
1668 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1669
1670 /* gradient evaluation error -> no scaling */
1671 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1672 {
1673 int i;
1674 for( i = 0; i < consdata->nvarexprs; ++i )
1675 {
1676 SCIP_Real deriv;
1677
1678 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1679 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1680 if( deriv == SCIP_INVALID )
1681 {
1682 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1683 consdata->gradnorm = 0.0;
1684 break;
1685 }
1686
1687 consdata->gradnorm += deriv*deriv;
1688 }
1689 }
1690 consdata->gradnorm = sqrt(consdata->gradnorm);
1691 consdata->gradnormsoltag = soltag;
1692 }
1693
1694 *viol /= MAX(1.0, consdata->gradnorm);
1695
1696 return SCIP_OKAY;
1697}
1698
1699/** returns whether constraint is currently violated
1700 *
1701 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1702 */
1703static
1705 SCIP* scip, /**< SCIP data structure */
1706 SCIP_CONS* cons /**< constraint */
1707 )
1708{
1709 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1710}
1711
1712/** checks for a linear variable that can be increased or decreased without harming feasibility */
1713static
1715 SCIP* scip, /**< SCIP data structure */
1716 SCIP_CONS* cons /**< constraint */
1717 )
1718{
1719 SCIP_CONSDATA* consdata;
1720 int poslock;
1721 int neglock;
1722 int i;
1723
1724 assert(cons != NULL);
1725
1726 consdata = SCIPconsGetData(cons);
1727 assert(consdata != NULL);
1728
1729 consdata->linvarincr = NULL;
1730 consdata->linvardecr = NULL;
1731 consdata->linvarincrcoef = 0.0;
1732 consdata->linvardecrcoef = 0.0;
1733
1734 /* root expression is not a sum -> no unlocked linear variable available */
1735 if( !SCIPisExprSum(scip, consdata->expr) )
1736 return;
1737
1738 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1739 {
1740 SCIP_EXPR* child;
1741
1742 child = SCIPexprGetChildren(consdata->expr)[i];
1743 assert(child != NULL);
1744
1745 /* check whether the child is a variable expression */
1746 if( SCIPisExprVar(scip, child) )
1747 {
1748 SCIP_VAR* var = SCIPgetVarExprVar(child);
1749 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1750
1751 if( coef > 0.0 )
1752 {
1753 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1754 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1755 }
1756 else
1757 {
1758 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1759 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1760 }
1762
1763 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1764 {
1765 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1766 * if we have already one candidate, then take the one where the loss in the objective function is less
1767 */
1768 if( (consdata->linvardecr == NULL) ||
1769 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1770 {
1771 consdata->linvardecr = var;
1772 consdata->linvardecrcoef = coef;
1773 }
1774 }
1775
1776 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1777 {
1778 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1779 * if we have already one candidate, then take the one where the loss in the objective function is less
1780 */
1781 if( (consdata->linvarincr == NULL) ||
1782 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1783 {
1784 consdata->linvarincr = var;
1785 consdata->linvarincrcoef = coef;
1786 }
1787 }
1788 }
1789 }
1790
1791 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1792 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1793
1794 if( consdata->linvarincr != NULL )
1795 {
1796 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1797 }
1798 if( consdata->linvardecr != NULL )
1799 {
1800 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1801 }
1802}
1803
1804/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1805 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1806 *
1807 * The method assumes that this is always possible and that not all constraints are feasible already.
1808 */
1809static
1811 SCIP* scip, /**< SCIP data structure */
1812 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1813 SCIP_CONS** conss, /**< constraints to process */
1814 int nconss, /**< number of constraints */
1815 SCIP_SOL* sol, /**< solution to process */
1816 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1817 )
1818{
1819 SCIP_CONSHDLRDATA* conshdlrdata;
1820 SCIP_SOL* newsol;
1821 int c;
1822
1823 assert(scip != NULL);
1824 assert(conshdlr != NULL);
1825 assert(conss != NULL || nconss == 0);
1826 assert(success != NULL);
1827
1828 *success = FALSE;
1829
1830 /* don't propose new solutions if not in presolve or solving */
1832 return SCIP_OKAY;
1833
1834 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1835 assert(conshdlrdata != NULL);
1836
1837 if( sol != NULL )
1838 {
1839 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1840 }
1841 else
1842 {
1843 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1844 }
1845 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1846 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1847 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1848
1849 for( c = 0; c < nconss; ++c )
1850 {
1851 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1852 SCIP_Real viol = 0.0;
1853 SCIP_Real delta;
1854 SCIP_Real gap;
1855
1856 assert(consdata != NULL);
1857
1858 /* get absolute violation and sign */
1859 if( consdata->lhsviol > SCIPfeastol(scip) )
1860 viol = consdata->lhsviol; /* lhs - activity */
1861 else if( consdata->rhsviol > SCIPfeastol(scip) )
1862 viol = -consdata->rhsviol; /* rhs - activity */
1863 else
1864 continue; /* constraint is satisfied */
1865
1866 if( consdata->linvarincr != NULL &&
1867 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1868 {
1869 SCIP_VAR* var = consdata->linvarincr;
1870
1871 /* compute how much we would like to increase var */
1872 delta = viol / consdata->linvarincrcoef;
1873 assert(delta > 0.0);
1874
1875 /* if var has an upper bound, may need to reduce delta */
1877 {
1878 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1879 delta = MIN(MAX(0.0, gap), delta);
1880 }
1881 if( SCIPisPositive(scip, delta) )
1882 {
1883 /* if variable is integral, round delta up so that it will still have an integer value */
1884 if( SCIPvarIsIntegral(var) )
1885 delta = SCIPceil(scip, delta);
1886
1887 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1888 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1889 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1890
1891 /* adjust constraint violation, if satisfied go on to next constraint */
1892 viol -= consdata->linvarincrcoef * delta;
1893 if( SCIPisZero(scip, viol) )
1894 continue;
1895 }
1896 }
1897
1898 assert(viol != 0.0);
1899 if( consdata->linvardecr != NULL &&
1900 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1901 {
1902 SCIP_VAR* var = consdata->linvardecr;
1903
1904 /* compute how much we would like to decrease var */
1905 delta = viol / consdata->linvardecrcoef;
1906 assert(delta < 0.0);
1907
1908 /* if var has a lower bound, may need to reduce delta */
1910 {
1911 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1912 delta = MAX(MIN(0.0, gap), delta);
1913 }
1914 if( SCIPisNegative(scip, delta) )
1915 {
1916 /* if variable is integral, round delta down so that it will still have an integer value */
1917 if( SCIPvarIsIntegral(var) )
1918 delta = SCIPfloor(scip, delta);
1919 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1920 /*lint --e{613} */
1921 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1922 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1923
1924 /* adjust constraint violation, if satisfied go on to next constraint */
1925 viol -= consdata->linvardecrcoef * delta;
1926 if( SCIPisZero(scip, viol) )
1927 continue;
1928 }
1929 }
1930
1931 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1932 break;
1933 }
1934
1935 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1936 * then pass it to the trysol heuristic
1937 */
1939 {
1940 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1941
1942 assert(conshdlrdata->trysolheur != NULL);
1943 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1944
1945 *success = TRUE;
1946 }
1947
1948 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1949
1950 return SCIP_OKAY;
1951}
1952
1953/** notify nonlinear handlers to add linearization in new solution that has been found
1954 *
1955 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1956 *
1957 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1958 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1959 * cut that is valid and supporting in the given solution.
1960 * For example, for convex constraints, we achieve this by linearizing.
1961 * For SOC, we also linearize, but on a a convex reformulation.
1962 *
1963 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1964 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1965 */
1966static
1968 SCIP* scip, /**< SCIP data structure */
1969 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1970 SCIP_CONS** conss, /**< constraints */
1971 int nconss, /**< number of constraints */
1972 SCIP_SOL* sol, /**< reference point where to estimate */
1973 SCIP_Bool solisbest /**< whether solution is best */
1974 )
1975{
1976 SCIP_CONSDATA* consdata;
1977 SCIP_Longint soltag;
1978 SCIP_EXPRITER* it;
1979 SCIP_EXPR* expr;
1980 int c, e;
1981
1982 assert(scip != NULL);
1983 assert(conshdlr != NULL);
1984 assert(conss != NULL || nconss == 0);
1985
1986 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1987
1988 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1989 * would be nice to recognize this and skip reevaluating
1990 */
1991 soltag = SCIPgetExprNewSoltag(scip);
1992
1996
1997 for( c = 0; c < nconss; ++c )
1998 {
1999 /* skip constraints that are not enabled or deleted or have separation disabled */
2000 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2001 continue;
2002 assert(SCIPconsIsActive(conss[c]));
2003
2004 consdata = SCIPconsGetData(conss[c]);
2005 assert(consdata != NULL);
2006
2007 ENFOLOG(
2008 {
2009 int i;
2010 SCIPinfoMessage(scip, enfologfile, " constraint ");
2011 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2012 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2013 for( i = 0; i < consdata->nvarexprs; ++i )
2014 {
2015 SCIP_VAR* var;
2016 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2017 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2019 }
2020 })
2021
2022 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2023 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2024
2025 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2026 {
2027 SCIP_EXPR_OWNERDATA* ownerdata;
2028
2029 ownerdata = SCIPexprGetOwnerData(expr);
2030 assert(ownerdata != NULL);
2031
2032 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2033 assert(SCIPexprGetEvalTag(expr) == soltag);
2035 if( ownerdata->auxvar != NULL )
2036 {
2037 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2038 }
2039
2040 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2041 for( e = 0; e < ownerdata->nenfos; ++e )
2042 {
2043 /* call sollinearize callback, if implemented by nlhdlr */
2044 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2045 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2046 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2047 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2048 }
2049 }
2050 }
2051
2052 SCIPfreeExpriter(&it);
2053
2054 return SCIP_OKAY;
2055}
2056
2057/** processes the event that a new primal solution has been found */
2058static
2059SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2060{
2061 SCIP_CONSHDLR* conshdlr;
2062 SCIP_CONSHDLRDATA* conshdlrdata;
2063 SCIP_SOL* sol;
2064
2065 assert(scip != NULL);
2066 assert(event != NULL);
2067 assert(eventdata != NULL);
2068 assert(eventhdlr != NULL);
2070
2071 conshdlr = (SCIP_CONSHDLR*)eventdata;
2072
2073 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2074 return SCIP_OKAY;
2075
2076 sol = SCIPeventGetSol(event);
2077 assert(sol != NULL);
2078
2079 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2080 assert(conshdlrdata != NULL);
2081
2082 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2083 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2084 * from the tree, but postprocessed via proposeFeasibleSolution
2085 */
2086 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2087 return SCIP_OKAY;
2088
2089 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2090
2092
2093 return SCIP_OKAY;
2094}
2095
2096/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2097 *
2098 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2099 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2100 *
2101 * Nothing will happen if SCIP is not in presolve or solve.
2102 */
2103static
2105 SCIP* scip, /**< SCIP data structure */
2106 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2107 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2108 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2109 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2110 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2111 )
2112{
2113 SCIP_VAR* var;
2114 SCIP_Bool tightenedlb;
2115 SCIP_Bool tightenedub;
2116 SCIP_Bool force;
2117
2118 assert(scip != NULL);
2119 assert(conshdlr != NULL);
2120 assert(expr != NULL);
2121 assert(cutoff != NULL);
2122
2123 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2125
2126 *cutoff = FALSE;
2127
2129 if( var == NULL )
2130 return SCIP_OKAY;
2131
2132 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2133 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2134
2135 /* try to tighten lower bound of (auxiliary) variable */
2136 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2137 if( tightenedlb )
2138 {
2139 if( ntightenings != NULL )
2140 ++*ntightenings;
2141 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2142 }
2143 if( *cutoff )
2144 {
2145 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2146 return SCIP_OKAY;
2147 }
2148
2149 /* try to tighten upper bound of (auxiliary) variable */
2150 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2151 if( tightenedub )
2152 {
2153 if( ntightenings != NULL )
2154 ++*ntightenings;
2155 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2156 }
2157 if( *cutoff )
2158 {
2159 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2160 return SCIP_OKAY;
2161 }
2162
2163 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2164 * that seems unnecessary and we could easily undo this here, e.g.,
2165 * if( tightenedlb ) expr->activity.inf = bounds.inf
2166 */
2167
2168 return SCIP_OKAY;
2169}
2170
2171/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2172 * and tries to tighten the bounds of the auxiliary variables accordingly
2173 */
2174static
2176 SCIP* scip, /**< SCIP data structure */
2177 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2178 SCIP_EXPR* rootexpr, /**< expression */
2179 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2180 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2181 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2182 )
2183{
2184 SCIP_EXPRITER* it;
2185 SCIP_EXPR* expr;
2186 SCIP_EXPR_OWNERDATA* ownerdata;
2187 SCIP_CONSHDLRDATA* conshdlrdata;
2188
2189 assert(scip != NULL);
2190 assert(rootexpr != NULL);
2191
2192 if( infeasible != NULL )
2193 *infeasible = FALSE;
2194 if( ntightenings != NULL )
2195 *ntightenings = 0;
2196
2197 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2198 assert(conshdlrdata != NULL);
2199
2200 /* if value is valid and empty, then we cannot improve, so do nothing */
2201 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2202 {
2203 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2204
2205 if( infeasible != NULL )
2206 *infeasible = TRUE;
2207
2208 /* just update tag to curboundstag */
2209 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2210
2211 return SCIP_OKAY;
2212 }
2213
2214 /* if value is up-to-date, then nothing to do */
2215 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2216 {
2217 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2218
2219 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2220
2221 return SCIP_OKAY;
2222 }
2223
2224 ownerdata = SCIPexprGetOwnerData(rootexpr);
2225 assert(ownerdata != NULL);
2226
2227 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2228 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2229 * during detect, we are in some in-between state where we may want to eval activity
2230 * on exprs that we did not notify about their activity usage
2231 */
2232 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2233 {
2234#ifdef DEBUG_PROP
2235 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2236#endif
2237 SCIPABORT();
2238 return SCIP_OKAY;
2239 }
2240
2244
2245 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2246 {
2247 switch( SCIPexpriterGetStageDFS(it) )
2248 {
2250 {
2251 /* skip child if it has been evaluated already */
2252 SCIP_EXPR* child;
2253
2254 child = SCIPexpriterGetChildExprDFS(it);
2255 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2256 {
2258 *infeasible = TRUE;
2259
2260 expr = SCIPexpriterSkipDFS(it);
2261 continue;
2262 }
2263
2264 break;
2265 }
2266
2268 {
2269 SCIP_INTERVAL activity;
2270
2271 /* we should not have entered this expression if its activity was already up to date */
2272 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2273
2274 ownerdata = SCIPexprGetOwnerData(expr);
2275 assert(ownerdata != NULL);
2276
2277 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2278 * so we can assume that the activity is up to date for all these variables
2279 * UNLESS we changed the method used to evaluate activity of variable expressions
2280 * or we currently use global bounds (varevents are catched for local bound changes only)
2281 */
2282 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2283 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2284 {
2285#ifndef NDEBUG
2286 SCIP_INTERVAL exprhdlrinterval;
2287
2288 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2289 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2290 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2291#endif
2292#ifdef DEBUG_PROP
2293 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2294#endif
2295 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2296
2297 break;
2298 }
2299
2300 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2301 {
2302 /* start with entire activity if current one is invalid */
2304 }
2306 {
2307 /* If already empty, then don't try to compute even better activity.
2308 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2309 * so an assert(infeasible == NULL || *infeasible) should work here.
2310 * However, after reporting a cutoff due to expr->activity being empty,
2311 * SCIP may wander to a different node and call propagation again.
2312 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2313 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2314 * we will still have expr->activity being empty, but will have forgotten
2315 * that we found infeasibility here before (!2221#note_134120).
2316 * Therefore we just set *infeasibility=TRUE here and stop.
2317 */
2318 if( infeasible != NULL )
2319 *infeasible = TRUE;
2320 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2321 break;
2322 }
2323 else
2324 {
2325 /* start with current activity, since it is valid */
2326 activity = SCIPexprGetActivity(expr);
2327 }
2328
2329 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2330 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2331 {
2332#ifdef DEBUG_PROP
2333 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2334#endif
2335 break;
2336 }
2337
2338#ifdef DEBUG_PROP
2339 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2340 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2341 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2342#endif
2343
2344 /* run interval eval of nonlinear handlers or expression handler */
2345 if( ownerdata->nenfos > 0 )
2346 {
2347 SCIP_NLHDLR* nlhdlr;
2348 SCIP_INTERVAL nlhdlrinterval;
2349 int e;
2350
2351 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2352 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2353 {
2354 /* skip nlhdlr if it does not want to participate in activity computation */
2355 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2356 continue;
2357
2358 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2359 assert(nlhdlr != NULL);
2360
2361 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2362 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2363 continue;
2364
2365 /* let nlhdlr evaluate current expression */
2366 nlhdlrinterval = activity;
2367 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2368 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2369#ifdef DEBUG_PROP
2370 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2371#endif
2372
2373 /* update activity by intersecting with computed activity */
2374 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2375#ifdef DEBUG_PROP
2376 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2377#endif
2378 }
2379 }
2380 else
2381 {
2382 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2383 SCIP_INTERVAL exprhdlrinterval = activity;
2384 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2385#ifdef DEBUG_PROP
2386 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2387#endif
2388
2389 /* update expr->activity by intersecting with computed activity */
2390 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2391#ifdef DEBUG_PROP
2392 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2393#endif
2394 }
2395
2396 /* if expression is integral, then we try to tighten the interval bounds a bit
2397 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2398 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2399 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2400 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2401 * (constants should be ok, too)
2402 */
2403 if( SCIPexprIsIntegral(expr) &&
2404 conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2405 {
2406 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2407 activity.inf = SCIPceil(scip, activity.inf);
2408 if( activity.sup < SCIP_INTERVAL_INFINITY )
2409 activity.sup = SCIPfloor(scip, activity.sup);
2410#ifdef DEBUG_PROP
2411 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2412#endif
2413 }
2414
2415 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2416 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2417 */
2418 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2419 {
2420 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2421 SCIPintervalSetEmpty(&activity);
2422 }
2423
2424 /* now finally store activity in expr */
2425 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2426
2428 {
2429 if( infeasible != NULL )
2430 *infeasible = TRUE;
2431 }
2432 else if( tightenauxvars && ownerdata->auxvar != NULL )
2433 {
2434 SCIP_Bool tighteninfeasible;
2435
2436 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2437 if( tighteninfeasible )
2438 {
2439 if( infeasible != NULL )
2440 *infeasible = TRUE;
2441 SCIPintervalSetEmpty(&activity);
2442 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2443 }
2444 }
2445
2446 break;
2447 }
2448
2449 default:
2450 /* you should never be here */
2451 SCIPerrorMessage("unexpected iterator stage\n");
2452 SCIPABORT();
2453 break;
2454 }
2455
2456 expr = SCIPexpriterGetNext(it);
2457 }
2458
2459 SCIPfreeExpriter(&it);
2460
2461 return SCIP_OKAY;
2462}
2463
2464/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2465 *
2466 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2467 *
2468 * If `subsetsufficient` is FALSE, then we require
2469 * - a change from an unbounded interval to a bounded one, or
2470 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2471 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2472 */
2473static
2475 SCIP* scip, /**< SCIP data structure */
2476 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2477 SCIP_INTERVAL newinterval, /**< new interval */
2478 SCIP_INTERVAL oldinterval /**< old interval */
2479 )
2480{
2481 assert(scip != NULL);
2484
2485 if( subsetsufficient )
2486 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2487 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2488
2489 /* check whether lower bound of interval becomes finite */
2490 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2491 return TRUE;
2492
2493 /* check whether upper bound of interval becomes finite */
2494 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2495 return TRUE;
2496
2497 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2498 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2499 return TRUE;
2500
2501 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2502 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2503 return TRUE;
2504
2505 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2506 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2507 return TRUE;
2508
2509 return FALSE;
2510}
2511
2512/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2513 *
2514 * The expression will be traversed in breadth first search by using this queue.
2515 *
2516 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2517 * forwardPropExpr() before calling this function.
2518 *
2519 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2520 */
2521static
2523 SCIP* scip, /**< SCIP data structure */
2524 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2525 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2526 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2527 )
2528{
2529 SCIP_CONSHDLRDATA* conshdlrdata;
2530 SCIP_EXPR* expr;
2531 SCIP_EXPR_OWNERDATA* ownerdata;
2532
2533 assert(infeasible != NULL);
2534 assert(ntightenings != NULL);
2535
2536 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2537 assert(conshdlrdata != NULL);
2538
2539 *ntightenings = 0;
2540
2541 /* main loop that calls reverse propagation for expressions on the queue
2542 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2543 */
2544 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2545 {
2546 SCIP_INTERVAL propbounds;
2547 int e;
2548
2549 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2550 assert(expr != NULL);
2551
2552 ownerdata = SCIPexprGetOwnerData(expr);
2553 assert(ownerdata != NULL);
2554
2555 assert(ownerdata->inpropqueue);
2556 /* mark that the expression is not in the queue anymore */
2557 ownerdata->inpropqueue = FALSE;
2558
2559 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2560 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2561 */
2562 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2563 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2564 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2565
2566 /* this intersects propbounds with activity and auxvar bounds
2567 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2568 * auxvar bounds separately, so disabling this for now
2569 */
2570#ifdef SCIP_DISABLED_CODE
2571 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2573 {
2574 *infeasible = TRUE;
2575 break;
2576 }
2577#else
2578 propbounds = ownerdata->propbounds;
2579#endif
2580
2581 if( ownerdata->nenfos > 0 )
2582 {
2583 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2584 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2585 {
2586 SCIP_NLHDLR* nlhdlr;
2587 int nreds;
2588
2589 /* skip nlhdlr if it does not want to participate in activity computation */
2590 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2591 continue;
2592
2593 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2594 assert(nlhdlr != NULL);
2595
2596 /* call the reverseprop of the nlhdlr */
2597#ifdef SCIP_DEBUG
2598 SCIPdebugMsg(scip, "call reverse propagation for ");
2599 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2600 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2601#endif
2602
2603 nreds = 0;
2604 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2605 assert(nreds >= 0);
2606 *ntightenings += nreds;
2607 }
2608 }
2610 {
2611 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2612 SCIP_INTERVAL* childrenbounds;
2613 int c;
2614
2615#ifdef SCIP_DEBUG
2616 SCIPdebugMsg(scip, "call reverse propagation for ");
2617 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2618 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2619#endif
2620
2621 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2622 * been initialized in detectNlhdlr yet (nenfos < 0)
2623 */
2624 assert(ownerdata->nenfos < 0);
2625
2626 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2627 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2628 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2629
2630 /* call the reverseprop of the exprhdlr */
2631 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2632
2633 if( !*infeasible )
2634 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2635 {
2636 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2637 }
2638
2639 SCIPfreeBufferArray(scip, &childrenbounds);
2640 }
2641 }
2642
2643 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2644 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2645 {
2646 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2647 assert(expr != NULL);
2648
2649 ownerdata = SCIPexprGetOwnerData(expr);
2650 assert(ownerdata != NULL);
2651
2652 /* mark that the expression is not in the queue anymore */
2653 ownerdata->inpropqueue = FALSE;
2654 }
2655
2656 return SCIP_OKAY;
2657}
2658
2659/** calls domain propagation for a given set of constraints
2660 *
2661 * The algorithm alternates calls of forward and reverse propagation.
2662 * Forward propagation ensures that activity of expressions is up to date.
2663 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2664 * [lhs,rhs] interval as starting point.
2665 *
2666 * The propagation algorithm works as follows:
2667 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2668 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2669 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2670 * provide tighter bounds
2671 * 3. apply reverse propagation to all collected expressions; don't explore
2672 * sub-expressions which have not changed since the beginning of the propagation loop
2673 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2674 *
2675 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2676 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2677 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2678 *
2679 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2680 * e.g., try less to propagate on convex constraints?
2681 */
2682static
2684 SCIP* scip, /**< SCIP data structure */
2685 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2686 SCIP_CONS** conss, /**< constraints to propagate */
2687 int nconss, /**< total number of constraints */
2688 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2689 SCIP_RESULT* result, /**< pointer to store the result */
2690 int* nchgbds /**< buffer to add the number of changed bounds */
2691 )
2692{
2693 SCIP_CONSHDLRDATA* conshdlrdata;
2694 SCIP_CONSDATA* consdata;
2695 SCIP_EXPR_OWNERDATA* ownerdata;
2697 SCIP_INTERVAL conssides;
2698 int ntightenings;
2699 int roundnr;
2700 SCIP_EXPRITER* revpropcollectit = NULL;
2701 int i;
2702
2703 assert(scip != NULL);
2704 assert(conshdlr != NULL);
2705 assert(conss != NULL);
2706 assert(nconss >= 0);
2707 assert(result != NULL);
2708 assert(nchgbds != NULL);
2709 assert(*nchgbds >= 0);
2710
2711 /* no constraints to propagate */
2712 if( nconss == 0 )
2713 {
2715 return SCIP_OKAY;
2716 }
2717
2718 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2719 assert(conshdlrdata != NULL);
2720#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2721 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2722#endif
2723 assert(!conshdlrdata->globalbounds);
2724
2726 roundnr = 0;
2727
2728 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2729 conshdlrdata->forceboundtightening = force;
2730
2731 /* invalidate all propbounds (probably not needed) */
2732 ++conshdlrdata->curpropboundstag;
2733
2734 /* create iterator that we will use if we need to look at all auxvars */
2735 if( conshdlrdata->propauxvars )
2736 {
2737 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2738 }
2739
2740 /* main propagation loop */
2741 do
2742 {
2743 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2744
2745 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2746
2747 /* apply forward propagation (update expression activities)
2748 * and add promising root expressions into queue for reversepropagation
2749 */
2750 for( i = 0; i < nconss; ++i )
2751 {
2752 consdata = SCIPconsGetData(conss[i]);
2753 assert(consdata != NULL);
2754
2755 /* skip deleted, non-active, or propagation-disabled constraints */
2756 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2757 continue;
2758
2759 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2760 * activity didn't change
2761 */
2762 if( consdata->ispropagated )
2763 continue;
2764
2765 /* update activities in expression */
2766 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2767 SCIPdebugPrintCons(scip, conss[i], NULL);
2768
2769 ntightenings = 0;
2770 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2772
2773 if( cutoff )
2774 {
2775 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2777 break;
2778 }
2779
2780 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2781
2782 /* 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 */
2783 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2784 {
2785 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2786 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2787 * so taking auxvar bounds is enough)
2788 */
2789 if( ownerdata->auxvar == NULL )
2790 {
2791 /* relax sides by SCIPepsilon() and handle infinite sides */
2792 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2793 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2794 SCIPintervalSetBounds(&conssides, lhs, rhs);
2795 }
2796 else
2797 {
2798 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2799 }
2800 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2801 }
2802 else
2803 {
2804 /* check whether bounds of any auxvar used in constraint provides a tightening
2805 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2806 * but skip exprs that have an auxvar, but do not participate in propagation
2807 */
2808 SCIP_EXPR* expr;
2809
2810 assert(revpropcollectit != NULL);
2811 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2812 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2813 {
2814 ownerdata = SCIPexprGetOwnerData(expr);
2815 assert(ownerdata != NULL);
2816
2817 if( ownerdata->auxvar == NULL )
2818 continue;
2819
2820 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2821 continue;
2822
2823 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2824 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2825 }
2826 }
2827
2828 if( cutoff )
2829 {
2830 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2832 break;
2833 }
2834
2835 assert(ntightenings >= 0);
2836 if( ntightenings > 0 )
2837 {
2838 *nchgbds += ntightenings;
2840 }
2841
2842 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2843 consdata->ispropagated = TRUE;
2844 }
2845
2846 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2847 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2848 assert(ntightenings >= 0);
2849 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2850
2851 if( cutoff )
2852 {
2853 SCIPdebugMsg(scip, " -> cutoff\n");
2855 break;
2856 }
2857
2858 if( ntightenings > 0 )
2859 {
2860 *nchgbds += ntightenings;
2862 }
2863 }
2864 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2865
2866 if( conshdlrdata->propauxvars )
2867 {
2868 SCIPfreeExpriter(&revpropcollectit);
2869 }
2870
2871 conshdlrdata->forceboundtightening = FALSE;
2872
2873 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2874 ++conshdlrdata->curpropboundstag;
2875
2876 return SCIP_OKAY;
2877}
2878
2879/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2880 *
2881 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2882 *
2883 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2884 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2885 */
2886static
2888 SCIP* scip, /**< SCIP data structure */
2889 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2890 SCIP_CONS** conss, /**< constraints to propagate */
2891 int nconss, /**< total number of constraints */
2892 SCIP_RESULT* result, /**< pointer to store the result */
2893 int* nchgbds /**< buffer to add the number of changed bounds */
2894 )
2895{
2896 SCIP_CONSDATA* consdata;
2897 SCIP_EXPRITER* it;
2898 SCIP_EXPR* expr;
2899 SCIP_EXPR_OWNERDATA* ownerdata;
2901 int ntightenings;
2902 int c;
2903 int e;
2904
2905 assert(scip != NULL);
2906 assert(conshdlr != NULL);
2907 assert(conss != NULL);
2908 assert(nconss >= 0);
2909 assert(result != NULL);
2910 assert(nchgbds != NULL);
2911 assert(*nchgbds >= 0);
2912
2913#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2914 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2915#endif
2916 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2917 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2918
2920
2923
2924 for( c = 0; c < nconss && !cutoff; ++c )
2925 {
2926 /* skip deleted, non-active, or propagation-disabled constraints */
2927 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2928 continue;
2929
2930 consdata = SCIPconsGetData(conss[c]);
2931 assert(consdata != NULL);
2932
2933 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2934 {
2935 ownerdata = SCIPexprGetOwnerData(expr);
2936 assert(ownerdata != NULL);
2937
2938 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2939 * this will propagate the current activity
2940 */
2941 for( e = 0; e < ownerdata->nenfos; ++e )
2942 {
2943 SCIP_NLHDLR* nlhdlr;
2944 assert(ownerdata->enfos[e] != NULL);
2945
2946 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2947 assert(nlhdlr != NULL);
2948 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2949 continue;
2950
2951 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2952 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2953 ntightenings = 0;
2954 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2955 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2956
2957 if( cutoff )
2958 {
2959 /* stop everything if we detected infeasibility */
2960 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2962 break;
2963 }
2964
2965 assert(ntightenings >= 0);
2966 if( ntightenings > 0 )
2967 {
2968 *nchgbds += ntightenings;
2970 }
2971 }
2972 }
2973 }
2974
2975 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2976 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2977 assert(ntightenings >= 0);
2978
2979 if( cutoff )
2980 {
2981 SCIPdebugMsg(scip, " -> cutoff\n");
2983 }
2984 else if( ntightenings > 0 )
2985 {
2986 *nchgbds += ntightenings;
2988 }
2989
2990 SCIPfreeExpriter(&it);
2991
2992 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2993 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2994
2995 return SCIP_OKAY;
2996}
2997
2998/** propagates variable locks through expression and adds locks to variables */
2999static
3001 SCIP* scip, /**< SCIP data structure */
3002 SCIP_EXPR* expr, /**< expression */
3003 int nlockspos, /**< number of positive locks */
3004 int nlocksneg /**< number of negative locks */
3005 )
3006{
3007 SCIP_EXPR_OWNERDATA* ownerdata;
3008 SCIP_EXPRITER* it;
3009 SCIP_EXPRITER_USERDATA ituserdata;
3010
3011 assert(expr != NULL);
3012
3013 /* if no locks, then nothing to propagate */
3014 if( nlockspos == 0 && nlocksneg == 0 )
3015 return SCIP_OKAY;
3016
3020 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3021
3022 /* store locks in root node */
3023 ituserdata.intvals[0] = nlockspos;
3024 ituserdata.intvals[1] = nlocksneg;
3025 SCIPexpriterSetCurrentUserData(it, ituserdata);
3026
3027 while( !SCIPexpriterIsEnd(it) )
3028 {
3029 /* collect locks */
3030 ituserdata = SCIPexpriterGetCurrentUserData(it);
3031 nlockspos = ituserdata.intvals[0];
3032 nlocksneg = ituserdata.intvals[1];
3033
3034 ownerdata = SCIPexprGetOwnerData(expr);
3035
3036 switch( SCIPexpriterGetStageDFS(it) )
3037 {
3039 {
3040 if( SCIPisExprVar(scip, expr) )
3041 {
3042 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3043 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3044 }
3045
3046 /* add locks to expression */
3047 ownerdata->nlockspos += nlockspos;
3048 ownerdata->nlocksneg += nlocksneg;
3049
3050 /* add monotonicity information if expression has been locked for the first time */
3051 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3053 {
3054 int i;
3055
3056 assert(ownerdata->monotonicity == NULL);
3057 assert(ownerdata->monotonicitysize == 0);
3058
3059 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3060 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3061
3062 /* store the monotonicity for each child */
3063 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3064 {
3065 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3066 }
3067 }
3068 break;
3069 }
3070
3072 {
3073 /* remove monotonicity information if expression has been unlocked */
3074 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3075 {
3076 assert(ownerdata->monotonicitysize > 0);
3077 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3078 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3079
3080 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3081 ownerdata->monotonicitysize = 0;
3082 }
3083 break;
3084 }
3085
3087 {
3088 SCIP_MONOTONE monotonicity;
3089
3090 /* get monotonicity of child */
3091 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3092 * SCIPcallExprMonotonicity
3093 */
3094 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3095
3096 /* compute resulting locks of the child expression */
3097 switch( monotonicity )
3098 {
3099 case SCIP_MONOTONE_INC:
3100 ituserdata.intvals[0] = nlockspos;
3101 ituserdata.intvals[1] = nlocksneg;
3102 break;
3103 case SCIP_MONOTONE_DEC:
3104 ituserdata.intvals[0] = nlocksneg;
3105 ituserdata.intvals[1] = nlockspos;
3106 break;
3108 ituserdata.intvals[0] = nlockspos + nlocksneg;
3109 ituserdata.intvals[1] = nlockspos + nlocksneg;
3110 break;
3112 ituserdata.intvals[0] = 0;
3113 ituserdata.intvals[1] = 0;
3114 break;
3115 }
3116 /* set locks in child expression */
3117 SCIPexpriterSetChildUserData(it, ituserdata);
3118
3119 break;
3120 }
3121
3122 default :
3123 /* you should never be here */
3124 SCIPABORT();
3125 break;
3126 }
3127
3128 expr = SCIPexpriterGetNext(it);
3129 }
3130
3131 SCIPfreeExpriter(&it);
3132
3133 return SCIP_OKAY;
3134}
3135
3136/** main function for adding locks to expressions and variables
3137 *
3138 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3139 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3140 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3141 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3142 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3143 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3144 * which implies that updating the monotonicity information during the next locking of this expression does not
3145 * break existing locks.
3146 *
3147 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3148 * locks from an expression and repropagating them after the structural changes have been applied.
3149 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3150 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3151 */
3152static
3154 SCIP* scip, /**< SCIP data structure */
3155 SCIP_CONS* cons, /**< nonlinear constraint */
3156 int nlockspos, /**< number of positive rounding locks */
3157 int nlocksneg /**< number of negative rounding locks */
3158 )
3159{
3160 SCIP_CONSDATA* consdata;
3161
3162 assert(cons != NULL);
3163
3164 if( nlockspos == 0 && nlocksneg == 0 )
3165 return SCIP_OKAY;
3166
3167 consdata = SCIPconsGetData(cons);
3168 assert(consdata != NULL);
3169
3170 /* no constraint sides -> nothing to lock */
3171 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3172 return SCIP_OKAY;
3173
3174 /* remember locks */
3175 consdata->nlockspos += nlockspos;
3176 consdata->nlocksneg += nlocksneg;
3177
3178 assert(consdata->nlockspos >= 0);
3179 assert(consdata->nlocksneg >= 0);
3180
3181 /* compute locks for lock propagation */
3182 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3183 {
3184 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg) );
3185 }
3186 else if( !SCIPisInfinity(scip, consdata->rhs) )
3187 {
3188 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg) );
3189 }
3190 else
3191 {
3192 assert(!SCIPisInfinity(scip, -consdata->lhs));
3193 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos) );
3194 }
3195
3196 return SCIP_OKAY;
3197}
3198
3199/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3200static
3202 SCIP* scip, /**< SCIP data structure */
3203 SCIP_CONS* cons /**< nonlinear constraint */
3204 )
3205{
3206 SCIP_CONSDATA* consdata;
3207
3208 assert(scip != NULL);
3209 assert(cons != NULL);
3210
3211 consdata = SCIPconsGetData(cons);
3212 assert(consdata != NULL);
3213 assert(consdata->expr != NULL);
3214
3215 if( consdata->nlrow != NULL )
3216 {
3217 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3218 }
3219
3220 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3221 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3222 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3223
3224 if( SCIPisExprSum(scip, consdata->expr) )
3225 {
3226 /* if root is a sum, then split into linear and nonlinear terms */
3227 SCIP_EXPR* nonlinpart;
3228 SCIP_EXPR* child;
3229 SCIP_Real* coefs;
3230 int i;
3231
3232 coefs = SCIPgetCoefsExprSum(consdata->expr);
3233
3234 /* constant term of sum */
3235 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3236
3237 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3238 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3239
3240 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3241 {
3242 child = SCIPexprGetChildren(consdata->expr)[i];
3243 if( SCIPisExprVar(scip, child) )
3244 {
3245 /* linear term */
3246 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3247 }
3248 else
3249 {
3250 /* nonlinear term */
3251 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3252 }
3253 }
3254
3255 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3256 {
3257 /* add expression to nlrow (this will make a copy) */
3258 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3259 }
3260 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3261 }
3262 else
3263 {
3264 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3265 }
3266
3267 return SCIP_OKAY;
3268}
3269
3270/** compares enfodata by enforcement priority of nonlinear handler
3271 *
3272 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3273 */
3274static
3276{
3277 SCIP_NLHDLR* h1;
3278 SCIP_NLHDLR* h2;
3279
3280 assert(elem1 != NULL);
3281 assert(elem2 != NULL);
3282
3283 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3284 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3285
3286 assert(h1 != NULL);
3287 assert(h2 != NULL);
3288
3291
3294
3295 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3296}
3297
3298/** install nlhdlrs in one expression */
3299static
3301 SCIP* scip, /**< SCIP data structure */
3302 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3303 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3304 )
3305{
3306 SCIP_EXPR_OWNERDATA* ownerdata;
3307 SCIP_CONSHDLRDATA* conshdlrdata;
3308 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3309 SCIP_NLHDLR_METHOD enforcemethods;
3310 SCIP_NLHDLR_METHOD enforcemethodsnew;
3311 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3312 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3313 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3314 int enfossize; /* allocated length of expr->enfos array */
3315 int h;
3316
3317 assert(expr != NULL);
3318
3319 ownerdata = SCIPexprGetOwnerData(expr);
3320 assert(ownerdata != NULL);
3321
3322 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3323 assert(conshdlrdata != NULL);
3324 assert(conshdlrdata->auxvarid >= 0);
3325 assert(!conshdlrdata->indetect);
3326
3327 /* there should be no enforcer yet and detection should not even have considered expr yet */
3328 assert(ownerdata->nenfos < 0);
3329 assert(ownerdata->enfos == NULL);
3330
3331 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3332 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3333 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3334 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3335 * - if no one uses activity, then do not need activity methods
3336 */
3337 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3338 if( ownerdata->nauxvaruses == 0 )
3339 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3340 else
3341 {
3342 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3343 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3344 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3345 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3346 }
3347 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3348 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3349
3350 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3351 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3352
3353 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3354 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3355
3356 ownerdata->nenfos = 0;
3357 enfossize = 2;
3358 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3359 conshdlrdata->indetect = TRUE;
3360
3361 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3362 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3363 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3364 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3365 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3366
3367 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3368 {
3369 SCIP_NLHDLR* nlhdlr;
3370
3371 nlhdlr = conshdlrdata->nlhdlrs[h];
3372 assert(nlhdlr != NULL);
3373
3374 /* skip disabled nlhdlrs */
3375 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3376 continue;
3377
3378 /* call detect routine of nlhdlr */
3379 nlhdlrexprdata = NULL;
3380 enforcemethodsnew = enforcemethods;
3381 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3382 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3383 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3384 /* coverity[var_deref_model] */
3385 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3386
3387 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3388 nlhdlrparticipating &= enforcemethodsallowed;
3389
3390 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3391 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3392
3393 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3394 * They are also cleaned up here to ensure that only the needed methods are claimed.
3395 */
3396 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3397
3398 /* nlhdlr needs to participate for the methods it is enforcing */
3399 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3400
3401 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3402 {
3403 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3404 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3405
3406 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3407 if( nlhdlrexprdata != NULL )
3408 {
3409 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3410 }
3411 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3412 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3413
3414 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3415
3416 continue;
3417 }
3418
3419 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3420 SCIPnlhdlrGetName(nlhdlr),
3421 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3422 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3423 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3424
3425 /* store nlhdlr and its data */
3426 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3427 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3428 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3429 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3430 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3431 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3432 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3433 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3434 ownerdata->nenfos++;
3435
3436 /* update enforcement flags */
3437 enforcemethods = enforcemethodsnew;
3438 }
3439
3440 conshdlrdata->indetect = FALSE;
3441
3442 /* stop if an enforcement method is missing but we are already in solving stage
3443 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3444 */
3445 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3446 {
3447 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3448 return SCIP_ERROR;
3449 }
3450
3451 assert(ownerdata->nenfos > 0);
3452
3453 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3454 if( ownerdata->nenfos > 1 )
3455 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3456
3457 /* resize enfos array to be nenfos long */
3458 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3459
3460 return SCIP_OKAY;
3461}
3462
3463/** detect nlhdlrs that can handle the expressions */
3464static
3466 SCIP* scip, /**< SCIP data structure */
3467 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3468 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3469 int nconss /**< total number of constraints */
3470 )
3471{
3472 SCIP_CONSHDLRDATA* conshdlrdata;
3473 SCIP_CONSDATA* consdata;
3474 SCIP_EXPR* expr;
3475 SCIP_EXPR_OWNERDATA* ownerdata;
3476 SCIP_EXPRITER* it;
3477 int i;
3478
3479 assert(conss != NULL || nconss == 0);
3480 assert(nconss >= 0);
3481 assert(SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVING && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3482
3483 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3484 assert(conshdlrdata != NULL);
3485
3488
3490 {
3491 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3492 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3493 */
3495 conshdlrdata->globalbounds = TRUE;
3496 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3497 }
3498
3499 for( i = 0; i < nconss; ++i )
3500 {
3501 assert(conss != NULL && conss[i] != NULL);
3502
3503 consdata = SCIPconsGetData(conss[i]);
3504 assert(consdata != NULL);
3505 assert(consdata->expr != NULL);
3506
3507 /* if a constraint is separated, we currently need it to be initial, too
3508 * this is because INITLP will create the auxiliary variables that are used for any separation
3509 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3510 */
3511 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3512
3513 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3514 assert(ownerdata != NULL);
3515
3516 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3517 * then we would normally skip to run DETECT again
3518 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3519 * thus, if expr is the root expression, we rerun DETECT
3520 */
3521 if( ownerdata->nenfos > 0 )
3522 {
3523 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3524 assert(ownerdata->nenfos < 0);
3525 }
3526
3527 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3528 * this way we can treat the root expression like any other expression when enforcing via separation
3529 * if constraint will be propagated, then register activity usage of root expression
3530 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3531 */
3532 conshdlrdata->indetect = TRUE;
3535 SCIPconsIsPropagated(conss[i]),
3536 FALSE, FALSE) );
3537 conshdlrdata->indetect = FALSE;
3538
3539 /* presolveSingleLockedVars() may need the activity of product expressions in a sum expr that is in the root expr of a nonlinear constraint with only one finite side
3540 * if this presolver may be run in the current presolve round (presoltiming=exhaustive could be added as additional criterion),
3541 * then we ensure that a routine will be present to compute this activity (SCIPregisterExprUsageNonlinear actually updates activity already)
3542 */
3543 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd'
3544 && (SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs)) && SCIPisExprSum(scip, consdata->expr) )
3545 {
3546 int c;
3547 for( c = 0; c < SCIPexprGetNChildren(consdata->expr); ++c )
3548 {
3549 expr = SCIPexprGetChildren(consdata->expr)[c];
3550 if( SCIPisExprProduct(scip, expr) )
3551 {
3553 }
3554 }
3555 }
3556
3557 /* compute integrality information for all subexpressions */
3558 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3559
3560 /* run detectNlhdlr on all expr where required */
3561 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3562 {
3563 ownerdata = SCIPexprGetOwnerData(expr);
3564 assert(ownerdata != NULL);
3565
3566 /* skip exprs that we already looked at */
3567 if( ownerdata->nenfos >= 0 )
3568 continue;
3569
3570 /* if there is use of the auxvar, then someone requires that
3571 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3572 * thus, we need to find nlhdlrs that separate or estimate
3573 * if there is use of the activity, then there is someone requiring that
3574 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3575 * thus, we need to find nlhdlrs that do interval-evaluation
3576 */
3577 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3578 {
3579 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3580
3581 assert(ownerdata->nenfos >= 0);
3582 }
3583 else
3584 {
3585 /* remember that we looked at this expression during detectNlhdlrs
3586 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3587 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3588 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3589 */
3590 ownerdata->nenfos = 0;
3591 }
3592 }
3593
3594 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3595 if( SCIPconsIsPropagated(conss[i]) )
3596 consdata->ispropagated = FALSE;
3597 }
3598
3600 {
3601 /* ensure that the local bounds are used again when reevaluating the expressions later;
3602 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3603 */
3605 conshdlrdata->globalbounds = FALSE;
3606 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3607 }
3608 else
3609 {
3610 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3612 }
3613
3614 SCIPfreeExpriter(&it);
3615
3616 return SCIP_OKAY;
3617}
3618
3619/** initializes (pre)solving data of constraints
3620 *
3621 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3622 * not be modified.
3623 * In particular, this function
3624 * - runs the detection method of nlhldrs
3625 * - looks for unlocked linear variables
3626 * - checks curvature (if not in presolve)
3627 * - creates and add row to NLP (if not in presolve)
3628 *
3629 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3630 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3631 */
3632static
3634 SCIP* scip, /**< SCIP data structure */
3635 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3636 SCIP_CONS** conss, /**< constraints */
3637 int nconss /**< number of constraints */
3638 )
3639{
3640 int c;
3641
3642 for( c = 0; c < nconss; ++c )
3643 {
3644 /* check for a linear variable that can be increase or decreased without harming feasibility */
3645 findUnlockedLinearVar(scip, conss[c]);
3646
3648 {
3649 SCIP_CONSDATA* consdata;
3650 SCIP_Bool success = FALSE;
3651
3652 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3653 assert(consdata != NULL);
3654 assert(consdata->expr != NULL);
3655
3656 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3657 {
3658 /* call the curvature detection algorithm of the convex nonlinear handler
3659 * Check only for those curvature that may result in a convex inequality, i.e.,
3660 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3661 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3662 */
3663 if( !SCIPisInfinity(scip, -consdata->lhs) )
3664 {
3665 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3666 if( success )
3667 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3668 }
3669 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3670 {
3671 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3672 if( success )
3673 consdata->curv = SCIP_EXPRCURV_CONVEX;
3674 }
3675 }
3676 else
3677 {
3678 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3679 {
3680 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3681 consdata->curv = SCIP_EXPRCURV_LINEAR;
3682 }
3683 else
3684 {
3685 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3686 }
3687 }
3688 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3689
3690 /* add nlrow representation to NLP, if NLP had been constructed */
3692 {
3693 if( consdata->nlrow == NULL )
3694 {
3695 SCIP_CALL( createNlRow(scip, conss[c]) );
3696 assert(consdata->nlrow != NULL);
3697 }
3698 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3699 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3700 }
3701 }
3702 }
3703
3704 /* register non linear handlers */
3705 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3706
3707 return SCIP_OKAY;
3708}
3709
3710/** deinitializes (pre)solving data of constraints
3711 *
3712 * This removes the initialization data created in initSolve().
3713 *
3714 * This function can be called in presolve and solve.
3715 *
3716 * TODO At the moment, it should not be called for a constraint if there are other constraints
3717 * that use the same expressions but still require their nlhdlr.
3718 * We should probably only decrement the auxvar and activity usage for the root expr and then
3719 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3720 */
3721static
3723 SCIP* scip, /**< SCIP data structure */
3724 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3725 SCIP_CONS** conss, /**< constraints */
3726 int nconss /**< number of constraints */
3727 )
3728{
3729 SCIP_EXPRITER* it;
3730 SCIP_EXPR* expr;
3731 SCIP_CONSDATA* consdata;
3732 SCIP_Bool rootactivityvalid;
3733 int c;
3734
3738
3739 /* call deinitialization callbacks of expression and nonlinear handlers
3740 * free nonlinear handlers information from expressions
3741 * remove auxiliary variables and nactivityuses counts from expressions
3742 */
3743 for( c = 0; c < nconss; ++c )
3744 {
3745 assert(conss != NULL);
3746 assert(conss[c] != NULL);
3747
3748 consdata = SCIPconsGetData(conss[c]);
3749 assert(consdata != NULL);
3750 assert(consdata->expr != NULL);
3751
3752 /* check and remember whether activity in root is valid */
3753 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3754
3755 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3756 {
3757 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3758
3759 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3760 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3761
3762 /* remove quadratic info */
3764
3765 if( rootactivityvalid )
3766 {
3767 /* ensure activity is valid if consdata->expr activity is valid
3768 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3769 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3770 * so this childs activity would be invalid, which can generate confusion
3771 */
3773 }
3774 }
3775
3776 if( consdata->nlrow != NULL )
3777 {
3778 /* remove row from NLP, if still in solving
3779 * if we are in exitsolve, the whole NLP will be freed anyway
3780 */
3782 {
3783 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3784 }
3785
3786 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3787 }
3788
3789 /* forget about linear variables that can be increased or decreased without harming feasibility */
3790 consdata->linvardecr = NULL;
3791 consdata->linvarincr = NULL;
3792
3793 /* forget about curvature */
3794 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3795 }
3796
3797 SCIPfreeExpriter(&it);
3798
3799 return SCIP_OKAY;
3800}
3801
3802/** helper method to decide whether a given expression is product of at least two binary variables */
3803static
3805 SCIP* scip, /**< SCIP data structure */
3806 SCIP_EXPR* expr /**< expression */
3807 )
3808{
3809 int i;
3810
3811 assert(expr != NULL);
3812
3813 /* check whether the expression is a product */
3814 if( !SCIPisExprProduct(scip, expr) )
3815 return FALSE;
3816
3817 /* don't consider products with a coefficient != 1 and products with a single child
3818 * simplification will take care of this expression later
3819 */
3820 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3821 return FALSE;
3822
3823 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3824 {
3825 SCIP_EXPR* child;
3826 SCIP_VAR* var;
3827
3828 child = SCIPexprGetChildren(expr)[i];
3829 assert(child != NULL);
3830
3831 if( !SCIPisExprVar(scip, child) )
3832 return FALSE;
3833
3834 var = SCIPgetVarExprVar(child);
3835
3836 /* check whether variable is binary, in any feasible solution
3837 * we need to forbid weakly implied binary variables because cons_and wouldn't ensure that the
3838 * product condition holds in any feasible solution (i.e., when vars may not be at bounds) in this case,
3839 * which would lead to accepting solutions that are not feasible in the original (non-reformulated) cons
3840 */
3842 return FALSE;
3843 }
3844
3845 return TRUE;
3846}
3847
3848/** helper method to collect all bilinear binary product terms */
3849static
3851 SCIP* scip, /**< SCIP data structure */
3852 SCIP_EXPR* sumexpr, /**< sum expression */
3853 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3854 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3855 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3856 int* nterms /**< pointer to store the total number of bilinear binary terms */
3857 )
3858{
3859 int i;
3860
3861 assert(sumexpr != NULL);
3862 assert(SCIPisExprSum(scip, sumexpr));
3863 assert(xs != NULL);
3864 assert(ys != NULL);
3865 assert(childidxs != NULL);
3866 assert(nterms != NULL);
3867
3868 *nterms = 0;
3869
3870 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3871 {
3872 SCIP_EXPR* child;
3873
3874 child = SCIPexprGetChildren(sumexpr)[i];
3875 assert(child != NULL);
3876
3877 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3878 {
3881
3882 assert(x != NULL);
3883 assert(y != NULL);
3884
3885 if( x != y )
3886 {
3887 xs[*nterms] = x;
3888 ys[*nterms] = y;
3889 childidxs[*nterms] = i;
3890 ++(*nterms);
3891 }
3892 }
3893 }
3894
3895 return SCIP_OKAY;
3896}
3897
3898/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3899static
3901 SCIP* scip, /**< SCIP data structure */
3902 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3903 SCIP_CONS* cons, /**< constraint */
3904 SCIP_VAR* facvar, /**< variable that has been factorized */
3905 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3906 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3907 int nvars, /**< total number of variables in sum_j c_ij x_j */
3908 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3909 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3910 )
3911{
3912 SCIP_VAR* auxvar;
3913 SCIP_CONS* newcons;
3914 SCIP_Real minact = 0.0;
3915 SCIP_Real maxact = 0.0;
3917 char name [SCIP_MAXSTRLEN];
3918 int i;
3919
3920 assert(facvar != NULL);
3921 assert(vars != NULL);
3922 assert(nvars > 1);
3923 assert(newexpr != NULL);
3924
3925 /* compute minimum and maximum activity of sum_j c_ij x_j */
3926 /* 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 */
3927 for( i = 0; i < nvars; ++i )
3928 {
3929 minact += MIN(coefs[i], 0.0);
3930 maxact += MAX(coefs[i], 0.0);
3933
3934 if( impltype != SCIP_IMPLINTTYPE_NONE && !SCIPisIntegral(scip, coefs[i]) )
3935 impltype = SCIP_IMPLINTTYPE_NONE;
3936 }
3937 assert(minact <= maxact);
3938
3939 /* create and add auxiliary variable */
3940 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3941 SCIP_CALL( SCIPcreateVarImpl(scip, &auxvar, name, minact, maxact, 0.0, SCIP_VARTYPE_CONTINUOUS, impltype,
3942 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
3943 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3944
3945#ifdef WITH_DEBUG_SOLUTION
3946 if( SCIPdebugIsMainscip(scip) )
3947 {
3948 SCIP_Real debugsolval; /* value of auxvar in debug solution */
3949 SCIP_Real val;
3950
3951 /* compute value of new variable in debug solution */
3952 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
3953 debugsolval = 0.0;
3954 for( i = 0; i < nvars; ++i )
3955 {
3957 debugsolval += coefs[i] * val;
3958 }
3959
3960 /* now multiply by x_i (facvar) */
3961 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
3962 debugsolval *= val;
3963
3964 /* store debug solution value of auxiliary variable */
3965 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
3966 }
3967#endif
3968
3969 /* create and add z - maxact x <= 0 */
3970 if( !SCIPisZero(scip, maxact) )
3971 {
3972 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3973 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3974 SCIP_CALL( SCIPaddCons(scip, newcons) );
3975 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3976 if( naddconss != NULL )
3977 ++(*naddconss);
3978 }
3979
3980 /* create and add 0 <= z - minact x */
3981 if( !SCIPisZero(scip, minact) )
3982 {
3983 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3984 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3985 SCIP_CALL( SCIPaddCons(scip, newcons) );
3986 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3987 if( naddconss != NULL )
3988 ++(*naddconss);
3989 }
3990
3991 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3993 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3994 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3995 if( !SCIPisZero(scip, minact) )
3996 {
3997 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3998 }
3999 SCIP_CALL( SCIPaddCons(scip, newcons) );
4000 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4001 if( naddconss != NULL )
4002 ++(*naddconss);
4003
4004 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4005 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4006 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4007 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4008 if( !SCIPisZero(scip, maxact) )
4009 {
4010 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4011 }
4012 SCIP_CALL( SCIPaddCons(scip, newcons) );
4013 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4014 if( naddconss != NULL )
4015 ++(*naddconss);
4016
4017 /* create variable expression */
4018 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4019
4020 /* release auxvar */
4021 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4022
4023 return SCIP_OKAY;
4024}
4025
4026/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4027static
4029 SCIP* scip, /**< SCIP data structure */
4030 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4031 SCIP_CONS* cons, /**< constraint */
4032 SCIP_EXPR* sumexpr, /**< expression */
4033 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4034 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4035 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4036 )
4037{
4038 SCIP_EXPR** exprs = NULL;
4039 SCIP_VAR** tmpvars = NULL;
4040 SCIP_VAR** vars = NULL;
4041 SCIP_VAR** xs = NULL;
4042 SCIP_VAR** ys = NULL;
4043 SCIP_Real* exprcoefs = NULL;
4044 SCIP_Real* tmpcoefs = NULL;
4045 SCIP_Real* sumcoefs;
4046 SCIP_Bool* isused = NULL;
4047 int* childidxs = NULL;
4048 int* count = NULL;
4049 int nchildren;
4050 int nexprs = 0;
4051 int nterms;
4052 int nvars;
4053 int ntotalvars;
4054 int i;
4055
4056 assert(sumexpr != NULL);
4057 assert(minterms > 1);
4058 assert(newexpr != NULL);
4059
4060 *newexpr = NULL;
4061
4062 /* check whether sumexpr is indeed a sum */
4063 if( !SCIPisExprSum(scip, sumexpr) )
4064 return SCIP_OKAY;
4065
4066 nchildren = SCIPexprGetNChildren(sumexpr);
4067 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4069 ntotalvars = SCIPgetNTotalVars(scip);
4070
4071 /* check whether there are enough terms available */
4072 if( nchildren < minterms )
4073 return SCIP_OKAY;
4074
4075 /* allocate memory */
4076 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4077 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4078 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4079
4080 /* collect all bilinear binary product terms */
4081 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4082
4083 /* check whether there are enough terms available */
4084 if( nterms < minterms )
4085 goto TERMINATE;
4086
4087 /* store how often each variable appears in a bilinear binary product */
4089 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4090 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4091
4092 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4093 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4096
4097 for( i = 0; i < nterms; ++i )
4098 {
4099 int xidx;
4100 int yidx;
4101
4102 assert(xs[i] != NULL);
4103 assert(ys[i] != NULL);
4104
4105 xidx = SCIPvarGetIndex(xs[i]);
4106 assert(xidx < ntotalvars);
4107 yidx = SCIPvarGetIndex(ys[i]);
4108 assert(yidx < ntotalvars);
4109
4110 ++count[xidx];
4111 ++count[yidx];
4112
4113 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4114 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4115 }
4116
4117 /* sort variables; don't change order of count array because it depends on problem indices */
4118 {
4119 int* tmpcount;
4120
4121 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4122 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4123 SCIPfreeBufferArray(scip, &tmpcount);
4124 }
4125
4126 for( i = 0; i < nvars; ++i )
4127 {
4128 SCIP_VAR* facvar = vars[i];
4129 int ntmpvars = 0;
4130 int j;
4131
4132 /* skip candidate if there are not enough terms left */
4133 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4134 continue;
4135
4136 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4137
4138 /* collect variables for x_i * sum_j c_ij x_j */
4139 for( j = 0; j < nterms; ++j )
4140 {
4141 int childidx = childidxs[j];
4142 assert(childidx >= 0 && childidx < nchildren);
4143
4144 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4145 {
4146 SCIP_Real coef;
4147 int xidx;
4148 int yidx;
4149
4150 coef = sumcoefs[childidx];
4151 assert(coef != 0.0);
4152
4153 /* collect corresponding variable */
4154 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4155 tmpcoefs[ntmpvars] = coef;
4156 ++ntmpvars;
4157
4158 /* update counters */
4159 xidx = SCIPvarGetIndex(xs[j]);
4160 assert(xidx < ntotalvars);
4161 yidx = SCIPvarGetIndex(ys[j]);
4162 assert(yidx < ntotalvars);
4163 --count[xidx];
4164 --count[yidx];
4165 assert(count[xidx] >= 0);
4166 assert(count[yidx] >= 0);
4167
4168 /* mark term to be used */
4169 isused[childidx] = TRUE;
4170 }
4171 }
4172 assert(ntmpvars >= minterms);
4173 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4174 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4175
4176 /* create required constraints and store the generated expression */
4177 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4178 exprcoefs[nexprs] = 1.0;
4179 ++nexprs;
4180 }
4181
4182 /* factorization was only successful if at least one expression has been generated */
4183 if( nexprs > 0 )
4184 {
4185 int nexprsold = nexprs;
4186
4187 /* add all children of the sum that have not been used */
4188 for( i = 0; i < nchildren; ++i )
4189 {
4190 if( !isused[i] )
4191 {
4192 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4193 exprcoefs[nexprs] = sumcoefs[i];
4194 ++nexprs;
4195 }
4196 }
4197
4198 /* create a new sum expression */
4199 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4200
4201 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4202 for( i = 0; i < nexprsold; ++i )
4203 {
4204 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4205 }
4206 }
4207
4208TERMINATE:
4209 /* free memory */
4210 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4211 SCIPfreeBufferArrayNull(scip, &tmpvars);
4212 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4215 SCIPfreeBufferArrayNull(scip, &isused);
4217 SCIPfreeBufferArray(scip, &childidxs);
4220
4221 return SCIP_OKAY;
4222}
4223
4224/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4225static
4227 SCIP* scip, /**< SCIP data structure */
4228 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4229 SCIP_EXPR* prodexpr, /**< product expression */
4230 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4231 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4232 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4233 )
4234{
4235 SCIP_VAR** vars;
4236 SCIP_CONS* cons;
4237 SCIP_Real* coefs;
4238 SCIP_VAR* w;
4239 char* name;
4240 int nchildren;
4241 int i;
4242
4243 assert(conshdlr != NULL);
4244 assert(prodexpr != NULL);
4245 assert(SCIPisExprProduct(scip, prodexpr));
4246 assert(newexpr != NULL);
4247
4248 nchildren = SCIPexprGetNChildren(prodexpr);
4249 assert(nchildren >= 2);
4250
4251 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4252 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4253 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4254 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4255
4256 /* prepare the names of the variable and the constraints */
4257 /* coverity[secure_coding] */
4258 strcpy(name, "binreform");
4259 for( i = 0; i < nchildren; ++i )
4260 {
4262 coefs[i] = 1.0;
4263 assert(vars[i] != NULL);
4264 (void) strcat(name, "_");
4265 (void) strcat(name, SCIPvarGetName(vars[i]));
4266
4268 }
4269
4270 /* create and add variable */
4271 SCIP_CALL( SCIPcreateVarImpl(scip, &w, name, 0.0, 1.0, 0.0,
4273 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
4275 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4276
4277#ifdef WITH_DEBUG_SOLUTION
4278 if( SCIPdebugIsMainscip(scip) )
4279 {
4280 SCIP_Real debugsolval; /* value of auxvar in debug solution */
4281 SCIP_Real val;
4282
4283 /* compute value of new variable in debug solution (\prod_i vars[i]) */
4284 debugsolval = 1.0;
4285 for( i = 0; i < nchildren; ++i )
4286 {
4288 debugsolval *= val;
4289 }
4290
4291 /* store debug solution value of auxiliary variable */
4292 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
4293 }
4294#endif
4295
4296 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4297 if( nchildren == 2 && !empathy4and )
4298 {
4299 SCIP_VAR* x = vars[0];
4300 SCIP_VAR* y = vars[1];
4301
4302 assert(x != NULL);
4303 assert(y != NULL);
4304 assert(x != y);
4305
4306 /* create and add x - w >= 0 */
4307 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4308 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4309 SCIP_CALL( SCIPaddCons(scip, cons) );
4310 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4311
4312 /* create and add y - w >= 0 */
4313 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4314 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4315 SCIP_CALL( SCIPaddCons(scip, cons) );
4316 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4317
4318 /* create and add x + y - w <= 1 */
4319 vars[2] = w;
4320 coefs[2] = -1.0;
4321 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4322 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4323 SCIP_CALL( SCIPaddCons(scip, cons) );
4324 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4325
4326 /* update number of added constraints */
4327 if( naddconss != NULL )
4328 *naddconss += 3;
4329 }
4330 else
4331 {
4332 /* create, add, and release AND constraint */
4333 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4334 SCIP_CALL( SCIPaddCons(scip, cons) );
4335 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4336 SCIPdebugMsg(scip, " create AND constraint\n");
4337
4338 /* update number of added constraints */
4339 if( naddconss != NULL )
4340 *naddconss += 1;
4341 }
4342
4343 /* create variable expression */
4344 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4345
4346 /* release created variable */
4348
4349 /* free memory */
4350 SCIPfreeBufferArray(scip, &name);
4351 SCIPfreeBufferArray(scip, &coefs);
4353
4354 return SCIP_OKAY;
4355}
4356
4357/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4358static
4360 SCIP* scip, /**< SCIP data structure */
4361 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4362 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4363 SCIP_EXPR* prodexpr, /**< product expression */
4364 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4365 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4366 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4367 )
4368{
4369 SCIP_CONSHDLRDATA* conshdlrdata;
4370 int nchildren;
4371
4372 assert(prodexpr != NULL);
4373 assert(newexpr != NULL);
4374
4375 *newexpr = NULL;
4376
4377 /* only consider products of binary variables */
4378 if( !isBinaryProduct(scip, prodexpr) )
4379 return SCIP_OKAY;
4380
4381 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4382 assert(conshdlrdata != NULL);
4383 nchildren = SCIPexprGetNChildren(prodexpr);
4384 assert(nchildren >= 2);
4385
4386 /* check whether there is already an expression that represents the product */
4387 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4388 {
4389 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4390 assert(*newexpr != NULL);
4391
4392 /* capture expression */
4393 SCIPcaptureExpr(*newexpr);
4394 }
4395 else
4396 {
4397 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4398
4399 if( nchildren == 2 )
4400 {
4401 SCIP_CLIQUE** xcliques;
4402 SCIP_VAR* x;
4403 SCIP_VAR* y;
4404 SCIP_Bool found_clique = FALSE;
4405 int c;
4406
4407 /* get variables from the product expression */
4408 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4409 assert(x != NULL);
4410 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4411 assert(y != NULL);
4412 assert(x != y);
4413
4414 /* first try to find a clique containing both variables */
4415 xcliques = SCIPvarGetCliques(x, TRUE);
4416
4417 /* look in cliques containing x */
4418 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4419 {
4420 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4421 {
4422 /* create zero value expression */
4423 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4424
4425 if( nchgcoefs != NULL )
4426 *nchgcoefs += 1;
4427
4428 found_clique = TRUE;
4429 break;
4430 }
4431
4432 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4433 {
4434 /* create variable expression for x */
4435 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4436
4437 if( nchgcoefs != NULL )
4438 *nchgcoefs += 2;
4439
4440 found_clique = TRUE;
4441 break;
4442 }
4443 }
4444
4445 if( !found_clique )
4446 {
4447 xcliques = SCIPvarGetCliques(x, FALSE);
4448
4449 /* look in cliques containing complement of x */
4450 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4451 {
4452 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4453 {
4454 /* create variable expression for y */
4455 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4456
4457 if( nchgcoefs != NULL )
4458 *nchgcoefs += 1;
4459
4460 found_clique = TRUE;
4461 break;
4462 }
4463
4464 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4465 {
4466 /* create sum expression */
4467 SCIP_EXPR* sum_children[2];
4468 SCIP_Real sum_coefs[2];
4469 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4470 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4471 sum_coefs[0] = 1.0;
4472 sum_coefs[1] = 1.0;
4473 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4474
4475 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4476 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4477
4478 if( nchgcoefs != NULL )
4479 *nchgcoefs += 3;
4480
4481 found_clique = TRUE;
4482 break;
4483 }
4484 }
4485 }
4486
4487 /* if the variables are not in a clique, do standard linearization */
4488 if( !found_clique )
4489 {
4490 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4491 }
4492 }
4493 else
4494 {
4495 /* linearize binary product using an AND constraint because nchildren > 2 */
4496 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4497 }
4498
4499 /* hash variable expression */
4500 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4501 }
4502
4503 return SCIP_OKAY;
4504}
4505
4506/** helper function to replace binary products in a given constraint */
4507static
4509 SCIP* scip, /**< SCIP data structure */
4510 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4511 SCIP_CONS* cons, /**< constraint */
4512 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4513 SCIP_EXPRITER* it, /**< expression iterator */
4514 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4515 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4516 )
4517{
4518 SCIP_CONSHDLRDATA* conshdlrdata;
4519 SCIP_CONSDATA* consdata;
4520 SCIP_EXPR* expr;
4521
4522 assert(conshdlr != NULL);
4523 assert(cons != NULL);
4524 assert(exprmap != NULL);
4525 assert(it != NULL);
4526
4527 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4528 assert(conshdlrdata != NULL);
4529
4530 consdata = SCIPconsGetData(cons);
4531 assert(consdata != NULL);
4532 assert(consdata->expr != NULL);
4533
4534 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4535
4536 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4537 {
4538 SCIP_EXPR* newexpr = NULL;
4539 SCIP_EXPR* childexpr;
4540 int childexpridx;
4541
4542 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4543 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4544 childexpr = SCIPexpriterGetChildExprDFS(it);
4545 assert(childexpr != NULL);
4546
4547 /* try to factorize variables in a sum expression that contains several products of binary variables */
4548 if( conshdlrdata->reformbinprodsfac > 1 )
4549 {
4550 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4551 }
4552
4553 /* try to create an expression that represents a product of binary variables */
4554 if( newexpr == NULL )
4555 {
4556 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4557 }
4558
4559 if( newexpr != NULL )
4560 {
4561 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4562
4563 /* replace product expression */
4564 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4565
4566 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4567 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4568
4569 /* mark the constraint to not be simplified anymore */
4570 consdata->issimplified = FALSE;
4571 }
4572 }
4573
4574 return SCIP_OKAY;
4575}
4576
4577/** reformulates products of binary variables during presolving in the following way:
4578 *
4579 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4580 * 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}:
4581 * \f[
4582 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4583 * \f]
4584 *
4585 * 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$.
4586 * These cliques allow for a better reformulation. There are four cases:
4587 *
4588 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4589 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4590 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4591 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4592 *
4593 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4594 *
4595 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4596 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4597 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4598 * Such a lower sum is reformulated with only one extra variable w_i:
4599 * \f{align}{
4600 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4601 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4602 * \text{minact}\, x_i & \leq w_i, \\
4603 * w_i &\leq \text{maxact}\, x_i, \\
4604 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4605 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4606 * \f}
4607 * 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
4608 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4609 * of terms are prioritized.
4610 */
4611static
4613 SCIP* scip, /**< SCIP data structure */
4614 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4615 SCIP_CONS** conss, /**< constraints */
4616 int nconss, /**< total number of constraints */
4617 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4618 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4619 )
4620{
4621 SCIP_CONSHDLRDATA* conshdlrdata;
4622 SCIP_HASHMAP* exprmap;
4623 SCIP_EXPRITER* it;
4624 int c;
4625
4626 assert(conshdlr != NULL);
4627
4628 /* no nonlinear constraints or binary variables -> skip */
4629 if( nconss == 0 || SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip) == 0 )
4630 return SCIP_OKAY;
4631 assert(conss != NULL);
4632
4633 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4634 assert(conshdlrdata != NULL);
4635
4636 /* create expression hash map */
4638
4639 /* create expression iterator */
4643
4644 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4645
4646 for( c = 0; c < nconss; ++c )
4647 {
4648 SCIP_CONSDATA* consdata;
4649 SCIP_EXPR* newexpr = NULL;
4650
4651 assert(conss[c] != NULL);
4652
4653 consdata = SCIPconsGetData(conss[c]);
4654 assert(consdata != NULL);
4655
4656 /* try to reformulate the root expression */
4657 if( conshdlrdata->reformbinprodsfac > 1 )
4658 {
4659 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4660 }
4661
4662 /* release the root node if another expression has been found */
4663 if( newexpr != NULL )
4664 {
4665 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4666 consdata->expr = newexpr;
4667
4668 /* mark constraint to be not simplified anymore */
4669 consdata->issimplified = FALSE;
4670 }
4671
4672 /* replace each product of binary variables separately */
4673 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4674 }
4675
4676 /* free memory */
4677 SCIPhashmapFree(&exprmap);
4678 SCIPfreeExpriter(&it);
4679
4680 return SCIP_OKAY;
4681}
4682
4683/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4684 *
4685 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4686 * Then scale by -1 if
4687 * - \f$n_+ < n_-\f$, or
4688 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4689 */
4690static
4692 SCIP* scip, /**< SCIP data structure */
4693 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4694 SCIP_CONS* cons, /**< nonlinear constraint */
4695 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4696 )
4697{
4698 SCIP_CONSDATA* consdata;
4699 int i;
4700
4701 assert(cons != NULL);
4702
4703 consdata = SCIPconsGetData(cons);
4704 assert(consdata != NULL);
4705
4706 if( SCIPisExprSum(scip, consdata->expr) )
4707 {
4708 SCIP_Real* coefs;
4709 SCIP_Real constant;
4710 int nchildren;
4711 int counter = 0;
4712
4713 coefs = SCIPgetCoefsExprSum(consdata->expr);
4714 constant = SCIPgetConstantExprSum(consdata->expr);
4715 nchildren = SCIPexprGetNChildren(consdata->expr);
4716
4717 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4718 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4719 {
4720 SCIP_EXPR* expr;
4721 expr = consdata->expr;
4722
4723 consdata->expr = SCIPexprGetChildren(expr)[0];
4724 assert(!SCIPisExprSum(scip, consdata->expr));
4725
4726 SCIPcaptureExpr(consdata->expr);
4727
4728 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4729 consdata->lhs = -consdata->lhs;
4730 consdata->rhs = -consdata->rhs;
4731
4732 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4733 *changed = TRUE;
4734 return SCIP_OKAY;
4735 }
4736
4737 /* compute n_+ - n_i */
4738 for( i = 0; i < nchildren; ++i )
4739 counter += coefs[i] > 0 ? 1 : -1;
4740
4741 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4742 {
4743 SCIP_EXPR* expr;
4744 SCIP_Real* newcoefs;
4745
4746 /* allocate memory */
4747 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4748
4749 for( i = 0; i < nchildren; ++i )
4750 newcoefs[i] = -coefs[i];
4751
4752 /* create a new sum expression */
4753 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4754
4755 /* replace expression in constraint data and scale sides */
4756 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4757 consdata->expr = expr;
4758 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4759 consdata->lhs = -consdata->lhs;
4760 consdata->rhs = -consdata->rhs;
4761
4762 /* free memory */
4763 SCIPfreeBufferArray(scip, &newcoefs);
4764
4765 *changed = TRUE;
4766 }
4767 }
4768
4769 return SCIP_OKAY;
4770}
4771
4772/** forbid multiaggrations of variables that appear nonlinear in constraints */
4773static
4775 SCIP* scip, /**< SCIP data structure */
4776 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4777 SCIP_CONS** conss, /**< constraints */
4778 int nconss /**< number of constraints */
4779 )
4780{
4781 SCIP_EXPRITER* it;
4782 SCIP_CONSDATA* consdata;
4783 SCIP_EXPR* expr;
4784 int c;
4785
4786 assert(scip != NULL);
4787 assert(conshdlr != NULL);
4788
4789 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4790 return SCIP_OKAY;
4791
4794
4795 for( c = 0; c < nconss; ++c )
4796 {
4797 consdata = SCIPconsGetData(conss[c]);
4798 assert(consdata != NULL);
4799
4800 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4801 * i.e., skip children of sum that are variables
4802 */
4803 if( SCIPisExprSum(scip, consdata->expr) )
4804 {
4805 int i;
4806 SCIP_EXPR* child;
4807 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4808 {
4809 child = SCIPexprGetChildren(consdata->expr)[i];
4810
4811 /* skip variable expression, as they correspond to a linear term */
4812 if( SCIPisExprVar(scip, child) )
4813 continue;
4814
4815 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4816 if( SCIPisExprVar(scip, expr) )
4817 {
4819 }
4820 }
4821 }
4822 else
4823 {
4824 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4825 if( SCIPisExprVar(scip, expr) )
4826 {
4828 }
4829 }
4830 }
4831
4832 SCIPfreeExpriter(&it);
4833
4834 return SCIP_OKAY;
4835}
4836
4837/** simplifies expressions and replaces common subexpressions for a set of constraints
4838 * @todo put the constant to the constraint sides
4839 */
4840static
4842 SCIP* scip, /**< SCIP data structure */
4843 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4844 SCIP_CONS** conss, /**< constraints */
4845 int nconss, /**< total number of constraints */
4846 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4847 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4848 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4849 int* naddconss, /**< counter to add number of added constraints, or NULL */
4850 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4851 )
4852{
4853 SCIP_CONSHDLRDATA* conshdlrdata;
4854 SCIP_CONSDATA* consdata;
4855 int* nlockspos;
4856 int* nlocksneg;
4857 SCIP_Bool havechange;
4858 int i;
4859
4860 assert(scip != NULL);
4861 assert(conshdlr != NULL);
4862 assert(conss != NULL);
4863 assert(nconss > 0);
4864 assert(infeasible != NULL);
4865
4866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4867 assert(conshdlrdata != NULL);
4868
4869 /* update number of canonicalize calls */
4870 ++(conshdlrdata->ncanonicalizecalls);
4871
4872 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4873
4874 *infeasible = FALSE;
4875
4876 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4877 havechange = conshdlrdata->ncanonicalizecalls == 1;
4878
4879 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4880 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4881
4882 /* allocate memory for storing locks of each constraint */
4883 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4884 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4885
4886 /* unlock all constraints */
4887 for( i = 0; i < nconss; ++i )
4888 {
4889 assert(conss[i] != NULL);
4890
4891 consdata = SCIPconsGetData(conss[i]);
4892 assert(consdata != NULL);
4893
4894 /* remember locks */
4895 nlockspos[i] = consdata->nlockspos;
4896 nlocksneg[i] = consdata->nlocksneg;
4897
4898 /* remove locks */
4899 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4900 assert(consdata->nlockspos == 0);
4901 assert(consdata->nlocksneg == 0);
4902 }
4903
4904#ifndef NDEBUG
4905 /* check whether all locks of each expression have been removed */
4906 for( i = 0; i < nconss; ++i )
4907 {
4908 SCIP_EXPR* expr;
4909 SCIP_EXPRITER* it;
4910
4912
4913 consdata = SCIPconsGetData(conss[i]);
4914 assert(consdata != NULL);
4915
4917 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4918 {
4919 assert(expr != NULL);
4920 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4921 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4922 }
4923 SCIPfreeExpriter(&it);
4924 }
4925#endif
4926
4927 /* reformulate products of binary variables */
4928 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4929 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4930 {
4931 int tmpnaddconss = 0;
4932 int tmpnchgcoefs = 0;
4933
4934 /* call this function before simplification because expressions might not be simplified after reformulating
4935 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4936 */
4937 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4938
4939 /* update counters */
4940 if( naddconss != NULL )
4941 *naddconss += tmpnaddconss;
4942 if( nchgcoefs != NULL )
4943 *nchgcoefs += tmpnchgcoefs;
4944
4945 /* check whether at least one expression has changed */
4946 if( tmpnaddconss + tmpnchgcoefs > 0 )
4947 havechange = TRUE;
4948 }
4949
4950 for( i = 0; i < nconss; ++i )
4951 {
4952 consdata = SCIPconsGetData(conss[i]);
4953 assert(consdata != NULL);
4954
4955 /* call simplify for each expression */
4956 if( !consdata->issimplified && consdata->expr != NULL )
4957 {
4958 SCIP_EXPR* simplified;
4959 SCIP_Bool changed;
4960
4961 changed = FALSE;
4962 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4963 consdata->issimplified = TRUE;
4964
4965 if( changed )
4966 havechange = TRUE;
4967
4968 /* 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").
4969 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4970 */
4971 if( simplified != consdata->expr )
4972 {
4973 assert(changed);
4974
4975 /* release old expression */
4976 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4977
4978 /* store simplified expression */
4979 consdata->expr = simplified;
4980 }
4981 else
4982 {
4983 /* The simplify captures simplified in any case, also if nothing has changed.
4984 * Therefore, we have to release it here.
4985 */
4986 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4987 }
4988
4989 if( *infeasible )
4990 break;
4991
4992 /* scale constraint sides */
4993 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4994
4995 if( changed )
4996 havechange = TRUE;
4997
4998 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4999 if( SCIPisExprValue(scip, consdata->expr) )
5000 {
5001 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5002 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5003 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5004 {
5005 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5006 SCIPdebugPrintCons(scip, conss[i], NULL);
5007 *infeasible = TRUE;
5008 break;
5009 }
5010 else
5011 {
5012 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5013 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5014 if( ndelconss != NULL )
5015 ++*ndelconss;
5016 havechange = TRUE;
5017 }
5018 }
5019 }
5020 }
5021
5022 /* replace common subexpressions */
5023 if( havechange && !*infeasible )
5024 {
5025 SCIP_CONS** consssorted;
5026 SCIP_EXPR** rootexprs;
5027 SCIP_Bool replacedroot;
5028
5029 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5030 for( i = 0; i < nconss; ++i )
5031 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5032
5033 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5034
5035 /* update pointer to root expr in constraints, if any has changed
5036 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5037 */
5038 if( replacedroot )
5039 for( i = 0; i < nconss; ++i )
5040 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5041
5042 SCIPfreeBufferArray(scip, &rootexprs);
5043
5044 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5045 * been changed after simplification; now we completely recollect all variable expression and variable events
5046 */
5047
5048 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5049 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5050 */
5051 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5052 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5053
5054 for( i = nconss-1; i >= 0; --i )
5055 {
5056 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5057 if( SCIPconsIsDeleted(consssorted[i]) )
5058 continue;
5059
5060 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5061 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5062 }
5063 for( i = 0; i < nconss; ++i )
5064 {
5065 if( SCIPconsIsDeleted(consssorted[i]) )
5066 continue;
5067
5068 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5069 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5070 }
5071
5072 SCIPfreeBufferArray(scip, &consssorted);
5073
5074 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5075 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5076 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5077 */
5078 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5079 }
5080
5081 /* restore locks */
5082 for( i = 0; i < nconss; ++i )
5083 {
5084 if( SCIPconsIsDeleted(conss[i]) )
5085 continue;
5086
5087 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5088 }
5089
5090 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5091 * TODO can we skip this in presoltiming fast?
5092 */
5093 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5094 {
5095 /* reset one of the number of detections counter to count only current presolving round */
5096 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5097 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5098
5099 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5100 }
5101
5102 /* free allocated memory */
5103 SCIPfreeBufferArray(scip, &nlocksneg);
5104 SCIPfreeBufferArray(scip, &nlockspos);
5105
5106 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5107
5108 return SCIP_OKAY;
5109}
5110
5111/** merges constraints that have the same root expression */
5112static
5114 SCIP* scip, /**< SCIP data structure */
5115 SCIP_CONS** conss, /**< constraints to process */
5116 int nconss, /**< number of constraints */
5117 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5118 )
5119{
5120 SCIP_HASHMAP* expr2cons;
5121 SCIP_Bool* updatelocks;
5122 int* nlockspos;
5123 int* nlocksneg;
5124 int c;
5125
5126 assert(success != NULL);
5127
5128 *success = FALSE;
5129
5130 /* not enough constraints available */
5131 if( nconss <= 1 )
5132 return SCIP_OKAY;
5133
5134 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5135 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5136 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5137 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5138
5139 for( c = 0; c < nconss; ++c )
5140 {
5141 SCIP_CONSDATA* consdata;
5142
5143 /* ignore deleted constraints */
5144 if( SCIPconsIsDeleted(conss[c]) )
5145 continue;
5146
5147 consdata = SCIPconsGetData(conss[c]);
5148 assert(consdata != NULL);
5149
5150 /* add expression to the hash map if not seen so far */
5151 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5152 {
5153 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5154 }
5155 else
5156 {
5157 SCIP_CONSDATA* imgconsdata;
5158 int idx;
5159
5160 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5161 assert(idx >= 0 && idx < nconss);
5162
5163 imgconsdata = SCIPconsGetData(conss[idx]);
5164 assert(imgconsdata != NULL);
5165 assert(imgconsdata->expr == consdata->expr);
5166
5167 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5168 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5169
5170 /* check whether locks need to be updated */
5171 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5172 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5173 {
5174 nlockspos[idx] = imgconsdata->nlockspos;
5175 nlocksneg[idx] = imgconsdata->nlocksneg;
5176 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5177 updatelocks[idx] = TRUE;
5178 }
5179
5180 /* update constraint sides */
5181 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5182 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5183
5184 /* delete constraint */
5185 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5186 *success = TRUE;
5187 }
5188 }
5189
5190 /* restore locks of updated constraints */
5191 if( *success )
5192 {
5193 for( c = 0; c < nconss; ++c )
5194 {
5195 if( updatelocks[c] )
5196 {
5197 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5198 }
5199 }
5200 }
5201
5202 /* free memory */
5203 SCIPfreeBufferArray(scip, &nlocksneg);
5204 SCIPfreeBufferArray(scip, &nlockspos);
5205 SCIPfreeBufferArray(scip, &updatelocks);
5206 SCIPhashmapFree(&expr2cons);
5207
5208 return SCIP_OKAY;
5209}
5210
5211/** interval evaluation of variables as used in redundancy check
5212 *
5213 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5214 */
5215static
5216SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5217{ /*lint --e{715}*/
5218 SCIP_CONSHDLRDATA* conshdlrdata;
5219 SCIP_INTERVAL interval;
5220 SCIP_Real lb;
5221 SCIP_Real ub;
5222
5223 assert(scip != NULL);
5224 assert(var != NULL);
5225
5226 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5227 assert(conshdlrdata != NULL);
5228
5229 if( conshdlrdata->globalbounds )
5230 {
5231 lb = SCIPvarGetLbGlobal(var);
5232 ub = SCIPvarGetUbGlobal(var);
5233 }
5234 else
5235 {
5236 lb = SCIPvarGetLbLocal(var);
5237 ub = SCIPvarGetUbLocal(var);
5238 }
5239 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5240
5241 /* relax variable bounds, if there are bounds and variable is not fixed
5242 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5243 */
5244 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5245 {
5246 if( !SCIPisInfinity(scip, -lb) )
5247 lb -= SCIPfeastol(scip);
5248
5249 if( !SCIPisInfinity(scip, ub) )
5250 ub += SCIPfeastol(scip);
5251 }
5252
5253 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5256 assert(lb <= ub);
5257
5258 SCIPintervalSetBounds(&interval, lb, ub);
5259
5260 return interval;
5261}
5262
5263/** removes constraints that are always feasible or very simple
5264 *
5265 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5266 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5267 * might violate variable bounds by up to feastol, too.
5268 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5269 *
5270 * Also removes constraints of the form lhs &le; variable &le; rhs.
5271 *
5272 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5273 *
5274 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5275 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5276 * would appear as if the constraint is redundant.
5277 */
5278static
5280 SCIP* scip, /**< SCIP data structure */
5281 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5282 SCIP_CONS** conss, /**< constraints to propagate */
5283 int nconss, /**< total number of constraints */
5284 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5285 int* ndelconss, /**< buffer to add the number of deleted constraints */
5286 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5287 )
5288{
5289 SCIP_CONSHDLRDATA* conshdlrdata;
5290 SCIP_CONSDATA* consdata;
5291 SCIP_INTERVAL activity;
5292 SCIP_INTERVAL sides;
5293 int i;
5294
5295 assert(scip != NULL);
5296 assert(conshdlr != NULL);
5297 assert(conss != NULL);
5298 assert(nconss >= 0);
5299 assert(cutoff != NULL);
5300 assert(ndelconss != NULL);
5301 assert(nchgbds != NULL);
5302
5303 /* no constraints to check */
5304 if( nconss == 0 )
5305 return SCIP_OKAY;
5306
5307 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5308 assert(conshdlrdata != NULL);
5309
5310 /* increase curboundstag and set lastvaractivitymethodchange
5311 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5312 * for the redundancy check differently than for domain propagation
5313 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5314 */
5315 ++conshdlrdata->curboundstag;
5316 assert(conshdlrdata->curboundstag > 0);
5317 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5318 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5319 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5320
5321 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5322
5323 *cutoff = FALSE;
5324 for( i = 0; i < nconss; ++i )
5325 {
5326 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5327 continue;
5328
5329 consdata = SCIPconsGetData(conss[i]);
5330 assert(consdata != NULL);
5331
5332 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5333 if( SCIPisExprValue(scip, consdata->expr) )
5334 {
5335 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5336
5337 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5338 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5339 {
5340 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5341 *cutoff = TRUE;
5342
5343 goto TERMINATE;
5344 }
5345
5346 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5347
5348 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5349 ++*ndelconss;
5350
5351 continue;
5352 }
5353
5354 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5355 if( SCIPisExprVar(scip, consdata->expr) )
5356 {
5357 SCIP_VAR* var;
5358 SCIP_Bool tightened;
5359
5360 var = SCIPgetVarExprVar(consdata->expr);
5361 assert(var != NULL);
5362
5363 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);
5364
5365 /* ensure that variable bounds are within constraint sides */
5366 if( !SCIPisInfinity(scip, -consdata->lhs) )
5367 {
5368 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5369
5370 if( tightened )
5371 ++*nchgbds;
5372
5373 if( *cutoff )
5374 goto TERMINATE;
5375 }
5376
5377 if( !SCIPisInfinity(scip, consdata->rhs) )
5378 {
5379 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5380
5381 if( tightened )
5382 ++*nchgbds;
5383
5384 if( *cutoff )
5385 goto TERMINATE;
5386 }
5387
5388 /* delete the (now) redundant constraint locally */
5389 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5390 ++*ndelconss;
5391
5392 continue;
5393 }
5394
5395 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5396 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5397 * variable bounds by up to feastol
5398 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5399 */
5400 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5401 SCIPdebugPrintCons(scip, conss[i], NULL);
5402
5403 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5405
5406 /* it is unlikely that we detect infeasibility by doing forward propagation */
5407 if( *cutoff )
5408 {
5409 SCIPdebugMsg(scip, " -> cutoff\n");
5410 goto TERMINATE;
5411 }
5412
5413 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5414 activity = SCIPexprGetActivity(consdata->expr);
5415
5416 /* relax sides by feastol
5417 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5418 */
5419 SCIPintervalSetBounds(&sides,
5420 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5421 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5422
5423 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5424 {
5425 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5426
5427 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5428 ++*ndelconss;
5429
5430 continue;
5431 }
5432
5433 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5434 }
5435
5436TERMINATE:
5437 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5438 ++conshdlrdata->curboundstag;
5439 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5440 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5441 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5442
5443 return SCIP_OKAY;
5444}
5445
5446/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5447static
5449 SCIP* scip, /**< SCIP data structure */
5450 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5451 SCIP_CONS* cons, /**< source constraint to try to convert */
5452 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5453 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5454 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5455 )
5456{
5457 SCIP_CONSHDLRDATA* conshdlrdata;
5458 SCIP_CONSDATA* consdata;
5459 SCIP_CONS** upgdconss;
5460 int upgdconsssize;
5461 int nupgdconss_;
5462 int i;
5463
5464 assert(scip != NULL);
5465 assert(conshdlr != NULL);
5466 assert(cons != NULL);
5468 assert(upgraded != NULL);
5469 assert(nupgdconss != NULL);
5470 assert(naddconss != NULL);
5471
5472 *upgraded = FALSE;
5473
5474 nupgdconss_ = 0;
5475
5476 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5477 assert(conshdlrdata != NULL);
5478
5479 /* if there are no upgrade methods, we can stop */
5480 if( conshdlrdata->nconsupgrades == 0 )
5481 return SCIP_OKAY;
5482
5483 upgdconsssize = 2;
5484 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5485
5486 /* call the upgrading methods */
5487 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5489
5490 consdata = SCIPconsGetData(cons);
5491 assert(consdata != NULL);
5492
5493 /* try all upgrading methods in priority order in case the upgrading step is enabled */
5494 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5495 {
5496 if( !conshdlrdata->consupgrades[i]->active )
5497 continue;
5498
5499 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5500
5501 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5502
5503 while( nupgdconss_ < 0 )
5504 {
5505 /* upgrade function requires more memory: resize upgdconss and call again */
5506 assert(-nupgdconss_ > upgdconsssize);
5507 upgdconsssize = -nupgdconss_;
5508 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5509
5510 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5511
5512 assert(nupgdconss_ != 0);
5513 }
5514
5515 if( nupgdconss_ > 0 )
5516 {
5517 /* got upgrade */
5518 int j;
5519
5520 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5521
5522 /* add the upgraded constraints to the problem and forget them */
5523 for( j = 0; j < nupgdconss_; ++j )
5524 {
5525 SCIPdebugMsgPrint(scip, "\t");
5526 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5527
5528 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5529 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5530 }
5531
5532 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5533 *nupgdconss += 1;
5534 *naddconss += nupgdconss_ - 1;
5535 *upgraded = TRUE;
5536
5537 /* delete upgraded constraint */
5538 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5539 SCIP_CALL( SCIPdelCons(scip, cons) );
5540
5541 break;
5542 }
5543 }
5544
5545 SCIPfreeBufferArray(scip, &upgdconss);
5546
5547 return SCIP_OKAY;
5548}
5549
5550/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5551 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5552 * variable bounds, and is not binary
5553 */
5554static
5556 SCIP* scip, /**< SCIP data structure */
5557 SCIP_EXPR* expr /**< variable expression */
5558 )
5559{
5560 SCIP_VAR* var;
5561 SCIP_EXPR_OWNERDATA* ownerdata;
5562
5563 assert(SCIPisExprVar(scip, expr));
5564
5565 var = SCIPgetVarExprVar(expr);
5566 assert(var != NULL);
5567
5568 ownerdata = SCIPexprGetOwnerData(expr);
5569 assert(ownerdata != NULL);
5570
5571 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5572 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5573 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5577}
5578
5579/** removes all variable expressions that are contained in a given expression from a hash map */
5580static
5582 SCIP* scip, /**< SCIP data structure */
5583 SCIP_EXPR* expr, /**< expression */
5584 SCIP_EXPRITER* it, /**< expression iterator */
5585 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5586 )
5587{
5588 SCIP_EXPR* e;
5589
5590 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5591 {
5592 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5593 {
5594 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5595 }
5596 }
5597
5598 return SCIP_OKAY;
5599}
5600
5601/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5602 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5603 *
5604 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5605 * Otherwise, a bound disjunction constraint is added.
5606 *
5607 * @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 (done in prop_dualfix?)
5608 */
5609static
5611 SCIP* scip, /**< SCIP data structure */
5612 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5613 SCIP_CONS* cons, /**< nonlinear constraint */
5614 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5615 int* naddconss, /**< pointer to store the total number of added constraints */
5616 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5617 )
5618{
5619 SCIP_CONSHDLRDATA* conshdlrdata;
5620 SCIP_CONSDATA* consdata;
5621 SCIP_EXPR** singlelocked;
5622 SCIP_HASHMAP* exprcands;
5623 SCIP_Bool hasbounddisj;
5624 SCIP_Bool haslhs;
5625 SCIP_Bool hasrhs;
5626 int nsinglelocked = 0;
5627 int i;
5628
5629 assert(conshdlr != NULL);
5630 assert(cons != NULL);
5631 assert(nchgvartypes != NULL);
5632 assert(naddconss != NULL);
5633 assert(infeasible != NULL);
5634
5635 *nchgvartypes = 0;
5636 *naddconss = 0;
5637 *infeasible = FALSE;
5638
5639 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5640 assert(conshdlrdata != NULL);
5641 consdata = SCIPconsGetData(cons);
5642 assert(consdata != NULL);
5643
5644 /* only consider constraints with one finite side */
5645 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5646 return SCIP_OKAY;
5647
5648 /* only consider sum expressions */
5649 if( !SCIPisExprSum(scip, consdata->expr) )
5650 return SCIP_OKAY;
5651
5652 /* remember which side is finite */
5653 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5654 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5655
5656 /* allocate memory */
5657 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5658 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5659
5660 /* check all variable expressions for single locked variables */
5661 for( i = 0; i < consdata->nvarexprs; ++i )
5662 {
5663 assert(consdata->varexprs[i] != NULL);
5664
5665 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5666 {
5667 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5668 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5669 }
5670 }
5671 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5672
5673 if( nsinglelocked > 0 )
5674 {
5675 SCIP_EXPR** children;
5676 SCIP_EXPRITER* it;
5677 int nchildren;
5678
5679 children = SCIPexprGetChildren(consdata->expr);
5680 nchildren = SCIPexprGetNChildren(consdata->expr);
5681
5682 /* create iterator */
5686
5687 for( i = 0; i < nchildren; ++i )
5688 {
5689 SCIP_EXPR* child;
5690 SCIP_Real coef;
5691
5692 child = children[i];
5693 assert(child != NULL);
5694 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5695
5696 /* ignore linear terms */
5697 if( SCIPisExprVar(scip, child) )
5698 continue;
5699
5700 /* consider products coef * prod_j f_j(x)
5701 * - if f_j(x) is a single variable, ignore it
5702 * - if f_j(x) = x^(2k), then keep it if product is concave when fixing all other factor;
5703 * since x^(2k) >= 0, it suffices to check that the activity of the whole product is non-negative if haslhs or non-positive if hasrhs
5704 * - remove all other variable expressions from exprcand
5705 */
5706 if( SCIPisExprProduct(scip, child) )
5707 {
5708 int j;
5709 SCIP_INTERVAL productactivity;
5710 SCIP_Bool keepevenpower;
5711
5712 /* activity has been ensured to be uptodate (or at least still valid) by
5713 * call to SCIPregisterExprUsageNonlinear() in detectNlhdlrs() in canonicalize
5714 */
5715 productactivity = SCIPexprGetActivity(child);
5716
5717 /* check whether variables in even-powered factor terms can be restricted to bounds (as in SCIPisExprPower() below) */
5718 keepevenpower = (haslhs && productactivity.inf >= 0.0) || (hasrhs && productactivity.sup <= 0.0);
5719
5720 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5721 {
5722 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5723 assert(grandchild != NULL);
5724
5725 /* if grandchild is x^(2k), then do not remove x from exprcands */
5726 if( keepevenpower && SCIPisExprPower(scip, grandchild) && SCIPisExprVar(scip, SCIPexprGetChildren(grandchild)[0]) )
5727 {
5728 SCIP_Real exponent = SCIPgetExponentExprPow(grandchild);
5729
5730 if( exponent > 1.0 && fmod(exponent, 2.0) == 0.0 )
5731 continue;
5732 }
5733
5734 if( !SCIPisExprVar(scip, grandchild) )
5735 {
5736 /* mark all variable expressions that are contained in the expression */
5737 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5738 }
5739 }
5740 }
5741 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5742 * for an integer k >= 1
5743 */
5744 else if( SCIPisExprPower(scip, child) )
5745 {
5746 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5747 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5749
5750 /* check for even integral exponent */
5751 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5752
5753 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5754 {
5755 /* mark all variable expressions that are contained in the expression */
5756 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5757 }
5758 }
5759 /* all other cases cannot be handled */
5760 else
5761 {
5762 /* mark all variable expressions that are contained in the expression */
5763 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5764 }
5765 }
5766
5767 /* free expression iterator */
5768 SCIPfreeExpriter(&it);
5769 }
5770
5771 /* check whether the bound disjunction constraint handler is available */
5772 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5773
5774 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5775 for( i = 0; i < nsinglelocked; ++i )
5776 {
5777 /* only consider expressions that are still contained in the exprcands map */
5778 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5779 {
5780 SCIP_CONS* newcons;
5781 SCIP_VAR* vars[2];
5782 SCIP_BOUNDTYPE boundtypes[2];
5783 SCIP_Real bounds[2];
5784 char name[SCIP_MAXSTRLEN];
5785 SCIP_VAR* var;
5786
5787 var = SCIPgetVarExprVar(singlelocked[i]);
5788 assert(var != NULL);
5789 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5791
5792 /* try to change the variable type to binary */
5793 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5794 {
5797 ++(*nchgvartypes);
5798
5799 if( *infeasible )
5800 {
5801 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5802 break;
5803 }
5804 }
5805 /* add bound disjunction constraint if bounds of the variable are finite */
5806 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5807 {
5808 vars[0] = var;
5809 vars[1] = var;
5810 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5811 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5812 bounds[0] = SCIPvarGetUbGlobal(var);
5813 bounds[1] = SCIPvarGetLbGlobal(var);
5814
5815 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5816
5817 /* create, add, and release bound disjunction constraint */
5818 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5819 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5821 SCIP_CALL( SCIPaddCons(scip, newcons) );
5822 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5823 ++(*naddconss);
5824 }
5825 }
5826 }
5827
5828 /* free memory */
5829 SCIPfreeBufferArray(scip, &singlelocked);
5830 SCIPhashmapFree(&exprcands);
5831
5832 return SCIP_OKAY;
5833}
5834
5835/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5836static
5838 SCIP* scip, /**< SCIP data structure */
5839 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5840 SCIP_CONS** conss, /**< nonlinear constraints */
5841 int nconss, /**< total number of nonlinear constraints */
5842 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5843 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5844 )
5845{
5846 int c;
5847
5848 assert(scip != NULL);
5849 assert(conshdlr != NULL);
5850 assert(conss != NULL || nconss == 0);
5851 assert(nchgvartypes != NULL);
5852 assert(infeasible != NULL);
5853
5854 *infeasible = FALSE;
5855
5856 /* nothing can be done on purley continuous problem */
5858 return SCIP_OKAY;
5859
5860 /* no continuous var can be made implicit-integer if there are no continuous variables */
5861 if( SCIPgetNContVars(scip) == 0 )
5862 return SCIP_OKAY;
5863
5864 for( c = 0; c < nconss; ++c )
5865 {
5866 SCIP_CONSDATA* consdata;
5867 SCIP_EXPR** children;
5868 int nchildren;
5869 SCIP_Real* coefs;
5870 SCIP_EXPR* cand = NULL;
5871 SCIP_Real candcoef = 0.0;
5872 int i;
5873 SCIP_IMPLINTTYPE impltype;
5874
5875 assert(conss != NULL && conss[c] != NULL);
5876
5877 consdata = SCIPconsGetData(conss[c]);
5878 assert(consdata != NULL);
5879
5880 /* the constraint must be an equality constraint */
5881 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5882 continue;
5883
5884 /* the root expression needs to be a sum expression */
5885 if( !SCIPisExprSum(scip, consdata->expr) )
5886 continue;
5887
5888 children = SCIPexprGetChildren(consdata->expr);
5889 nchildren = SCIPexprGetNChildren(consdata->expr);
5890
5891 /* the sum expression must have at least two children
5892 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5893 */
5894 if( nchildren <= 1 )
5895 continue;
5896
5897 coefs = SCIPgetCoefsExprSum(consdata->expr);
5898
5899 /* find first continuous variable and get value of its coefficient */
5900 for( i = 0; i < nchildren; ++i )
5901 {
5902 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5903 continue;
5904
5905 candcoef = coefs[i];
5906 assert(candcoef != 0.0);
5907
5908 /* lhs/rhs - constant divided by candcoef must be integral
5909 * if not, break with cand == NULL, so give up
5910 */
5911 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5912 cand = children[i];
5913
5914 break;
5915 }
5916
5917 /* no suitable continuous variable found */
5918 if( cand == NULL )
5919 continue;
5920
5921 impltype = SCIP_IMPLINTTYPE_STRONG;
5922
5923 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5924 for( i = 0; i < nchildren; ++i )
5925 {
5926 if( children[i] == cand )
5927 continue;
5928
5929 impltype = MIN(impltype, SCIPexprGetIntegrality(children[i]));
5930 /* child i must be integral */
5931 if( impltype == SCIP_IMPLINTTYPE_NONE )
5932 {
5933 cand = NULL;
5934 break;
5935 }
5936
5937 /* coefficient of child i must be integral if diving by candcoef */
5938 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5939 {
5940 cand = NULL;
5941 break;
5942 }
5943 }
5944
5945 if( cand == NULL )
5946 continue;
5947
5948 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5950
5951 /* change variable type */
5952 assert(impltype != SCIP_IMPLINTTYPE_NONE);
5953
5954 SCIP_CALL( SCIPchgVarImplType(scip, SCIPgetVarExprVar(cand), impltype, infeasible) );
5955 ++(*nchgvartypes);
5956
5957 if( *infeasible )
5958 return SCIP_OKAY;
5959
5960 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5961 SCIPexprSetIntegrality(cand, impltype);
5962 }
5963
5964 return SCIP_OKAY;
5965}
5966
5967/** creates auxiliary variable for a given expression
5968 *
5969 * @note for a variable expression it does nothing
5970 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5971 */
5972static
5974 SCIP* scip, /**< SCIP data structure */
5975 SCIP_EXPR* expr /**< expression */
5976 )
5977{
5978 SCIP_EXPR_OWNERDATA* ownerdata;
5979 SCIP_CONSHDLRDATA* conshdlrdata;
5980 SCIP_IMPLINTTYPE impltype;
5981 SCIP_INTERVAL activity;
5982 char name[SCIP_MAXSTRLEN];
5983
5984 assert(scip != NULL);
5985 assert(expr != NULL);
5986
5987 ownerdata = SCIPexprGetOwnerData(expr);
5988 assert(ownerdata != NULL);
5989 assert(ownerdata->nauxvaruses > 0);
5990
5991 /* if we already have auxvar, then do nothing */
5992 if( ownerdata->auxvar != NULL )
5993 return SCIP_OKAY;
5994
5995 /* if expression is a variable-expression, then do nothing */
5996 if( SCIPisExprVar(scip, expr) )
5997 return SCIP_OKAY;
5998
6000 {
6001 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6002 return SCIP_INVALIDCALL;
6003 }
6004
6005 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6006 assert(conshdlrdata != NULL);
6007 assert(conshdlrdata->auxvarid >= 0);
6008
6009 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6010 * but it usually indicates a missing simplify
6011 * if we find situations where we need to have an auxvar for a constant, then remove this assert
6012 */
6013 assert(!SCIPisExprValue(scip, expr));
6014
6015 /* create and capture auxiliary variable */
6016 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6017 ++conshdlrdata->auxvarid;
6018
6019 /* type of auxiliary variable depends on integrality information of the expression */
6020 impltype = SCIPexprGetIntegrality(expr);
6021
6022 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6023 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6024 {
6025 activity = SCIPexprGetActivity(expr);
6026 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6027 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6028 * and abort in debug mode only
6029 */
6031 {
6032 SCIPABORT();
6034 }
6035 }
6036 else
6038
6039 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6040 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6041 */
6042 if( SCIPgetDepth(scip) == 0 )
6043 {
6044 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name,
6045 MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0,
6046 SCIP_VARTYPE_CONTINUOUS, impltype,
6047 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6048 }
6049 else
6050 {
6051 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
6052 SCIP_VARTYPE_CONTINUOUS, impltype,
6053 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6054 }
6055
6056 /* mark the auxiliary variable to be added for the relaxation only
6057 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6058 * or to copy the variable to a subscip
6059 */
6060 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6061
6062 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6063
6064 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6065
6066 /* add variable locks in both directions
6067 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6068 * but then we need to also update the auxvars locks when the expr locks change
6069 */
6070 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6071
6072#ifdef WITH_DEBUG_SOLUTION
6073 if( SCIPdebugIsMainscip(scip) )
6074 {
6075 /* store debug solution value of auxiliary variable
6076 * assumes that expression has been evaluated in debug solution before
6077 */
6078 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6079 }
6080#endif
6081
6082 if( SCIPgetDepth(scip) > 0 )
6083 {
6084 /* initialize local bounds to (locally valid) activity */
6086 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6087 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6088 }
6089
6090 return SCIP_OKAY;
6091}
6092
6093/** initializes separation for constraint
6094 *
6095 * - ensures that activities are up to date in all expressions
6096 * - creates auxiliary variables where required
6097 * - calls propExprDomains() to possibly tighten auxvar bounds
6098 * - calls separation initialization callback of nlhdlrs
6099 */
6100static
6102 SCIP* scip, /**< SCIP data structure */
6103 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6104 SCIP_CONS** conss, /**< constraints */
6105 int nconss, /**< number of constraints */
6106 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6107 )
6108{
6109 SCIP_CONSDATA* consdata;
6110 SCIP_CONSHDLRDATA* conshdlrdata;
6111 SCIP_EXPRITER* it;
6112 SCIP_EXPR* expr;
6114 SCIP_VAR* auxvar;
6115 int nreductions = 0;
6116 int c, e;
6117
6118 assert(scip != NULL);
6119 assert(conshdlr != NULL);
6120 assert(conss != NULL || nconss == 0);
6121 assert(nconss >= 0);
6122 assert(infeasible != NULL);
6123
6124 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6125 assert(conshdlrdata != NULL);
6126
6127 /* start with new propbounds (just to be sure, should not be needed) */
6128 ++conshdlrdata->curpropboundstag;
6129
6132
6133 /* first ensure activities are up to date and create auxvars */
6134 *infeasible = FALSE;
6135 for( c = 0; c < nconss; ++c )
6136 {
6137 assert(conss != NULL);
6138 assert(conss[c] != NULL);
6139
6140 consdata = SCIPconsGetData(conss[c]);
6141 assert(consdata != NULL);
6142 assert(consdata->expr != NULL);
6143
6144#ifdef WITH_DEBUG_SOLUTION
6145 if( SCIPdebugIsMainscip(scip) )
6146 {
6147 SCIP_SOL* debugsol;
6148
6149 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6150
6151 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6152 {
6153 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6154 * in createAuxVar()
6155 */
6156 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6157 }
6158 }
6159#endif
6160
6161 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6162 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6163
6164 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6165 {
6166 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6167 {
6168 SCIP_CALL( createAuxVar(scip, expr) );
6169 }
6170 }
6171
6172 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6173 if( auxvar != NULL )
6174 {
6175 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6176 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6177 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6178 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6179 if( *infeasible )
6180 {
6181 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6182 break;
6183 }
6184
6185 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6186 if( *infeasible )
6187 {
6188 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6189 break;
6190 }
6191 }
6192 }
6193
6194 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6195 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6196 * (e.g., log(x*y), which becomes log(w), w=x*y
6197 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6198 */
6199 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6200 if( result == SCIP_CUTOFF )
6201 *infeasible = TRUE;
6202
6203 /* now call initsepa of nlhdlrs
6204 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6205 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6206 */
6208 for( c = 0; c < nconss && !*infeasible; ++c )
6209 {
6210 assert(conss != NULL);
6211 assert(conss[c] != NULL);
6212
6213 consdata = SCIPconsGetData(conss[c]);
6214 assert(consdata != NULL);
6215 assert(consdata->expr != NULL);
6216
6217 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6218 {
6219 SCIP_EXPR_OWNERDATA* ownerdata;
6220
6221 ownerdata = SCIPexprGetOwnerData(expr);
6222 assert(ownerdata != NULL);
6223
6224 if( ownerdata->nauxvaruses == 0 )
6225 continue;
6226
6227 for( e = 0; e < ownerdata->nenfos; ++e )
6228 {
6229 SCIP_NLHDLR* nlhdlr;
6230 SCIP_Bool underestimate;
6231 SCIP_Bool overestimate;
6232 assert(ownerdata->enfos[e] != NULL);
6233
6234 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6235 * which participated in a previous initSepa() call
6236 */
6237 if( ownerdata->enfos[e]->issepainit )
6238 continue;
6239
6240 /* only call initsepa if it will actually separate */
6241 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6242 continue;
6243
6244 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6245 assert(nlhdlr != NULL);
6246
6247 /* only init sepa if there is an initsepa callback */
6248 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6249 continue;
6250
6251 /* check whether expression needs to be under- or overestimated */
6252 overestimate = ownerdata->nlocksneg > 0;
6253 underestimate = ownerdata->nlockspos > 0;
6254 assert(underestimate || overestimate);
6255
6256 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6257
6258 /* call the separation initialization callback of the nonlinear handler */
6259 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6260 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6261 ownerdata->enfos[e]->issepainit = TRUE;
6262
6263 if( *infeasible )
6264 {
6265 /* stop everything if we detected infeasibility */
6266 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6267 break;
6268 }
6269 }
6270 }
6271 }
6272
6273 SCIPfreeExpriter(&it);
6274
6275 return SCIP_OKAY;
6276}
6277
6278/** returns whether we are ok to branch on auxiliary variables
6279 *
6280 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6281 */
6282static
6284 SCIP* scip, /**< SCIP data structure */
6285 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6286 )
6287{
6288 SCIP_CONSHDLRDATA* conshdlrdata;
6289
6290 assert(conshdlr != NULL);
6291
6292 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6293 assert(conshdlrdata != NULL);
6294
6295 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6296}
6297
6298/** gets weight of variable when splitting violation score onto several variables in an expression */
6299static
6301 SCIP* scip, /**< SCIP data structure */
6302 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6303 SCIP_VAR* var, /**< variable */
6304 SCIP_SOL* sol /**< current solution */
6305 )
6306{
6307 SCIP_CONSHDLRDATA* conshdlrdata;
6308
6309 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6310 assert(conshdlrdata != NULL);
6311
6312 switch( conshdlrdata->branchviolsplit )
6313 {
6314 case 'u' : /* uniform: everyone gets the same score */
6315 return 1.0;
6316
6317 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6318 {
6319 SCIP_Real weight;
6321 return MAX(0.05, weight);
6322 }
6323
6324 case 'd' : /* domain width */
6326
6327 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6328 {
6330 assert(width > 0.0);
6331 if( width > 10.0 )
6332 return 10.0*log10(width);
6333 if( width < 0.1 )
6334 return 0.1/(-log10(width));
6335 return width;
6336 }
6337
6338 default :
6339 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6340 SCIPABORT();
6341 return SCIP_INVALID;
6342 }
6343}
6344
6345/** adds violation-branching score to a set of expressions, thereby distributing the score
6346 *
6347 * Each expression must either be a variable expression or have an aux-variable.
6348 *
6349 * If unbounded variables are present, each unbounded var gets an even score.
6350 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6351 */
6352static
6354 SCIP* scip, /**< SCIP data structure */
6355 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6356 int nexprs, /**< number of expressions */
6357 SCIP_Real violscore, /**< violation-branching score to add to expression */
6358 SCIP_SOL* sol, /**< current solution */
6359 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6360 )
6361{
6362 SCIP_CONSHDLR* conshdlr;
6363 SCIP_VAR* var;
6364 SCIP_Real weight;
6365 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6366 int nunbounded = 0; /* number of candidates with unbounded domain */
6367 int i;
6368
6369 assert(exprs != NULL);
6370 assert(nexprs >= 0);
6371 assert(success != NULL);
6372
6373 if( nexprs == 1 )
6374 {
6375 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6376 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6378 *success = TRUE;
6379 return;
6380 }
6381
6382 if( nexprs == 0 )
6383 {
6384 *success = FALSE;
6385 return;
6386 }
6387
6388 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6389
6390 for( i = 0; i < nexprs; ++i )
6391 {
6393 assert(var != NULL);
6394
6396 ++nunbounded;
6398 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6399 }
6400
6401 *success = FALSE;
6402 for( i = 0; i < nexprs; ++i )
6403 {
6405 assert(var != NULL);
6406
6407 if( nunbounded > 0 )
6408 {
6410 {
6411 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6412 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6413 100.0/nunbounded, violscore,
6415 *success = TRUE;
6416 }
6417 }
6419 {
6420 assert(weightsum > 0.0);
6421
6422 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6423 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6424 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6425 100*weight / weightsum, violscore,
6427 *success = TRUE;
6428 }
6429 else
6430 {
6431 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6433 }
6434 }
6435}
6436
6437/** adds violation-branching score to children of expression for given auxiliary variables
6438 *
6439 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6440 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6441 *
6442 * @note This method may modify the given auxvars array by means of sorting.
6443 */
6444static
6446 SCIP* scip, /**< SCIP data structure */
6447 SCIP_EXPR* expr, /**< expression where to start searching */
6448 SCIP_Real violscore, /**< violation score to add to expression */
6449 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6450 int nauxvars, /**< number of auxiliary variables */
6451 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6452 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6453 )
6454{
6455 SCIP_EXPRITER* it;
6456 SCIP_VAR* auxvar;
6457 SCIP_EXPR** exprs;
6458 int nexprs;
6459 int pos;
6460
6461 assert(scip != NULL);
6462 assert(expr != NULL);
6463 assert(auxvars != NULL);
6464 assert(success != NULL);
6465
6466 /* sort variables to make lookup below faster */
6467 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6468
6471
6472 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6473 nexprs = 0;
6474
6475 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6476 {
6477 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6478 if( auxvar == NULL )
6479 continue;
6480
6481 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6482 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6483 {
6484 assert(auxvars[pos] == auxvar);
6485
6486 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6487 exprs[nexprs++] = expr;
6488
6489 if( nexprs == nauxvars )
6490 break;
6491 }
6492 }
6493
6494 SCIPfreeExpriter(&it);
6495
6496 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6497
6498 SCIPfreeBufferArray(scip, &exprs);
6499
6500 return SCIP_OKAY;
6501}
6502
6503/** registers all unfixed variables in violated constraints as branching candidates */
6504static
6506 SCIP* scip, /**< SCIP data structure */
6507 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6508 SCIP_CONS** conss, /**< constraints */
6509 int nconss, /**< number of constraints */
6510 int* nnotify /**< counter for number of notifications performed */
6511 )
6512{
6513 SCIP_CONSDATA* consdata;
6514 SCIP_VAR* var;
6515 int c;
6516 int i;
6517
6518 assert(conshdlr != NULL);
6519 assert(conss != NULL || nconss == 0);
6520 assert(nnotify != NULL);
6521
6522 *nnotify = 0;
6523
6524 for( c = 0; c < nconss; ++c )
6525 {
6526 assert(conss != NULL && conss[c] != NULL);
6527
6528 consdata = SCIPconsGetData(conss[c]);
6529 assert(consdata != NULL);
6530
6531 /* consider only violated constraints */
6532 if( !isConsViolated(scip, conss[c]) )
6533 continue;
6534
6535 /* register all variables that have not been fixed yet */
6536 assert(consdata->varexprs != NULL);
6537 for( i = 0; i < consdata->nvarexprs; ++i )
6538 {
6539 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6540 assert(var != NULL);
6541
6543 {
6545 ++(*nnotify);
6546 }
6547 }
6548 }
6549
6550 return SCIP_OKAY;
6551}
6552
6553/** registers all variables in violated constraints with branching scores as external branching candidates */
6554static
6556 SCIP* scip, /**< SCIP data structure */
6557 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6558 SCIP_CONS** conss, /**< constraints */
6559 int nconss, /**< number of constraints */
6560 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6561 )
6562{
6563 SCIP_CONSDATA* consdata;
6564 SCIP_EXPRITER* it = NULL;
6565 int c;
6566
6567 assert(conshdlr != NULL);
6568 assert(success != NULL);
6569
6570 *success = FALSE;
6571
6572 if( branchAuxNonlinear(scip, conshdlr) )
6573 {
6576 }
6577
6578 /* register external branching candidates */
6579 for( c = 0; c < nconss; ++c )
6580 {
6581 assert(conss != NULL && conss[c] != NULL);
6582
6583 consdata = SCIPconsGetData(conss[c]);
6584 assert(consdata != NULL);
6585 assert(consdata->varexprs != NULL);
6586
6587 /* consider only violated constraints */
6588 if( !isConsViolated(scip, conss[c]) )
6589 continue;
6590
6591 if( !branchAuxNonlinear(scip, conshdlr) )
6592 {
6593 int i;
6594
6595 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6596 * only, so we can loop over variable expressions
6597 */
6598 for( i = 0; i < consdata->nvarexprs; ++i )
6599 {
6600 SCIP_Real violscore;
6601 SCIP_Real lb;
6602 SCIP_Real ub;
6603 SCIP_VAR* var;
6604
6605 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6606
6607 /* skip variable expressions that do not have a violation score */
6608 if( violscore == 0.0 )
6609 continue;
6610
6611 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6612 assert(var != NULL);
6613
6614 lb = SCIPvarGetLbLocal(var);
6615 ub = SCIPvarGetUbLocal(var);
6616
6617 /* consider variable for branching if it has not been fixed yet */
6618 if( !SCIPisEQ(scip, lb, ub) )
6619 {
6620 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6622 *success = TRUE;
6623 }
6624 else
6625 {
6626 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6627 }
6628
6629 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6630 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6631 */
6632 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6633 }
6634 }
6635 else
6636 {
6637 SCIP_EXPR* expr;
6638 SCIP_VAR* var;
6639 SCIP_Real lb;
6640 SCIP_Real ub;
6641 SCIP_Real violscore;
6642
6643 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6644 {
6645 violscore = SCIPgetExprViolScoreNonlinear(expr);
6646 if( violscore == 0.0 )
6647 continue;
6648
6649 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6650 * variable, so this expression should either be an original variable or have an auxiliary variable
6651 */
6653 assert(var != NULL);
6654
6655 lb = SCIPvarGetLbLocal(var);
6656 ub = SCIPvarGetUbLocal(var);
6657
6658 /* consider variable for branching if it has not been fixed yet */
6659 if( !SCIPisEQ(scip, lb, ub) )
6660 {
6661 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6662
6664 *success = TRUE;
6665 }
6666 else
6667 {
6668 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6669 }
6670 }
6671 }
6672 }
6673
6674 if( it != NULL )
6675 SCIPfreeExpriter(&it);
6676
6677 return SCIP_OKAY;
6678}
6679
6680/** collect branching candidates from violated constraints
6681 *
6682 * Fills array with expressions that serve as branching candidates.
6683 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6684 * branching candidate.
6685 *
6686 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6687 * through variable-expressions only.
6688 */
6689static
6691 SCIP* scip, /**< SCIP data structure */
6692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6693 SCIP_CONS** conss, /**< constraints to process */
6694 int nconss, /**< number of constraints */
6695 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6696 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6697 SCIP_Longint soltag, /**< tag of solution */
6698 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6699 int* ncands /**< number of candidates found */
6700 )
6701{
6702 SCIP_CONSHDLRDATA* conshdlrdata;
6703 SCIP_CONSDATA* consdata;
6704 SCIP_EXPRITER* it = NULL;
6705 int c;
6706 int attempt;
6707 SCIP_VAR* var;
6708
6709 assert(scip != NULL);
6710 assert(conshdlr != NULL);
6711 assert(cands != NULL);
6712 assert(ncands != NULL);
6713
6714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6715 assert(conshdlrdata != NULL);
6716
6717 if( branchAuxNonlinear(scip, conshdlr) )
6718 {
6721 }
6722
6723 *ncands = 0;
6724 for( attempt = 0; attempt < 2; ++attempt )
6725 {
6726 /* collect branching candidates from violated constraints
6727 * in the first attempt, consider only constraints with large violation
6728 * in the second attempt, consider all remaining violated constraints
6729 */
6730 for( c = 0; c < nconss; ++c )
6731 {
6732 SCIP_Real consviol;
6733
6734 assert(conss != NULL && conss[c] != NULL);
6735
6736 /* consider only violated constraints */
6737 if( !isConsViolated(scip, conss[c]) )
6738 continue;
6739
6740 consdata = SCIPconsGetData(conss[c]);
6741 assert(consdata != NULL);
6742 assert(consdata->varexprs != NULL);
6743
6744 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6745
6746 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6747 continue;
6748 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6749 continue;
6750
6751 if( !branchAuxNonlinear(scip, conshdlr) )
6752 {
6753 int i;
6754
6755 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6756 * only, so we can loop over variable expressions
6757 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6758 * variable, therefore we invalidate the score of a variable after processing it.
6759 */
6760 for( i = 0; i < consdata->nvarexprs; ++i )
6761 {
6762 SCIP_Real lb;
6763 SCIP_Real ub;
6764
6765 /* skip variable expressions that do not have a valid violation score */
6766 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6767 continue;
6768
6769 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6770 assert(var != NULL);
6771
6772 lb = SCIPvarGetLbLocal(var);
6773 ub = SCIPvarGetUbLocal(var);
6774
6775 /* skip already fixed variable */
6776 if( SCIPisEQ(scip, lb, ub) )
6777 {
6778 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6779 continue;
6780 }
6781
6782 assert(*ncands + 1 < SCIPgetNVars(scip));
6783 cands[*ncands].expr = consdata->varexprs[i];
6784 cands[*ncands].var = var;
6785 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6786 cands[*ncands].fractionality = 0.0;
6787 ++(*ncands);
6788
6789 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6790 * several times as external branching candidate */
6791 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6792 }
6793 }
6794 else
6795 {
6796 SCIP_EXPR* expr;
6797 SCIP_Real lb;
6798 SCIP_Real ub;
6799
6800 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6801 {
6802 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6803 continue;
6804
6805 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6806 * variables, so this expression should either be an original variable or have an auxiliary variable
6807 */
6809 assert(var != NULL);
6810
6811 lb = SCIPvarGetLbLocal(var);
6812 ub = SCIPvarGetUbLocal(var);
6813
6814 /* skip already fixed variable */
6815 if( SCIPisEQ(scip, lb, ub) )
6816 {
6817 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6818 continue;
6819 }
6820
6821 assert(*ncands + 1 < SCIPgetNVars(scip));
6822 cands[*ncands].expr = expr;
6823 cands[*ncands].var = var;
6824 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6825 cands[*ncands].fractionality = 0.0;
6826 ++(*ncands);
6827 }
6828 }
6829 }
6830
6831 /* if we have branching candidates, then we don't need another attempt */
6832 if( *ncands > 0 )
6833 break;
6834 }
6835
6836 if( it != NULL )
6837 SCIPfreeExpriter(&it);
6838
6839 return SCIP_OKAY;
6840}
6841
6842/** computes a branching score for a variable that reflects how important branching on this variable would be for
6843 * improving the dual bound from the LP relaxation
6844 *
6845 * Assume the Lagrangian for the current LP is something of the form
6846 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6847 * where x are the original variables, z the auxiliary variables,
6848 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6849 *
6850 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6851 * If we could have used not only an estimator, but the actual function f(x), then this would
6852 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6853 * Using a lot of handwaving, we claim that
6854 * lambda_i * (f(x) - a_i'x + b_i)
6855 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6856 * If an estimator depended on local bounds, then it could be improved by branching.
6857 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6858 *
6859 * 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.
6860 * To scale, we divide by the LP objective value (if >1).
6861 *
6862 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6863 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6864 *
6865 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6866 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6867 * would also be branching candidates
6868 */
6869static
6871 SCIP* scip, /**< SCIP data structure */
6872 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6873 SCIP_VAR* var /**< variable */
6874 )
6875{
6876 SCIP_COL* col;
6877 SCIP_ROW** rows;
6878 int nrows;
6879 int r;
6880 SCIP_Real dualscore;
6881
6882 assert(scip != NULL);
6883 assert(conshdlr != NULL);
6884 assert(var != NULL);
6885
6886 /* if LP not solved, then the dual branching score is not available */
6888 return 0.0;
6889
6890 /* if var is not in the LP, then the dual branching score is not available */
6892 return 0.0;
6893
6894 col = SCIPvarGetCol(var);
6895 assert(col != NULL);
6896
6897 if( !SCIPcolIsInLP(col) )
6898 return 0.0;
6899
6900 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6901 rows = SCIPcolGetRows(col);
6902
6903 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6904
6905 /* aggregate duals from all rows from consexpr with non-zero dual
6906 * TODO: this is a quick-and-dirty implementation, and not used by default
6907 * in the long run, this should be either removed or replaced by a proper implementation
6908 */
6909 dualscore = 0.0;
6910 for( r = 0; r < nrows; ++r )
6911 {
6912 SCIP_Real estimategap;
6913 const char* estimategapstr;
6914
6915 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6916 * these would typically be local, unless they are created at the root node
6917 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6918 if( !SCIProwIsLocal(rows[r]) )
6919 continue;
6920 */
6921 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6922 continue;
6923 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6924 continue;
6925
6926 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6927 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6928 continue;
6929 estimategap = atof(estimategapstr + 13);
6930 assert(estimategap >= 0.0);
6931 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6932 estimategap = SCIPgetHugeValue(scip);
6933
6934 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6935 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6936
6937 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6938 }
6939
6940 /* divide by optimal value of LP for scaling */
6941 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6942
6943 return dualscore;
6944}
6945
6946/** computes branching scores (including weighted score) for a set of candidates
6947 *
6948 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6949 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6950 *
6951 * For each score, compute the maximum over all candidates.
6952 *
6953 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6954 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6955 * score of all candidates.
6956 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6957 *
6958 * For example:
6959 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6960 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6961 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6962 * - 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.
6963 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6964 */
6965static
6967 SCIP* scip, /**< SCIP data structure */
6968 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6969 BRANCHCAND* cands, /**< branching candidates */
6970 int ncands, /**< number of candidates */
6971 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6972 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6973 )
6974{
6975 SCIP_CONSHDLRDATA* conshdlrdata;
6976 BRANCHCAND maxscore;
6977 int c;
6978
6979 assert(scip != NULL);
6980 assert(conshdlr != NULL);
6981 assert(cands != NULL);
6982 assert(ncands > 0);
6983
6984 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6985 assert(conshdlrdata != NULL);
6986
6987 /* initialize counts to 0 */
6988 memset(&maxscore, 0, sizeof(BRANCHCAND));
6989
6990 for( c = 0; c < ncands; ++c )
6991 {
6992 if( conshdlrdata->branchviolweight > 0.0 )
6993 {
6994 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6995 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6996 }
6997
6998 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarIsNonimpliedIntegral(cands[c].var) )
6999 {
7000 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
7001 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
7002 */
7003 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
7004
7005 if( considerfracnl && cands[c].fractionality == 0.0 )
7006 {
7007 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
7008 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
7009 */
7010 SCIP_Real solval;
7011 SCIP_Real rounded;
7012
7013 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7014 rounded = SCIPround(scip, solval);
7015
7016 cands[c].fractionality = REALABS(solval - rounded);
7017 }
7018
7019 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
7020 }
7021 else
7022 cands[c].fractionality = 0.0;
7023
7024 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
7025 {
7026 SCIP_Real domainwidth;
7027 SCIP_VAR* var;
7028
7029 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7030 assert(var != NULL);
7031
7032 /* get domain width, taking infinity at 1e20 on purpose */
7033 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
7034
7035 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7036 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7037 * the idea is to penalize very large and very small domains
7038 */
7039 if( domainwidth >= 1.0 )
7040 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7041 else
7042 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7043
7044 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7045 }
7046 else
7047 cands[c].domain = 0.0;
7048
7049 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
7050 {
7051 SCIP_VAR* var;
7052
7053 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7054 assert(var != NULL);
7055
7056 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7057 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7058 }
7059 else
7060 cands[c].dual = 0.0;
7061
7062 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7063 {
7064 SCIP_VAR* var;
7065
7066 var = cands[c].var;
7067 assert(var != NULL);
7068
7069 if( cands[c].expr != NULL )
7070 {
7072 cands[c].pscost = SCIP_INVALID;
7073 else
7074 {
7075 SCIP_Real brpoint;
7076 SCIP_Real pscostdown;
7077 SCIP_Real pscostup;
7078 char strategy;
7079
7080 /* decide how to compute pseudo-cost scores
7081 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7082 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7083 */
7084 if( !SCIPvarIsIntegral(var) )
7085 strategy = conshdlrdata->branchpscostupdatestrategy;
7086 else
7087 strategy = 'l';
7088
7090
7091 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7092 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7093 * For here, I use a simple #counts >= branchpscostreliable.
7094 * TODO use SCIPgetVarPseudocostCount() instead?
7095 */
7096 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7097 {
7098 switch( strategy )
7099 {
7100 case 's' :
7102 break;
7103 case 'd' :
7105 break;
7106 case 'l' :
7108 pscostdown = SCIP_INVALID;
7109 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7110 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7111 else
7113 break;
7114 default :
7115 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7116 pscostdown = SCIP_INVALID;
7117 }
7118 }
7119 else
7120 pscostdown = SCIP_INVALID;
7121
7122 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7123 {
7124 switch( strategy )
7125 {
7126 case 's' :
7128 break;
7129 case 'd' :
7131 break;
7132 case 'l' :
7134 pscostup = SCIP_INVALID;
7135 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7136 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7137 else
7139 break;
7140 default :
7141 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7142 pscostup = SCIP_INVALID;
7143 }
7144 }
7145 else
7146 pscostup = SCIP_INVALID;
7147
7148 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7149 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7150 */
7151 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7152 cands[c].pscost = SCIP_INVALID;
7153 else if( pscostdown == SCIP_INVALID )
7154 cands[c].pscost = pscostup;
7155 else if( pscostup == SCIP_INVALID )
7156 cands[c].pscost = pscostdown;
7157 else
7158 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7159 }
7160 }
7161 else
7162 {
7163 SCIP_Real pscostdown;
7164 SCIP_Real pscostup;
7165 SCIP_Real solval;
7166
7167 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7168
7169 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7170 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7171 * and different between variable value and rounded up value for pscostup
7172 */
7173 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7174 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7175 else
7176 pscostdown = SCIP_INVALID;
7177
7178 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7179 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7180 else
7181 pscostup = SCIP_INVALID;
7182
7183 /* TODO see above for nonlinear variable case */
7184 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7185 cands[c].pscost = SCIP_INVALID;
7186 else if( pscostdown == SCIP_INVALID )
7187 cands[c].pscost = pscostup;
7188 else if( pscostup == SCIP_INVALID )
7189 cands[c].pscost = pscostdown;
7190 else
7191 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7192 }
7193
7194 if( cands[c].pscost != SCIP_INVALID )
7195 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7196 }
7197 else
7198 cands[c].pscost = SCIP_INVALID;
7199
7200 if( conshdlrdata->branchvartypeweight > 0.0 )
7201 {
7202 switch( SCIPvarGetType(cands[c].var) )
7203 {
7205 cands[c].vartype = 1.0;
7206 break;
7208 cands[c].vartype = 0.1;
7209 break;
7211 if( SCIPvarIsImpliedIntegral(cands[c].var) )
7212 cands[c].vartype = 0.01;
7213 else
7214 cands[c].vartype = 0.0;
7215 break;
7216 default:
7217 SCIPerrorMessage("invalid variable type\n");
7218 SCIPABORT();
7219 return; /*lint !e527*/
7220 } /*lint !e788*/
7221
7222 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7223 }
7224 }
7225
7226 /* now compute a weighted score for each candidate from the single scores
7227 * the single scores are scaled to be in [0,1] for this
7228 */
7229 for( c = 0; c < ncands; ++c )
7230 {
7231 SCIP_Real weightsum;
7232
7233 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7234
7235 cands[c].weighted = 0.0;
7236 weightsum = 0.0;
7237
7238 if( maxscore.auxviol > 0.0 )
7239 {
7240 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7241 weightsum += conshdlrdata->branchviolweight;
7242
7243 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7244 }
7245
7246 if( maxscore.fractionality > 0.0 )
7247 {
7248 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7249 weightsum += conshdlrdata->branchfracweight;
7250
7251 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7252 }
7253
7254 if( maxscore.domain > 0.0 )
7255 {
7256 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7257 weightsum += conshdlrdata->branchdomainweight;
7258
7259 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7260 }
7261
7262 if( maxscore.dual > 0.0 )
7263 {
7264 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7265 weightsum += conshdlrdata->branchdualweight;
7266
7267 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7268 }
7269
7270 if( maxscore.pscost > 0.0 )
7271 {
7272 /* use pseudo-costs only if available */
7273 if( cands[c].pscost != SCIP_INVALID )
7274 {
7275 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7276 weightsum += conshdlrdata->branchpscostweight;
7277
7278 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7279 }
7280 else
7281 {
7282 /* do not add pscostscore, if not available, also do not add into weightsum */
7283 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7284 }
7285 }
7286
7287 if( maxscore.vartype > 0.0 )
7288 {
7289 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7290 weightsum += conshdlrdata->branchvartypeweight;
7291
7292 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7293 }
7294
7295 assert(weightsum > 0.0); /* we should have got at least one valid score */
7296 cands[c].weighted /= weightsum;
7297
7298 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7299 }
7300}
7301
7302/** compare two branching candidates by their weighted score
7303 *
7304 * if weighted score is equal, use variable index of (aux)var
7305 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7306 */
7307static
7308SCIP_DECL_SORTINDCOMP(branchcandCompare)
7309{
7310 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7311
7312 if( cands[ind1].weighted != cands[ind2].weighted )
7313 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7314
7315 if( cands[ind1].var != cands[ind2].var )
7316 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7317
7318 return cands[ind1].expr != NULL ? 1 : -1;
7319}
7320
7321/** picks a candidate from array of branching candidates */
7322static
7324 SCIP* scip, /**< SCIP data structure */
7325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7326 BRANCHCAND* cands, /**< branching candidates */
7327 int ncands, /**< number of candidates */
7328 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7329 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
7330 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7331 )
7332{
7333 SCIP_CONSHDLRDATA* conshdlrdata;
7334 int* perm;
7335 int c;
7336 int left;
7337 int right;
7338 SCIP_Real threshold;
7339
7340 assert(cands != NULL);
7341 assert(ncands >= 1);
7342 assert(selected != NULL);
7343
7344 if( ncands == 1 )
7345 {
7346 *selected = cands;
7347 return SCIP_OKAY;
7348 }
7349
7350 /* if there are more than one candidate, then compute scores and select */
7351
7352 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7353 assert(conshdlrdata != NULL);
7354
7355 /* compute additional scores on branching candidates and weighted score */
7356 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
7357
7358 /* sort candidates by weighted score */
7359 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7360 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7361
7362 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7363 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7364 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7365
7366 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7367 left = 0;
7368 right = ncands - 1;
7369 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7370 while( left < right )
7371 {
7372 int mid = (left + right) / 2;
7373 if( cands[perm[mid]].weighted >= threshold )
7374 left = mid + 1;
7375 else
7376 right = mid;
7377 }
7378 assert(left <= ncands);
7379
7380 if( left < ncands )
7381 {
7382 if( cands[perm[left]].weighted >= threshold )
7383 {
7384 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7385 ncands = left + 1;
7386 }
7387 else
7388 {
7389 assert(cands[perm[left]].weighted < threshold);
7390 ncands = left;
7391 }
7392 }
7393 assert(ncands > 0);
7394
7395 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7396 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7397 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7398
7399 if( ncands > 1 )
7400 {
7401 /* choose at random from candidates 0..ncands-1 */
7402 if( conshdlrdata->branchrandnumgen == NULL )
7403 {
7404 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7405 }
7406 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7407 *selected = &cands[perm[c]];
7408 }
7409 else
7410 *selected = &cands[perm[0]];
7411
7412 SCIPfreeBufferArray(scip, &perm);
7413
7414 return SCIP_OKAY;
7415}
7416
7417/** do spatial branching or register branching candidates */
7418static
7420 SCIP* scip, /**< SCIP data structure */
7421 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7422 SCIP_CONS** conss, /**< constraints to process */
7423 int nconss, /**< number of constraints */
7424 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7425 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7426 SCIP_Longint soltag, /**< tag of solution */
7427 SCIP_RESULT* result /**< pointer to store the result of branching */
7428 )
7429{
7430 SCIP_CONSHDLRDATA* conshdlrdata;
7431 BRANCHCAND* cands;
7432 int ncands;
7433 BRANCHCAND* selected = NULL;
7434 SCIP_NODE* downchild;
7435 SCIP_NODE* eqchild;
7436 SCIP_NODE* upchild;
7437
7438 assert(conshdlr != NULL);
7439 assert(result != NULL);
7440
7442
7443 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7444 assert(conshdlrdata != NULL);
7445
7446 if( conshdlrdata->branchexternal )
7447 {
7448 /* just register branching candidates as external */
7449 SCIP_Bool success;
7450
7451 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7452 if( success )
7454
7455 return SCIP_OKAY;
7456 }
7457
7458 /* collect branching candidates and their auxviol-score */
7460 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7461
7462 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7463 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7464 */
7465 if( ncands == 0 )
7466 goto TERMINATE;
7467
7468 /* here we include fractionality of integer variables into the branching score
7469 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7470 */
7471 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
7472 assert(selected != NULL);
7473 assert(selected->expr != NULL);
7474
7475 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7476 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7477
7478 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7479 &upchild) );
7480 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7482 else
7483 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7485
7486 TERMINATE:
7487 SCIPfreeBufferArray(scip, &cands);
7488
7489 return SCIP_OKAY;
7490}
7491
7492/** call enforcement or estimate callback of nonlinear handler
7493 *
7494 * Calls the enforcement callback, if available.
7495 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7496 *
7497 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7498 */
7499static
7501 SCIP* scip, /**< SCIP main data structure */
7502 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7503 SCIP_CONS* cons, /**< nonlinear constraint */
7504 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7505 SCIP_EXPR* expr, /**< expression */
7506 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7507 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7508 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7509 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7510 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7511 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7512 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7513 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7514 SCIP_RESULT* result /**< pointer to store the result */
7515 )
7516{
7517 assert(result != NULL);
7518
7519 /* call enforcement callback of the nlhdlr */
7520 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7521 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7522
7523 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7525 {
7526 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7527 SCIPnlhdlrGetName(nlhdlr), *result); )
7528 return SCIP_OKAY;
7529 }
7530 else
7531 {
7532 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7533 }
7534
7536
7537 /* now call the estimator callback of the nlhdlr */
7538 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7539 {
7540 SCIP_VAR* auxvar;
7541 SCIP_Bool sepasuccess = FALSE;
7542 SCIP_Bool branchscoresuccess = FALSE;
7543 SCIP_PTRARRAY* rowpreps;
7544 int minidx;
7545 int maxidx;
7546 int r;
7547 SCIP_ROWPREP* rowprep;
7548
7549 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7550
7551 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7552 assert(auxvar != NULL);
7553
7554 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7555 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7556
7557 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7558 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7559
7560 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7561
7562 if( !sepasuccess )
7563 {
7564 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7565 SCIPnlhdlrGetName(nlhdlr)); )
7566 }
7567
7568 for( r = minidx; r <= maxidx; ++r )
7569 {
7570 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7571
7572 assert(rowprep != NULL);
7574
7575 if( !branchcandonly )
7576 {
7577 /* complete estimator to cut */
7578 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7579
7580 /* add the cut and/or branching scores
7581 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7582 */
7583 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7584 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7585 }
7586
7587 SCIPfreeRowprep(scip, &rowprep);
7588 }
7589
7590 if( branchcandonly && branchscoresuccess )
7591 {
7592 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7594 }
7595
7596 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7597 }
7598
7599 return SCIP_OKAY;
7600}
7601
7602/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7603 *
7604 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7605 */
7606static
7608 SCIP* scip, /**< SCIP data structure */
7609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7610 SCIP_CONS* cons, /**< nonlinear constraint */
7611 SCIP_EXPR* expr, /**< expression */
7612 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7613 SCIP_Longint soltag, /**< tag of solution */
7614 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7615 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7616 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7617 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7618 )
7619{
7620 SCIP_CONSHDLRDATA* conshdlrdata;
7621 SCIP_EXPR_OWNERDATA* ownerdata;
7622 SCIP_Real origviol;
7623 SCIP_Bool underestimate;
7624 SCIP_Bool overestimate;
7625 SCIP_Real auxviol;
7626 SCIP_Bool auxunderestimate;
7627 SCIP_Bool auxoverestimate;
7628 SCIP_RESULT hdlrresult;
7629 int e;
7630
7631 assert(scip != NULL);
7632 assert(expr != NULL);
7633 assert(result != NULL);
7634
7635 ownerdata = SCIPexprGetOwnerData(expr);
7636 assert(ownerdata != NULL);
7637 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7638
7640
7641 /* make sure that this expression has been evaluated */
7642 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7643
7644 /* decide whether under- or overestimate is required and get amount of violation */
7645 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7646
7647 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7648 assert(conshdlrdata != NULL);
7649
7650 /* no sufficient violation w.r.t. the original variables -> skip expression */
7651 if( !overestimate && !underestimate )
7652 {
7653 return SCIP_OKAY;
7654 }
7655
7656 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7657 for( e = 0; e < ownerdata->nenfos; ++e )
7658 {
7659 SCIP_NLHDLR* nlhdlr;
7660
7661 /* skip nlhdlr that do not want to participate in any separation */
7662 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7663 continue;
7664
7665 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7666 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7667 continue;
7668
7669 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7670 assert(nlhdlr != NULL);
7671
7672 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7673 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7674 ENFOLOG(
7675 SCIPinfoMessage(scip, enfologfile, " expr ");
7676 SCIPprintExpr(scip, expr, enfologfile);
7677 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7678 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7679 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7680 )
7681
7682 /* TODO if expr is root of constraint (consdata->expr == expr),
7683 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7684 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7685 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7686 * so we should enforce in these auxiliaries first
7687 * if changing this here, we must also adapt analyzeViolation()
7688 */
7689
7690 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7691 assert(auxviol >= 0.0);
7692
7693 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7694 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7695 {
7696 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7697 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7698 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7699
7700 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7701 continue;
7702 }
7703
7704 /* 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 */
7705 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7706 {
7707 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7708 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7709 underestimate, overestimate); )
7710
7711 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7712 continue;
7713 }
7714
7715 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7716 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7717 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7718
7719 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7720 * wants to be called for separation on this side, then call separation of nlhdlr
7721 */
7722 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7723 {
7724 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7725 hdlrresult = SCIP_DIDNOTFIND;
7726 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7727 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7728
7729 if( hdlrresult == SCIP_CUTOFF )
7730 {
7731 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7733 ownerdata->lastenforced = conshdlrdata->enforound;
7734 break;
7735 }
7736
7737 if( hdlrresult == SCIP_SEPARATED )
7738 {
7739 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7741 ownerdata->lastenforced = conshdlrdata->enforound;
7742 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7743 break;
7744 }
7745
7746 if( hdlrresult == SCIP_REDUCEDDOM )
7747 {
7748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7750 ownerdata->lastenforced = conshdlrdata->enforound;
7751 /* TODO or should we always just stop here? */
7752 }
7753
7754 if( hdlrresult == SCIP_BRANCHED )
7755 {
7756 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7757 assert(inenforcement);
7758
7759 /* separation and domain reduction takes precedence over branching */
7761 if( *result == SCIP_DIDNOTFIND )
7763 ownerdata->lastenforced = conshdlrdata->enforound;
7764 }
7765 }
7766
7767 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7768 * wants to be called for separation on this side, then call separation of nlhdlr
7769 */
7770 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7771 {
7772 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7773 hdlrresult = SCIP_DIDNOTFIND;
7774 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7775 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7776
7777 if( hdlrresult == SCIP_CUTOFF )
7778 {
7779 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7781 ownerdata->lastenforced = conshdlrdata->enforound;
7782 break;
7783 }
7784
7785 if( hdlrresult == SCIP_SEPARATED )
7786 {
7787 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7789 ownerdata->lastenforced = conshdlrdata->enforound;
7790 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7791 break;
7792 }
7793
7794 if( hdlrresult == SCIP_REDUCEDDOM )
7795 {
7796 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7798 ownerdata->lastenforced = conshdlrdata->enforound;
7799 /* TODO or should we always just stop here? */
7800 }
7801
7802 if( hdlrresult == SCIP_BRANCHED )
7803 {
7804 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7805 assert(inenforcement);
7806
7807 /* separation takes precedence over branching */
7809 if( *result == SCIP_DIDNOTFIND )
7811 ownerdata->lastenforced = conshdlrdata->enforound;
7812 }
7813 }
7814 }
7815
7816 return SCIP_OKAY;
7817}
7818
7819/** helper function to enforce a single constraint */
7820static
7822 SCIP* scip, /**< SCIP data structure */
7823 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7824 SCIP_CONS* cons, /**< constraint to process */
7825 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7826 SCIP_Longint soltag, /**< tag of solution */
7827 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7828 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7829 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7830 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7831 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7832 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7833 )
7834{
7835 SCIP_CONSDATA* consdata;
7836 SCIP_CONSHDLRDATA* conshdlrdata;
7837 SCIP_EXPR* expr;
7838
7839 assert(conshdlr != NULL);
7840 assert(cons != NULL);
7841 assert(it != NULL);
7842 assert(result != NULL);
7843 assert(success != NULL);
7844
7845 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7846 assert(conshdlrdata != NULL);
7847
7848 consdata = SCIPconsGetData(cons);
7849 assert(consdata != NULL);
7850 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7851
7852 *success = FALSE;
7853
7854 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7855 {
7856 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7857 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7858 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7859 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7860 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7861 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7862 * confuse the stalling check for how long to do separation).
7863 */
7864 SCIP_Bool infeasible;
7865 int ntightenings;
7866
7867 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7868 if( infeasible )
7869 {
7871 return SCIP_OKAY;
7872 }
7873 /* if we tightened an auxvar bound, we better communicate that */
7874 if( ntightenings > 0 )
7876 }
7877
7878 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7879 {
7880 SCIP_EXPR_OWNERDATA* ownerdata;
7881 SCIP_RESULT resultexpr;
7882
7883 ownerdata = SCIPexprGetOwnerData(expr);
7884 assert(ownerdata != NULL);
7885
7886 /* we can only enforce if there is an auxvar to compare with */
7887 if( ownerdata->auxvar == NULL )
7888 continue;
7889
7890 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7891 if( ownerdata->lastenforced == conshdlrdata->enforound )
7892 {
7893 ENFOLOG(
7894 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7895 SCIPprintExpr(scip, expr, enfologfile);
7896 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7897 )
7898 *success = TRUE;
7899 continue;
7900 }
7901
7902 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7903
7904 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7905 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7906 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
7907 *success = TRUE;
7908
7909 if( resultexpr == SCIP_CUTOFF )
7910 {
7912 break;
7913 }
7914
7915 if( resultexpr == SCIP_SEPARATED )
7917
7918 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7920
7921 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7923 }
7924
7925 return SCIP_OKAY;
7926}
7927
7928/** try to separate violated constraints and, if in enforcement, register branching scores
7929 *
7930 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7931 *
7932 * Sets result to
7933 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7934 * - SCIP_CUTOFF, if node can be cutoff,
7935 * - SCIP_SEPARATED, if a cut has been added,
7936 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7937 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7938 * - SCIP_INFEASIBLE, if external branching candidates were registered
7939 */
7940static
7942 SCIP* scip, /**< SCIP data structure */
7943 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7944 SCIP_CONS** conss, /**< constraints to process */
7945 int nconss, /**< number of constraints */
7946 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7947 SCIP_Longint soltag, /**< tag of solution */
7948 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7949 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7950 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7951 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7952 )
7953{
7954 SCIP_CONSHDLRDATA* conshdlrdata;
7955 SCIP_EXPRITER* it;
7956 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7957 int c;
7958
7959 assert(conshdlr != NULL);
7960 assert(conss != NULL || nconss == 0);
7961 assert(result != NULL);
7962
7963 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7964 assert(conshdlrdata != NULL);
7965
7966 /* increase tag to tell whether branching scores in expression belong to this sweep
7967 * and which expressions have already been enforced in this sweep
7968 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7969 */
7970 ++(conshdlrdata->enforound);
7971
7973
7976
7977 for( c = 0; c < nconss; ++c )
7978 {
7979 assert(conss != NULL && conss[c] != NULL);
7980
7981 /* skip constraints that are not enabled or deleted */
7982 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7983 continue;
7984 assert(SCIPconsIsActive(conss[c]));
7985
7986 /* skip constraints that have separation disabled if we are only in separation */
7987 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7988 continue;
7989
7990 /* skip non-violated constraints */
7991 if( !isConsViolated(scip, conss[c]) )
7992 continue;
7993
7994 ENFOLOG(
7995 {
7996 SCIP_CONSDATA* consdata;
7997 int i;
7998 consdata = SCIPconsGetData(conss[c]);
7999 assert(consdata != NULL);
8000 SCIPinfoMessage(scip, enfologfile, " constraint ");
8001 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
8002 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
8003 for( i = 0; i < consdata->nvarexprs; ++i )
8004 {
8005 SCIP_VAR* var;
8006 var = SCIPgetVarExprVar(consdata->varexprs[i]);
8007 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
8009 }
8010 })
8011
8012 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
8013
8014 if( *result == SCIP_CUTOFF )
8015 break;
8016
8017 if( !consenforced && inenforcement && !branchcandonly )
8018 {
8019 SCIP_Real viol;
8020
8021 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
8022 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
8023 {
8024 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
8025 "cuts allowed\n", SCIPconsGetName(conss[c])); )
8026
8027 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
8028
8029 if( consenforced )
8030 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
8031
8032 if( *result == SCIP_CUTOFF )
8033 break;
8034 }
8035 }
8036 }
8037
8038 SCIPfreeExpriter(&it);
8039
8040 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8041
8042 if( *result == SCIP_BRANCHED && !branchcandonly )
8043 {
8044 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
8045 * branching
8046 */
8047 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
8048
8049 /* branching should either have branched: result == SCIP_BRANCHED,
8050 * or fixed a variable: result == SCIP_REDUCEDDOM,
8051 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
8052 * or have not done anything: result == SCIP_DIDNOTFIND
8053 */
8055 }
8056
8057 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8058
8059 return SCIP_OKAY;
8060}
8061
8062/** decide whether to branch on fractional integer or nonlinear variable
8063 *
8064 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
8065 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
8066 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
8067 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
8068 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
8069 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
8070 */
8071static
8073 SCIP* scip, /**< SCIP data structure */
8074 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8075 SCIP_CONS** conss, /**< constraints to process */
8076 int nconss, /**< number of constraints */
8077 SCIP_Longint soltag, /**< tag of LP solution */
8078 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
8079 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
8080 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
8081 )
8082{
8084 int nlpcands;
8085 SCIP_VAR** lpcands; /* fractional integer variables */
8086 SCIP_Real* lpcandsfrac; /* fractionalities */
8087 BRANCHCAND* cands;
8088 BRANCHCAND* selected;
8089 int ncands;
8090 int c;
8091
8092 assert(scip != NULL);
8093 assert(conshdlr != NULL);
8094 assert(conss != NULL);
8095 assert(nconss > 0);
8096 assert(branchintegral != NULL);
8097 assert(cutoff != NULL);
8098
8099 *branchintegral = FALSE;
8100 *cutoff = FALSE;
8101
8103 return SCIP_OKAY;
8104
8105 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
8106 switch( result )
8107 {
8108 case SCIP_DIDNOTFIND:
8109 /* no branching candidates found could mean that the LP solution is in a convex region */
8110 *branchintegral = TRUE;
8111 return SCIP_OKAY;
8112
8113 case SCIP_CUTOFF:
8114 /* probably cannot happen, but easy to handle */
8115 *cutoff = TRUE;
8116 return SCIP_OKAY;
8117
8118 case SCIP_SEPARATED:
8119 case SCIP_REDUCEDDOM:
8120 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8121 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8122 return SCIP_ERROR;
8123
8124 case SCIP_BRANCHED:
8125 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8126 break;
8127
8128 case SCIP_INFEASIBLE:
8129 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8130 * but this was disabled by branchcandonly = TRUE)
8131 */
8132 default:
8133 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8134 return SCIP_ERROR;
8135 } /*lint !e788*/
8136
8137 /* collect spatial branching candidates and their auxviol-score */
8139 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8140
8141 /* add fractional integer variables to branching candidates */
8143
8144 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8145
8146 for( c = 0; c < nlpcands; ++c )
8147 {
8150 cands[ncands].expr = NULL;
8151 cands[ncands].var = lpcands[c];
8152 cands[ncands].auxviol = 0.0;
8153 cands[ncands].fractionality = lpcandsfrac[c];
8154 ++ncands;
8155 }
8156
8157 /* select a variable for branching
8158 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8159 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
8160 */
8161 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
8162 assert(selected != NULL);
8163
8164 if( selected->expr == NULL )
8165 {
8166 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8167
8168 *branchintegral = TRUE;
8169 }
8170
8171 SCIPfreeBufferArray(scip, &cands);
8172
8173 return SCIP_OKAY;
8174}
8175
8176/** decide whether to consider spatial branching before integrality has been enforced
8177 *
8178 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8179 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8180 *
8181 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8182 */
8183static
8185 SCIP* scip, /**< SCIP data structure */
8186 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8187 SCIP_SOL* sol /**< solution to be enforced */
8188 )
8189{
8190 SCIP_CONSHDLRDATA* conshdlrdata;
8191
8192 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8193 assert(conshdlrdata != NULL);
8194
8195 /* if LP still unbounded, then work on nonlinear constraints first */
8197 return FALSE;
8198
8199 /* no branching in cons_integral if no integer variables */
8201 return FALSE;
8202
8203 /* no branching in cons_integral if LP solution not fractional */
8204 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
8205 return FALSE;
8206
8207 /* no branching in cons_integral if relax solution not fractional */
8208 if( sol != NULL )
8209 {
8210 SCIP_Bool isfractional = FALSE;
8211 SCIP_VAR** vars;
8212 int nbinvars;
8213 int nintvars;
8214 int i;
8215
8217 nbinvars = SCIPgetNBinVars(scip);
8218 nintvars = SCIPgetNIntVars(scip);
8219
8220 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
8221 {
8222 assert(vars[i] != NULL);
8224
8226 isfractional = TRUE;
8227 }
8228
8229 if( !isfractional )
8230 return FALSE;
8231 }
8232
8233 /* branchmixfractional being infinity means that integral should always go first */
8234 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8235 return TRUE;
8236
8237 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8238 if( conshdlrdata->branchmixfractional == 0.0 )
8239 return FALSE;
8240
8241 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8242 * @todo this gives the total pseudocost count divided by the number of discrete variables
8243 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8244 */
8245 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8246 return TRUE;
8247 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8248 return TRUE;
8249
8250 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8251 return FALSE;
8252}
8253
8254/** collect (and print (if debugging enfo)) information on violation in expressions
8255 *
8256 * assumes that constraint violations have been computed
8257 */
8258static
8260 SCIP* scip, /**< SCIP data structure */
8261 SCIP_CONS** conss, /**< constraints */
8262 int nconss, /**< number of constraints */
8263 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8264 SCIP_Longint soltag, /**< tag of solution */
8265 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8266 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8267 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8268 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8269 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8270 )
8271{
8272 SCIP_CONSDATA* consdata;
8273 SCIP_EXPRITER* it;
8274 SCIP_EXPR* expr;
8275 SCIP_Real v;
8276 int c;
8277
8278 assert(conss != NULL || nconss == 0);
8279 assert(maxabsconsviol != NULL);
8280 assert(maxrelconsviol != NULL);
8281 assert(maxauxviol != NULL);
8282 assert(maxvarboundviol != NULL);
8283
8286
8287 *maxabsconsviol = 0.0;
8288 *maxrelconsviol = 0.0;
8289 *minauxviol = SCIPinfinity(scip);
8290 *maxauxviol = 0.0;
8291 *maxvarboundviol = 0.0;
8292
8293 for( c = 0; c < nconss; ++c )
8294 {
8295 assert(conss != NULL && conss[c] != NULL);
8296
8297 consdata = SCIPconsGetData(conss[c]);
8298 assert(consdata != NULL);
8299
8300 /* skip constraints that are not enabled, deleted, or have separation disabled */
8301 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8302 continue;
8303 assert(SCIPconsIsActive(conss[c]));
8304
8305 v = getConsAbsViolation(conss[c]);
8306 *maxabsconsviol = MAX(*maxabsconsviol, v);
8307
8308 /* skip non-violated constraints */
8309 if( !isConsViolated(scip, conss[c]) )
8310 continue;
8311
8312 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8313 *maxrelconsviol = MAX(*maxrelconsviol, v);
8314
8315 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8316 {
8317 SCIP_EXPR_OWNERDATA* ownerdata;
8318 SCIP_Real auxvarvalue;
8319 SCIP_Real auxvarlb;
8320 SCIP_Real auxvarub;
8321 SCIP_Bool violunder;
8322 SCIP_Bool violover;
8323 SCIP_Real origviol;
8324 SCIP_Real auxviol;
8325 int e;
8326
8327 ownerdata = SCIPexprGetOwnerData(expr);
8328 assert(ownerdata != NULL);
8329
8330 if( ownerdata->auxvar == NULL )
8331 {
8332 /* check violation of variable bounds of original variable */
8333 if( SCIPisExprVar(scip, expr) )
8334 {
8335 SCIP_VAR* var;
8336 var = SCIPgetVarExprVar(expr);
8337 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8338 auxvarlb = SCIPvarGetLbLocal(var);
8339 auxvarub = SCIPvarGetUbLocal(var);
8340
8341 origviol = 0.0;
8342 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8343 origviol = auxvarlb - auxvarvalue;
8344 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8345 origviol = auxvarvalue - auxvarub;
8346 if( origviol <= 0.0 )
8347 continue;
8348
8349 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8350
8351 ENFOLOG(
8352 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8353 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8354 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8355 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8356 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8357 SCIPinfoMessage(scip, enfologfile, "\n");
8358 )
8359 }
8360
8361 continue;
8362 }
8363
8364 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8365 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8366 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8367
8368 /* check violation of variable bounds of auxiliary variable */
8369 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8370 *maxvarboundviol = auxvarlb - auxvarvalue;
8371 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8372 *maxvarboundviol = auxvarvalue - auxvarub;
8373
8374 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8375
8376 ENFOLOG(
8377 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8378 {
8379 SCIPinfoMessage(scip, enfologfile, "expr ");
8380 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8381 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8382
8383 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8384 if( origviol > 0.0 )
8385 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8386 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8387 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8388 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8389 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8390 SCIPinfoMessage(scip, enfologfile, "\n");
8391 }
8392 )
8393
8394 /* no violation w.r.t. the original variables -> skip expression */
8395 if( origviol == 0.0 )
8396 continue;
8397
8398 /* compute aux-violation for each nonlinear handlers */
8399 for( e = 0; e < ownerdata->nenfos; ++e )
8400 {
8401 SCIP_NLHDLR* nlhdlr;
8402
8403 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8404 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8405 continue;
8406
8407 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8408 assert(nlhdlr != NULL);
8409
8410 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8411 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8412
8413 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8414
8415 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8416
8417 if( auxviol > 0.0 )
8418 {
8419 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8420 *maxauxviol = MAX(*maxauxviol, auxviol);
8421 *minauxviol = MIN(*minauxviol, auxviol);
8422 }
8423 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8424 }
8425 }
8426 }
8427
8428 SCIPfreeExpriter(&it);
8429
8430 return SCIP_OKAY;
8431} /*lint !e715*/
8432
8433/** enforcement of constraints called by enfolp and enforelax */
8434static
8436 SCIP* scip, /**< SCIP data structure */
8437 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8438 SCIP_CONS** conss, /**< constraints to process */
8439 int nconss, /**< number of constraints */
8440 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8441 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8442 )
8443{
8444 SCIP_CONSHDLRDATA* conshdlrdata;
8445 SCIP_Real maxabsconsviol;
8446 SCIP_Real maxrelconsviol;
8447 SCIP_Real minauxviol;
8448 SCIP_Real maxauxviol;
8449 SCIP_Real maxvarboundviol;
8450 SCIP_Longint soltag;
8451 SCIP_Bool branchintegral;
8452 int nnotify;
8453 int c;
8454
8455 if( branchingIntegralFirst(scip, conshdlr, sol) )
8456 {
8457 /* let cons_integral handle enforcement */
8459 return SCIP_OKAY;
8460 }
8461
8462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8463 assert(conshdlr != NULL);
8464
8465 soltag = SCIPgetExprNewSoltag(scip);
8466
8468 for( c = 0; c < nconss; ++c )
8469 {
8470 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8471
8472 if( isConsViolated(scip, conss[c]) )
8474 }
8475
8476 if( *result == SCIP_FEASIBLE )
8477 {
8478 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8480 return SCIP_OKAY;
8481 }
8482
8483 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8484 &minauxviol, &maxauxviol, &maxvarboundviol) );
8485
8486 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8487 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8488 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8489 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8490
8491 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8492
8493 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8494 if( sol == NULL )
8495 {
8497
8498 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8499 if( cutoff )
8500 {
8502 return SCIP_OKAY;
8503 }
8504 if( branchintegral )
8505 {
8506 /* let cons_integral handle enforcement */
8508 return SCIP_OKAY;
8509 }
8510 }
8511
8512 /* try to propagate */
8513 if( conshdlrdata->propinenforce )
8514 {
8515 SCIP_RESULT propresult;
8516 int nchgbds = 0;
8517
8518 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8519
8520 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8521 {
8522 *result = propresult;
8523 return SCIP_OKAY;
8524 }
8525 }
8526
8527 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8528 * all violated expr/auxvar in violated constraints)
8529 */
8530 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8531 sol == NULL )
8532 {
8533 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8534 ++conshdlrdata->ntightenlp;
8535
8537
8538 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8539 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8540
8541 return SCIP_OKAY;
8542 }
8543
8544 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8545 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8546 */
8547 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8548 {
8549 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8550 ++conshdlrdata->ntightenlp;
8551
8553
8554 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8555
8556 return SCIP_OKAY;
8557 }
8558
8559 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8560
8563 return SCIP_OKAY;
8564
8566
8567 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8568 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8569
8570 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8571 {
8572 /* if there are still fractional integer variables, then let cons_integral go first */
8574 return SCIP_OKAY;
8575 }
8576
8577 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8578 {
8579 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8580 ++conshdlrdata->ntightenlp;
8581
8583
8584 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8585 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8586
8587 return SCIP_OKAY;
8588 }
8589
8590 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8591 SCIPgetLPFeastol(scip)) && sol == NULL )
8592 {
8593 /* try whether tighten the LP feasibility tolerance could help
8594 * maybe it is just some cut that hasn't been taken into account sufficiently
8595 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8596 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8597 * until the LP feastol reaches epsilon
8598 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8599 * when maxauxviol is above LP feastol)
8600 */
8601 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8602 ++conshdlrdata->ndesperatetightenlp;
8603
8605
8606 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8607
8608 return SCIP_OKAY;
8609 }
8610
8611 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8612 if( !conshdlrdata->propinenforce )
8613 {
8614 SCIP_RESULT propresult;
8615 int nchgbds = 0;
8616
8617 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8618
8619 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8620 {
8621 *result = propresult;
8622 return SCIP_OKAY;
8623 }
8624 }
8625
8626 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8627 * now look if we find any unfixed variable that we could still branch on
8628 */
8629 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8630
8631 if( nnotify > 0 )
8632 {
8633 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8634 ++conshdlrdata->ndesperatebranch;
8635
8636 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8637
8638 return SCIP_OKAY;
8639 }
8640
8641 /* if everything is fixed in violated constraints, then let's cut off the node
8642 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8643 * result may not be conclusive (when constraint violations are small)
8644 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8645 * sufficiently (see st_e40)
8646 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8647 * not "desperate", but a pretty obvious thing to do
8648 */
8649 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8651
8652 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8653 if( !SCIPisZero(scip, maxvarboundviol) )
8654 ++conshdlrdata->ndesperatecutoff;
8655
8656 return SCIP_OKAY;
8657}
8658
8659/** separation for all violated constraints to be used by SEPA callbacks */
8660static
8662 SCIP* scip, /**< SCIP data structure */
8663 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8664 SCIP_CONS** conss, /**< constraints to process */
8665 int nconss, /**< number of constraints */
8666 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8667 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8668 )
8669{
8670 SCIP_Longint soltag;
8671 SCIP_Bool haveviol = FALSE;
8672 int c;
8673
8675
8676 soltag = SCIPgetExprNewSoltag(scip);
8677
8678 /* compute violations */
8679 for( c = 0; c < nconss; ++c )
8680 {
8681 assert(conss[c] != NULL);
8682
8683 /* skip constraints that are not enabled, deleted, or have separation disabled */
8684 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8685 continue;
8686 assert(SCIPconsIsActive(conss[c]));
8687
8688 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8689
8690 if( isConsViolated(scip, conss[c]) )
8691 haveviol = TRUE;
8692 }
8693
8694 /* if none of our constraints are violated, don't attempt separation */
8695 if( !haveviol )
8696 {
8697 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8698 return SCIP_OKAY;
8699 }
8700
8701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8702
8703 /* call separation */
8704 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8705
8706 return SCIP_OKAY;
8707}
8708
8709/** hash key retrieval function for bilinear term entries */
8710static
8711SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8712{ /*lint --e{715}*/
8713 SCIP_CONSHDLRDATA* conshdlrdata;
8714 int idx;
8715
8716 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8717 assert(conshdlrdata != NULL);
8718
8719 idx = ((int)(size_t)elem) - 1;
8720 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8721
8722 return (void*)&conshdlrdata->bilinterms[idx];
8723}
8724
8725/** returns TRUE iff the bilinear term entries are equal */
8726static
8727SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8728{ /*lint --e{715}*/
8731
8732 /* get corresponding entries */
8733 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8734 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8735 assert(entry1->x != NULL && entry1->y != NULL);
8736 assert(entry2->x != NULL && entry2->y != NULL);
8737 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8738 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8739
8740 return entry1->x == entry2->x && entry1->y == entry2->y;
8741}
8742
8743/** returns the hash value of the key */
8744static
8745SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8746{ /*lint --e{715}*/
8748
8749 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8750 assert(entry->x != NULL && entry->y != NULL);
8751 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8752
8753 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8754}
8755
8756/** compare two auxiliary expressions
8757 *
8758 * Compares auxiliary variables, followed by coefficients, and then constants.
8759 */
8760static
8762{
8765 int compvars;
8766 int i;
8767
8768 /* compare the auxiliary variables */
8769 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8770
8771 if( compvars != 0 )
8772 return compvars;
8773
8774 /* compare the coefficients and constants */
8775 for( i = 0; i < 3; ++i )
8776 {
8777 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8778 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8779 }
8780
8781 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8782}
8783
8784/* add an auxiliary expression to a bilinear term */
8785static
8787 SCIP* scip, /**< SCIP data structure */
8788 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8789 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8790 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8791 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8792 )
8793{
8794 SCIP_Bool found;
8795 int pos;
8796 int i;
8797
8798 *added = FALSE;
8799
8800 /* check if auxexpr has already been added to term */
8801 if( term->nauxexprs == 0 )
8802 {
8803 found = FALSE;
8804 pos = 0;
8805 }
8806 else
8807 {
8808 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8809 }
8810
8811 if( !found )
8812 {
8813 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8814 return SCIP_OKAY;
8815
8817 assert(term->auxexprssize >= term->nauxexprs + 1);
8818
8819 /* insert expression at the correct position */
8820 for( i = term->nauxexprs; i > pos; --i )
8821 {
8822 term->aux.exprs[i] = term->aux.exprs[i-1];
8823 }
8824 term->aux.exprs[pos] = auxexpr;
8825 ++(term->nauxexprs);
8826 *added = TRUE;
8827 }
8828 else
8829 {
8830 assert(term->aux.exprs != NULL);
8831 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8832 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8833 }
8834
8835 return SCIP_OKAY;
8836}
8837
8838/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8839static
8841 SCIP* scip, /**< SCIP data structure */
8842 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8843 SCIP_CONS** conss, /**< nonlinear constraints */
8844 int nconss /**< total number of nonlinear constraints */
8845 )
8846{
8847 SCIP_CONSHDLRDATA* conshdlrdata;
8848 SCIP_EXPRITER* it;
8849 int c;
8850
8851 assert(conss != NULL || nconss == 0);
8852
8853 if( nconss == 0 )
8854 return SCIP_OKAY;
8855
8856 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8857 assert(conshdlrdata != NULL);
8858
8859 /* check whether the bilinear terms have been stored already */
8860 if( conshdlrdata->bilinterms != NULL )
8861 return SCIP_OKAY;
8862
8863 /* create and initialize iterator */
8867
8868 /* iterate through all constraints */
8869 for( c = 0; c < nconss; ++c )
8870 {
8871 SCIP_CONSDATA* consdata;
8872 SCIP_EXPR* expr;
8873
8874 assert(conss != NULL && conss[c] != NULL);
8875 consdata = SCIPconsGetData(conss[c]);
8876 assert(consdata != NULL);
8877
8878 /* iterate through all expressions */
8879 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8880 {
8881 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8882 SCIP_VAR* x = NULL;
8883 SCIP_VAR* y = NULL;
8884
8885 /* check whether the expression is of the form f(..)^2 */
8886 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8887 {
8888 x = SCIPgetExprAuxVarNonlinear(children[0]);
8889 y = x;
8890 }
8891 /* check whether the expression is of the form f(..) * g(..) */
8892 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8893 {
8894 x = SCIPgetExprAuxVarNonlinear(children[0]);
8895 y = SCIPgetExprAuxVarNonlinear(children[1]);
8896 }
8897
8898 /* add variables to the hash table */
8899 if( x != NULL && y != NULL )
8900 {
8903 }
8904 }
8905 }
8906
8907 /* release iterator */
8908 SCIPfreeExpriter(&it);
8909
8910 return SCIP_OKAY;
8911}
8912
8913/** store x, y and the locks in a new bilinear term */
8914static
8916 SCIP* scip, /**< SCIP data structure */
8917 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8918 SCIP_VAR* x, /**< the first variable */
8919 SCIP_VAR* y, /**< the second variable */
8920 int nlockspos, /**< number of positive locks of the bilinear term */
8921 int nlocksneg, /**< number of negative locks of the bilinear term */
8922 int* idx, /**< pointer to store the position of the term in bilinterms array */
8923 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8924 )
8925{
8926 SCIP_CONSHDLRDATA* conshdlrdata;
8928
8929 assert(conshdlr != NULL);
8930 assert(x != NULL);
8931 assert(y != NULL);
8932 assert(nlockspos >= 0);
8933 assert(nlocksneg >= 0);
8934
8935 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8936 assert(conshdlrdata != NULL);
8937
8938 /* ensure that x.index <= y.index */
8939 if( SCIPvarCompare(x, y) == 1 )
8940 {
8941 SCIPswapPointers((void**)&x, (void**)&y);
8942 }
8943 assert(SCIPvarCompare(x, y) < 1);
8944
8945 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8946
8947 /* update or create the term */
8948 if( *idx >= 0 )
8949 { /* the term has already been added */
8950 assert(conshdlrdata->bilinterms[*idx].x == x);
8951 assert(conshdlrdata->bilinterms[*idx].y == y);
8952
8953 /* get term and add locks */
8954 term = &conshdlrdata->bilinterms[*idx];
8955 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8956 term->nlockspos += nlockspos;
8957 term->nlocksneg += nlocksneg;
8958 }
8959 else
8960 { /* this is the first time we encounter this product */
8961 /* ensure size of bilinterms array */
8962 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8963
8964 *idx = conshdlrdata->nbilinterms;
8965
8966 /* get term and set values in the created bilinear term */
8967 term = &conshdlrdata->bilinterms[*idx];
8968 assert(term != NULL);
8969 term->x = x;
8970 term->y = y;
8971 term->nauxexprs = 0;
8972 term->auxexprssize = 0;
8973 term->nlockspos = nlockspos;
8974 term->nlocksneg = nlocksneg;
8975 term->existing = existing;
8976 if( existing )
8977 term->aux.var = NULL;
8978 else
8979 term->aux.exprs = NULL;
8980
8981 /* increase the total number of bilinear terms */
8982 ++(conshdlrdata->nbilinterms);
8983
8984 /* save to the hashtable */
8985 if( conshdlrdata->bilinhashtable == NULL )
8986 {
8987 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8988 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8989 (void*)conshdlrdata) );
8990 }
8991 assert(conshdlrdata->bilinhashtable != NULL);
8992
8993 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8994 * because zero can not be inserted into hash table
8995 */
8996 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8997
8998 /* capture product variables */
9001 }
9002
9003 return SCIP_OKAY;
9004}
9005
9006/** frees array of bilinear terms and hash table */
9007static
9009 SCIP* scip, /**< SCIP data structure */
9010 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
9011 )
9012{
9013 int i;
9014 int j;
9015
9016 assert(conshdlrdata != NULL);
9017
9018 /* check whether bilinear terms have been stored */
9019 if( conshdlrdata->bilinterms == NULL )
9020 {
9021 assert(conshdlrdata->bilinterms == NULL);
9022 assert(conshdlrdata->nbilinterms == 0);
9023 assert(conshdlrdata->bilintermssize == 0);
9024
9025 return SCIP_OKAY;
9026 }
9027
9028 /* release variables */
9029 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
9030 {
9031 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
9032 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
9033
9034 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
9035 {
9036 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
9037 {
9038 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
9039 }
9040 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
9041 }
9042
9043 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
9044 {
9045 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
9046 continue;
9047 }
9048
9049 /* the rest is for simple terms with a single auxvar */
9050
9051 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
9052 if( conshdlrdata->bilinterms[i].aux.var != NULL )
9053 {
9054 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
9055 }
9056 }
9057
9058 /* free hash table */
9059 if( conshdlrdata->bilinhashtable != NULL )
9060 {
9061 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
9062 }
9063
9064 /* free bilinterms array; reset counters */
9065 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
9066 conshdlrdata->nbilinterms = 0;
9067 conshdlrdata->bilintermssize = 0;
9068
9069 return SCIP_OKAY;
9070}
9071
9072/*
9073 * vertex polyhedral separation
9074 */
9075
9076/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
9077static
9079 SCIP* scip, /**< SCIP data structure */
9080 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
9081 SCIP_LPI** lp /**< pointer to store created LP */
9082 )
9083{
9084 SCIP_Real* obj;
9085 SCIP_Real* lb;
9086 SCIP_Real* ub;
9087 SCIP_Real* val;
9088 int* beg;
9089 int* ind;
9090 unsigned int nnonz;
9091 unsigned int ncols;
9092 unsigned int nrows;
9093 unsigned int i;
9094 unsigned int k;
9095
9096 assert(scip != NULL);
9097 assert(lp != NULL);
9098 assert(nvars > 0);
9100
9101 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
9102
9103 /* create lpi to store the LP */
9105
9106 nrows = (unsigned int)nvars + 1;
9107 ncols = POWEROFTWO((unsigned int)nvars);
9108 nnonz = (ncols * (nrows + 1)) / 2;
9109
9110 /* allocate necessary memory; set obj, lb, and ub to zero */
9113 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
9114 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
9115 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
9116 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
9117
9118 /* calculate nonzero entries in the LP */
9119 for( i = 0, k = 0; i < ncols; ++i )
9120 {
9121 int row;
9122 unsigned int a;
9123
9124 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
9125 ub[i] = SCIPlpiInfinity(*lp);
9126
9127 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
9128 beg[i] = (int)k;
9129 row = 0;
9130
9131 /* iterate through the bit representation of i */
9132 a = 1;
9133 while( a <= i )
9134 {
9135 if( (a & i) != 0 )
9136 {
9137 val[k] = 1.0;
9138 ind[k] = row;
9139
9140 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
9141
9142 ++k;
9143 }
9144
9145 a <<= 1;
9146 ++row;
9147 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
9148 assert(POWEROFTWO(row) == a);
9149 }
9150
9151 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
9152 val[k] = 1.0;
9153 ind[k] = (int)nrows - 1;
9154 ++k;
9155 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9156 }
9157 assert(k == nnonz);
9158
9159 /* load all data into LP interface
9160 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9161 */
9162 assert(nrows <= ncols);
9164 (int)ncols, obj, lb, ub, NULL,
9165 (int)nrows, lb, lb, NULL,
9166 (int)nnonz, beg, ind, val) );
9167
9168 /* for the last row, we can set the rhs to 1.0 already */
9169 ind[0] = (int)nrows - 1;
9170 val[0] = 1.0;
9171 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9172
9173 /* free allocated memory */
9180
9181 return SCIP_OKAY;
9182}
9183
9184/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9185 * \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
9186 * set of vertices of the domain
9187 */
9188static
9190 SCIP* scip, /**< SCIP data structure */
9191 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9192 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9193 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9194 int nallvars, /**< number of all variables */
9195 int nvars, /**< number of unfixed variables */
9196 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9197 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9198 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9199 )
9200{
9201 SCIP_Real maxerror;
9202 SCIP_Real facetval;
9203 SCIP_Real funval;
9204 SCIP_Real error;
9205 unsigned int i;
9206 unsigned int ncorners;
9207 unsigned int prev;
9208
9209 assert(scip != NULL);
9210 assert(funvals != NULL);
9211 assert(box != NULL);
9212 assert(nonfixedpos != NULL);
9213 assert(facetcoefs != NULL);
9214
9215 ncorners = POWEROFTWO(nvars);
9216 maxerror = 0.0;
9217
9218 /* check the origin (all variables at lower bound) */
9219 facetval = facetconstant;
9220 for( i = 0; i < (unsigned int) nallvars; ++i )
9221 facetval += facetcoefs[i] * box[2*i];
9222
9223 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9224 funval = funvals[0];
9225 if( overestimate )
9226 error = funval - facetval;
9227 else
9228 error = facetval - funval;
9229
9230 /* update maximum error */
9231 maxerror = MAX(error, maxerror);
9232
9233 prev = 0;
9234 for( i = 1; i < ncorners; ++i )
9235 {
9236 unsigned int gray;
9237 unsigned int diff;
9238 unsigned int pos;
9239 int origpos;
9240
9241 gray = i ^ (i >> 1);
9242 diff = gray ^ prev;
9243
9244 /* compute position of unique 1 of diff */
9245 pos = 0;
9246 while( (diff >>= 1) != 0 )
9247 ++pos;
9248 assert(pos < (unsigned int)nvars);
9249
9250 origpos = nonfixedpos[pos];
9251
9252 if( gray > prev )
9253 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9254 else
9255 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9256
9257 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9258 funval = funvals[gray];
9259 if( overestimate )
9260 error = funval - facetval;
9261 else
9262 error = facetval - funval;
9263
9264 /* update maximum error */
9265 maxerror = MAX(error, maxerror);
9266
9267 prev = gray;
9268 }
9269
9270 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9271
9272 return maxerror;
9273}
9274
9275/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9276static
9278 SCIP* scip, /**< SCIP data structure */
9279 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9280 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9281 SCIP_Real* xstar, /**< point to be separated */
9282 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9283 int nallvars, /**< half of the length of box */
9284 int* nonfixedpos, /**< indices of nonfixed variables */
9285 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9286 int nvars, /**< number of nonfixed variables */
9287 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9288 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9289 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9290 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9291 )
9292{ /*lint --e{715}*/
9293 SCIP_CONSHDLRDATA* conshdlrdata;
9294 SCIP_LPI* lp;
9295 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9296 int* inds;
9297 int ncols;
9298 int nrows;
9299 int i;
9300 SCIP_Real facetvalue;
9301 SCIP_Real mindomwidth;
9302 SCIP_RETCODE lpsolveretcode;
9303
9304 assert(scip != NULL);
9305 assert(conshdlr != NULL);
9306 assert(xstar != NULL);
9307 assert(box != NULL);
9308 assert(nonfixedpos != NULL);
9309 assert(funvals != NULL);
9310 assert(nvars >= 0);
9312 assert(success != NULL);
9313 assert(facetcoefs != NULL);
9314 assert(facetconstant != NULL);
9315
9316 *success = FALSE;
9317
9318 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9319 assert(conshdlrdata != NULL);
9320
9321 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9322 {
9323 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9324 }
9325
9326 /* construct an LP for this size, if not having one already */
9327 if( conshdlrdata->vp_lp[nvars] == NULL )
9328 {
9329 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9330 }
9331 lp = conshdlrdata->vp_lp[nvars];
9332 assert(lp != NULL);
9333
9334 /* get number of cols and rows of separation lp */
9335 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9336 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9337
9338 /* number of columns should equal the number of corners = 2^nvars */
9339 assert(ncols == (int)POWEROFTWO(nvars));
9340
9341 /* allocate necessary memory */
9342 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9343 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9344
9345 /*
9346 * set up the described LP on the transformed space
9347 */
9348
9349 for( i = 0; i < ncols; ++i )
9350 inds[i] = i;
9351
9352 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9353 mindomwidth = 2*SCIPinfinity(scip);
9354 for( i = 0; i < nrows-1; ++i )
9355 {
9356 SCIP_Real solval;
9357 SCIP_Real lb;
9358 SCIP_Real ub;
9359 int varpos;
9360
9361 assert(i < nvars);
9362
9363 varpos = nonfixedpos[i];
9364 lb = box[2 * varpos];
9365 ub = box[2 * varpos + 1];
9366 solval = xstar[varpos];
9367
9368 if( ub - lb < mindomwidth )
9369 mindomwidth = ub - lb;
9370
9371 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9372 if( solval <= lb )
9373 aux[i] = 0.0;
9374 else if( solval >= ub )
9375 aux[i] = 1.0;
9376 else
9377 aux[i] = (solval - lb) / (ub - lb);
9378
9379 /* perturb point to hopefully obtain a facet of the convex envelope */
9380 if( conshdlrdata->vp_maxperturb > 0.0 )
9381 {
9382 assert(conshdlrdata->vp_randnumgen != NULL);
9383
9384 if( aux[i] == 1.0 )
9385 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9386 else if( aux[i] == 0.0 )
9387 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9388 else
9389 {
9390 SCIP_Real perturbation;
9391
9392 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9393 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9394 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9395 }
9396 assert(0.0 < aux[i] && aux[i] < 1.0);
9397 }
9398
9399 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9400 }
9401
9402 /* update LP */
9403 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9404 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9406
9407 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9408 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9409 {
9410 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9411 }
9412 /* set an iteration limit so we do not run forever */
9414 /* 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 */
9416 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9417 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9418 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9419 */
9421
9422#ifdef SCIP_DEBUG
9424#endif
9425
9426 /*
9427 * solve the LP and store the resulting facet for the transformed space
9428 */
9429 if( conshdlrdata->vp_dualsimplex )
9430 {
9431 lpsolveretcode = SCIPlpiSolveDual(lp);
9432 }
9433 else
9434 {
9435 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9436 }
9437 if( lpsolveretcode == SCIP_LPERROR )
9438 {
9439 SCIPdebugMsg(scip, "LP error, aborting.\n");
9440 goto CLEANUP;
9441 }
9442 SCIP_CALL( lpsolveretcode );
9443
9444 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9445 if( !SCIPlpiIsDualFeasible(lp) )
9446 {
9447 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9448 goto CLEANUP;
9449 }
9450
9451 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9452 * columns than needed, in particular, \bar \beta is the last dual multiplier
9453 */
9454 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9455
9456 for( i = 0; i < nvars; ++i )
9457 facetcoefs[nonfixedpos[i]] = aux[i];
9458 /* last dual multiplier is the constant */
9459 *facetconstant = aux[nrows - 1];
9460
9461#ifdef SCIP_DEBUG
9462 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9463 for( i = 0; i < nallvars; ++i )
9464 {
9465 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9466 }
9467 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9468#endif
9469
9470 /*
9471 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9472 */
9473
9474 SCIPdebugMsg(scip, "facet in orig. space: ");
9475
9476 facetvalue = 0.0;
9477 for( i = 0; i < nvars; ++i )
9478 {
9479 SCIP_Real lb;
9480 SCIP_Real ub;
9481 int varpos;
9482
9483 varpos = nonfixedpos[i];
9484 lb = box[2 * varpos];
9485 ub = box[2 * varpos + 1];
9486 assert(!SCIPisEQ(scip, lb, ub));
9487
9488 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9489 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9490
9491 /* beta = beta_bar - sum_i alpha_i * lb_i */
9492 *facetconstant -= facetcoefs[varpos] * lb;
9493
9494 /* evaluate */
9495 facetvalue += facetcoefs[varpos] * xstar[varpos];
9496
9497 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9498 }
9499 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9500
9501 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9502 facetvalue += *facetconstant;
9503
9504 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9505
9506 /* if overestimate, then we want facetvalue < targetvalue
9507 * if underestimate, then we want facetvalue > targetvalue
9508 * if none holds, give up
9509 * so maybe here we should check against the minimal violation
9510 */
9511 if( overestimate == (facetvalue > targetvalue) )
9512 {
9513 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9514 goto CLEANUP;
9515 }
9516
9517 /* if we made it until here, then we have a nice facet */
9518 *success = TRUE;
9519
9520CLEANUP:
9521 /* free allocated memory */
9522 SCIPfreeBufferArray(scip, &inds);
9524
9525 return SCIP_OKAY;
9526}
9527
9528/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9529 *
9530 * In other words, compute the line that passes through two given points.
9531 */
9532static
9534 SCIP* scip, /**< SCIP data structure */
9535 SCIP_Real left, /**< left coordinate */
9536 SCIP_Real right, /**< right coordinate */
9537 SCIP_Real funleft, /**< value of function in left coordinate */
9538 SCIP_Real funright, /**< value of function in right coordinate */
9539 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9540 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9541 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9542 )
9543{
9544 assert(scip != NULL);
9545 assert(SCIPisLE(scip, left, right));
9546 assert(!SCIPisInfinity(scip, -left));
9547 assert(!SCIPisInfinity(scip, right));
9548 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9549 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9550 assert(success != NULL);
9551 assert(facetcoef != NULL);
9552 assert(facetconstant != NULL);
9553
9554 *facetcoef = (funright - funleft) / (right - left);
9555 *facetconstant = funleft - *facetcoef * left;
9556
9557 *success = TRUE;
9558
9559 return SCIP_OKAY;
9560}
9561
9562/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9563 *
9564 * Three points a, b, and c are given.
9565 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9566 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9567 */
9568static
9570 SCIP* scip, /**< SCIP data structure */
9571 SCIP_Real a1, /**< first coordinate of a */
9572 SCIP_Real a2, /**< second coordinate of a */
9573 SCIP_Real a3, /**< third coordinate of a */
9574 SCIP_Real b1, /**< first coordinate of b */
9575 SCIP_Real b2, /**< second coordinate of b */
9576 SCIP_Real b3, /**< third coordinate of b */
9577 SCIP_Real c1, /**< first coordinate of c */
9578 SCIP_Real c2, /**< second coordinate of c */
9579 SCIP_Real c3, /**< third coordinate of c */
9580 SCIP_Real* alpha, /**< coefficient of first coordinate */
9581 SCIP_Real* beta, /**< coefficient of second coordinate */
9582 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9583 SCIP_Real* delta /**< constant right-hand side */
9584 )
9585{
9586 assert(scip != NULL);
9587 assert(alpha != NULL);
9588 assert(beta != NULL);
9589 assert(gamma_ != NULL);
9590 assert(delta != NULL);
9591
9592 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9593 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9594 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9595 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9596
9597 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9598
9599 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9600 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9601 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9602 {
9603 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9604 *delta = 0.0;
9605 *alpha = 0.0;
9606 *beta = 0.0;
9607 *gamma_ = 0.0;
9608 return SCIP_OKAY;
9609 }
9610
9611 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9612 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9613 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9614 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9615 {
9616 SCIP_Real m[9];
9617 SCIP_Real rhs[3];
9618 SCIP_Real x[3];
9619 SCIP_Bool success;
9620
9621 /*
9622 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));
9623 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));
9624 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));
9625 */
9626
9627 /* initialize matrix column-wise */
9628 m[0] = a1;
9629 m[1] = b1;
9630 m[2] = c1;
9631 m[3] = a2;
9632 m[4] = b2;
9633 m[5] = c2;
9634 m[6] = a3;
9635 m[7] = b3;
9636 m[8] = c3;
9637
9638 rhs[0] = 1.0;
9639 rhs[1] = 1.0;
9640 rhs[2] = 1.0;
9641
9642 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9643
9644 /* solve the linear problem */
9645 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9646
9647 *delta = rhs[0];
9648 *alpha = x[0];
9649 *beta = x[1];
9650 *gamma_ = x[2];
9651
9652 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9653 * not add a cut to SCIP and that all assertions are trivially fulfilled
9654 */
9655 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9656 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9657 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9658 {
9659 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9660 *delta = 0.0;
9661 *alpha = 0.0;
9662 *beta = 0.0;
9663 *gamma_ = 0.0;
9664 }
9665 }
9666
9667 if( *gamma_ < 0.0 )
9668 {
9669 *alpha = -*alpha;
9670 *beta = -*beta;
9671 *gamma_ = -*gamma_;
9672 *delta = -*delta;
9673 }
9674
9675 return SCIP_OKAY;
9676}
9677
9678/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9679static
9681 SCIP* scip, /**< SCIP data structure */
9682 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9683 SCIP_Real p1[2], /**< first vertex of box */
9684 SCIP_Real p2[2], /**< second vertex of box */
9685 SCIP_Real p3[2], /**< third vertex of box */
9686 SCIP_Real p4[2], /**< forth vertex of box */
9687 SCIP_Real p1val, /**< value in p1 */
9688 SCIP_Real p2val, /**< value in p2 */
9689 SCIP_Real p3val, /**< value in p3 */
9690 SCIP_Real p4val, /**< value in p4 */
9691 SCIP_Real xstar[2], /**< point to be separated */
9692 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9693 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9694 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9695 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9696 )
9697{
9698 SCIP_Real alpha, beta, gamma_, delta;
9699 SCIP_Real xstarval, candxstarval = 0.0;
9700 int leaveout;
9701
9702 assert(scip != NULL);
9703 assert(success != NULL);
9704 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9705 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9706 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9707 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9708 assert(facetcoefs != NULL);
9709 assert(facetconstant != NULL);
9710
9711 *success = FALSE;
9712
9713 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9714 if( !overestimate )
9715 {
9716 p1val = -p1val;
9717 p2val = -p2val;
9718 p3val = -p3val;
9719 p4val = -p4val;
9720 targetvalue = -targetvalue;
9721 }
9722
9723 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9724 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9725 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9726 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9727
9728 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9729 * alpha*x + beta*y + gamma*z = delta
9730 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9731 * the fourth corner point lies below this hyperplane.
9732 * 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.,
9733 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9734 * or, equivalently,
9735 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9736 */
9737 for( leaveout = 1; leaveout <= 4; ++leaveout )
9738 {
9739 switch( leaveout)
9740 {
9741 case 1 :
9742 /* get hyperplane through p2, p3, p4 */
9743 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9744 &alpha, &beta, &gamma_, &delta) );
9745 /* if not underestimating in p1, then go to next candidate */
9746 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9747 continue;
9748 break;
9749
9750 case 2 :
9751 /* get hyperplane through p1, p3, p4 */
9752 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9753 &alpha, &beta, &gamma_, &delta) );
9754 /* if not underestimating in p2, then go to next candidate */
9755 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9756 continue;
9757 break;
9758
9759 case 3 :
9760 /* get hyperplane through p1, p2, p4 */
9761 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9762 &alpha, &beta, &gamma_, &delta) );
9763 /* if not underestimating in p3, then go to next candidate */
9764 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9765 continue;
9766 break;
9767
9768 case 4 :
9769 /* get hyperplane through p1, p2, p3 */
9770 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9771 &alpha, &beta, &gamma_, &delta) );
9772 /* if not underestimating in p4, then stop */
9773 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9774 continue;
9775 break;
9776
9777 default: /* only for lint */
9779 beta = SCIP_INVALID;
9780 gamma_ = SCIP_INVALID;
9781 delta = SCIP_INVALID;
9782 break;
9783 }
9784
9785 /* check if bad luck: should not happen if numerics are fine */
9786 if( SCIPisZero(scip, gamma_) )
9787 continue;
9788 assert(!SCIPisNegative(scip, gamma_));
9789
9790 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9791 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9792 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9793 continue;
9794
9795 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9796
9797 /* value of hyperplane candidate in xstar */
9798 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9799
9800 /* if reaching target and first or better than previous candidate, then update */
9801 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9802 {
9803 /* flip hyperplane */
9804 if( !overestimate )
9805 gamma_ = -gamma_;
9806
9807 facetcoefs[0] = -alpha/gamma_;
9808 facetcoefs[1] = -beta/gamma_;
9809 *facetconstant = delta/gamma_;
9810
9811 *success = TRUE;
9812 candxstarval = xstarval;
9813 }
9814 }
9815
9816 return SCIP_OKAY;
9817}
9818
9819/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9820 * graph yet) in an array
9821 */
9822static
9824 SCIP* scip, /**< SCIP pointer */
9825 int** openidx, /**< address of openidx array */
9826 int nelems, /**< number of elements that need to be stored */
9827 int* maxnelems /**< pointer to store maximum number that can be stored */
9828 )
9829{
9830 assert(scip != NULL);
9831 assert(openidx != NULL);
9832 assert(maxnelems != NULL);
9833
9834 if( nelems > *maxnelems )
9835 {
9836 int newsize;
9837
9838 newsize = SCIPcalcMemGrowSize(scip, nelems);
9839 assert(newsize >= nelems);
9840
9841 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9842
9843 *maxnelems = newsize;
9844 }
9845
9846 return SCIP_OKAY;
9847}
9848
9849/** ensures that we can store information about local variables in an array */
9850static
9852 SCIP* scip, /**< SCIP pointer */
9853 SCIP_VAR*** vars, /**< address of variable array */
9854 SCIP_Real** vals, /**< address of value array */
9855 int nelems, /**< number of elements that need to be stored */
9856 int* maxnelems /**< pointer to store maximum number that can be stored */
9857 )
9858{
9859 assert(scip != NULL);
9860 assert(vars != NULL);
9861 assert(vals != NULL);
9862 assert(maxnelems != NULL);
9863
9864 if( nelems > *maxnelems )
9865 {
9866 int newsize;
9867
9868 newsize = SCIPcalcMemGrowSize(scip, nelems);
9869 assert(newsize > *maxnelems);
9870
9872 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9873
9874 *maxnelems = newsize;
9875 }
9876
9877 return SCIP_OKAY;
9878}
9879
9880/** tries to add gadget for finding signed permutations of bilinear products
9881 *
9882 * If a product has exactly two children being variables, negating both simultanteoulsy
9883 * is a signed permutation.
9884 */
9885static
9887 SCIP* scip, /**< SCIP pointer */
9888 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9889 SCIP_CONS* cons, /**< constraint containing product expression */
9890 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9891 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9892 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9893 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9894 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9895 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9896 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9897 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9898 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9899 )
9900{
9901 SYM_EXPRDATA* symdata;
9902 SCIP_EXPR** children;
9903 SCIP_VAR* var1 = NULL;
9904 SCIP_VAR* var2 = NULL;
9905 SCIP_Real val1 = 0.0;
9906 SCIP_Real val2 = 0.0;
9907 SCIP_Real coef;
9908 SCIP_Real prodval;
9909 SCIP_Real constant;
9910 int nlocvars;
9911 int optype;
9912 int nchildren;
9913 int prodidx;
9914 int coefidx1;
9915 int coefidx2;
9916 int childidx;
9917
9918 assert(scip != NULL);
9919 assert(expr != NULL);
9921 assert(graph != NULL);
9922 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9923 assert(consvars != NULL);
9924 assert(consvals != NULL);
9925 assert(maxnconsvars != NULL);
9926 assert(*maxnconsvars > 0);
9927 assert(handledexprs != NULL);
9928 assert(success != NULL);
9929
9930 *success = FALSE;
9931
9932 /* we require exactly two children being variables */
9933 nchildren = SCIPexprGetNChildren(expr);
9934 if( nchildren != 2 )
9935 return SCIP_OKAY;
9936
9937 children = SCIPexprGetChildren(expr);
9938 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9939 return SCIP_OKAY;
9940
9941 /* check whether each child is not multi-aggregated and is not shifted */
9942 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9943
9944 for( childidx = 0; childidx < 2; ++childidx )
9945 {
9946 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9947 (*consvals)[0] = 1.0;
9948 nlocvars = 1;
9949 constant = 0.0;
9950
9951 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9952 &constant, SCIPconsIsTransformed(cons)) );
9953
9954 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9955 return SCIP_OKAY;
9956
9957 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9958 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9959 return SCIP_OKAY;
9960
9961 /* store information about variables */
9962 if( childidx == 0 )
9963 {
9964 var1 = (*consvars)[0];
9965 val1 = (*consvals)[0];
9966 }
9967 else
9968 {
9969 var2 = (*consvars)[0];
9970 val2 = (*consvals)[0];
9971 }
9972 }
9973 assert(var1 != NULL);
9974 assert(var2 != NULL);
9975
9976 /* store the we handle the children */
9977 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9978 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9979
9980 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9981 assert(symdata != NULL);
9982 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9983
9984 coef = SCIPgetSymExprdataConstants(symdata)[0];
9985
9986 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9987
9988 /* add gadget modeling the product
9989 *
9990 * Since the constants are 0, each variable is centered at the origin, which leads to
9991 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9992 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9993 * negate both variables simulataneously.
9994 */
9996 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9997 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9998
9999 prodval = coef * val1 * val2;
10000
10001 /* introduce nodes for the product value and its negation; since flipping both variables
10002 * simultaneously is a signed symmetry, assign both nodes the same value
10003 */
10004 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
10005 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
10006
10007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
10008 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
10009 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
10010
10011 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10012 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10013 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10014 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10015 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10016 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10017 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10018 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10019
10020 *success = TRUE;
10021
10022 return SCIP_OKAY;
10023}
10024
10025/** returns whether an operator is even and, if yes, stores data about operator */
10026static
10028 SCIP* scip, /**< SCIP pointer */
10029 SCIP_EXPR* expr, /**< expression corresponding to operator */
10030 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
10031 * needed for symmetry computation */
10032 SCIP_Real* value /**< pointer to store value for symmetry computation */
10033 )
10034{
10035 SYM_EXPRDATA* symdata;
10036
10037 assert(scip != NULL);
10038 assert(expr != NULL);
10039 assert(hasvalue != NULL);
10040 assert(value != NULL);
10041
10042 /* check for different operators known to be even */
10043 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
10044 {
10045 /* get remaining information needed for symmetry detection */
10046 if( SCIPisExprSignpower(scip, expr) )
10047 {
10048 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10049 assert(symdata != NULL);
10050 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10051
10052 *value = SCIPgetSymExprdataConstants(symdata)[0];
10053 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
10054
10056 }
10057 else
10058 {
10059 assert(SCIPisExprCos(scip, expr));
10060 *hasvalue = FALSE;
10061 }
10062
10063 return TRUE;
10064 }
10065 else if( SCIPisExprPower(scip, expr) )
10066 {
10067 SCIP_Real exponent;
10068 int safeexponent;
10069
10070 /* only consider expressions corresponding to an even power */
10071 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10072 assert(symdata != NULL);
10073 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10074
10075 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10077
10078 /* check whether the exponent is an even integer */
10079 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
10080 return FALSE;
10081
10082 /* deal with numerics */
10083 safeexponent = (int) (exponent + 0.5);
10084 if( safeexponent % 2 != 0 )
10085 return FALSE;
10086
10087 *hasvalue = TRUE;
10088 *value = exponent;
10089
10090 return TRUE;
10091 }
10092 else if( SCIPisExprAbs(scip, expr) )
10093 {
10094 *hasvalue = FALSE;
10095
10096 return TRUE;
10097 }
10098
10099 return FALSE;
10100}
10101
10102/** returns whether a variable is centered at 0 */
10103static
10105 SCIP* scip, /**< SCIP pointer */
10106 SCIP_VAR* var /**< variable to be checked */
10107 )
10108{
10109 assert(scip != NULL);
10110 assert(var != NULL);
10111
10113 return FALSE;
10114
10116 return TRUE;
10117
10119 return TRUE;
10120
10121 return FALSE;
10122}
10123
10124/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
10125static
10127 SCIP* scip, /**< SCIP pointer */
10128 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10129 SCIP_EXPR* child, /**< child expression of evenopexpr */
10130 SCIP_CONS* cons, /**< constraint containing expression */
10131 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10132 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10133 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10134 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10135 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10136 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10137 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10138 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10139 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10140 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10141 )
10142{
10143 SCIP_VAR* var;
10144 SCIP_Real constant;
10145 SCIP_Real edgeweight;
10146 int nlocvars;
10147 int nodeidx;
10148 int optype;
10149 int thisopidx;
10150
10151 assert(scip != NULL);
10152 assert(evenopexpr != NULL);
10153 assert(child != NULL);
10154 assert(SCIPisExprVar(scip, child));
10155 assert(cons != NULL);
10156 assert(graph != NULL);
10157 assert(parentidx >= 0);
10158 assert(consvars != NULL);
10159 assert(consvals != NULL);
10160 assert(maxnconsvars != NULL);
10161 assert(success != NULL);
10162
10163 *success = FALSE;
10164
10165 /* check whether child variable is (multi-)aggregated */
10166 var = SCIPgetVarExprVar(child);
10167 (*consvars)[0] = var;
10168 (*consvals)[0] = 1.0;
10169 constant = 0.0;
10170 nlocvars = 1;
10171
10172 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10173 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10174 SCIPconsIsTransformed(cons)) );
10175
10176 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10177 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10178 return SCIP_OKAY;
10179
10180 if( !varIsCenteredAt0(scip, var) )
10181 return SCIP_OKAY;
10182
10183 /* store partial information for gadget */
10184 var = (*consvars)[0];
10185 edgeweight = (*consvals)[0];
10186
10187 /* add gadget to graph for even univariate expression */
10188 *success = TRUE;
10189
10191
10192 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10193 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10194
10196 TRUE, edgeweight) );
10198 TRUE, edgeweight) );
10199
10200 if( hassymval )
10201 {
10202 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10203 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10204 }
10205
10206 return SCIP_OKAY;
10207}
10208
10209/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10210static
10212 SCIP* scip, /**< SCIP pointer */
10213 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10214 SCIP_EXPR* child, /**< child expression of evenopexpr */
10215 SCIP_CONS* cons, /**< constraint containing expression */
10216 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10217 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10218 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10219 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10220 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10221 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10222 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10223 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10224 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10225 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10226 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10227 )
10228{
10229 SCIP_VAR* var;
10230 SCIP_Real constant;
10231 SCIP_Real weight;
10232 int nlocvars;
10233 int nodeidx;
10234 int optype;
10235 int thisopidx;
10236 int i;
10237
10238 assert(scip != NULL);
10239 assert(evenopexpr != NULL);
10240 assert(child != NULL);
10241 assert(SCIPisExprSum(scip, child));
10242 assert(cons != NULL);
10243 assert(graph != NULL);
10244 assert(parentidx >= 0);
10245 assert(consvars != NULL);
10246 assert(consvals != NULL);
10247 assert(maxnconsvars != NULL);
10248 assert(handledexprs != NULL);
10249 assert(success != NULL);
10250
10251 *success = FALSE;
10252
10253 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10254 nlocvars = SCIPexprGetNChildren(child);
10255
10256 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10257
10258 for( i = 0; i < nlocvars; ++i)
10259 {
10260 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10261 {
10262 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10263 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10264 }
10265 else
10266 return SCIP_OKAY;
10267 }
10268 constant = SCIPgetConstantExprSum(child);
10269
10270 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10271 SCIPconsIsTransformed(cons)) );
10272
10273 /* we can only handle the case without constant and two variables with domain centered at origin */
10274 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10275 return SCIP_OKAY;
10276 assert(nlocvars > 0);
10277
10278 var = (*consvars)[0];
10279 if( !varIsCenteredAt0(scip, var) )
10280 return SCIP_OKAY;
10281
10282 if( nlocvars == 2 )
10283 {
10284 var = (*consvars)[1];
10285 if( !varIsCenteredAt0(scip, var) )
10286 return SCIP_OKAY;
10287 }
10288
10289 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10290 *success = TRUE;
10291 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10292 {
10293 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10294 }
10295
10297
10298 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10299 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10300
10301 if( hassymval )
10302 {
10303 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10304 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10305 }
10306
10307 if( nlocvars == 1 )
10308 {
10309 var = (*consvars)[0];
10310 weight = (*consvals)[0];
10311
10313 TRUE, weight) );
10315 TRUE, weight) );
10316 }
10317 else
10318 {
10319 int dummyidx1;
10320 int dummyidx2;
10321
10322 /* add dummy nodes for gadget */
10323 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10324 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10325
10326 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10327 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10328 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10329
10330 /* connect dummy nodes with variables */
10331 for( i = 0; i < 2; ++i)
10332 {
10333 var = (*consvars)[i];
10334 weight = ABS((*consvals)[i]);
10335
10337 TRUE, weight) );
10339 TRUE, weight) );
10340 }
10341 }
10342
10343 return SCIP_OKAY;
10344}
10345
10346/** tries to add gadget for finding signed permutations of even univariate operators
10347 *
10348 * We handle two cases. First, if a univariate operator is even and has a variable
10349 * as child, negating the child is signed permutation. Second, the univariate operator
10350 * is even and has a weighted sum of two variables as child.
10351 */
10352static
10354 SCIP* scip, /**< SCIP pointer */
10355 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10356 SCIP_CONS* cons, /**< constraint containing expression */
10357 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10358 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10359 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10360 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10361 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10362 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10363 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10364 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10365 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10366 )
10367{
10368 SCIP_EXPR* child;
10369 SCIP_Real val = 0.0;
10370 SCIP_Bool hasval = FALSE;
10371
10372 assert(scip != NULL);
10373 assert(expr != NULL);
10374 assert(graph != NULL);
10375 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10376 assert(consvars != NULL);
10377 assert(consvals != NULL);
10378 assert(maxnconsvars != NULL);
10379 assert(*maxnconsvars > 0);
10380 assert(handledexprs != NULL);
10381 assert(success != NULL);
10382
10383 *success = FALSE;
10384
10385 /* ignore variable or value expressions */
10386 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10387 return SCIP_OKAY;
10388 assert(SCIPexprGetNChildren(expr) > 0);
10389
10390 /* ignore operators with too many children */
10391 if( SCIPexprGetNChildren(expr) > 1 )
10392 return SCIP_OKAY;
10393
10394 /* check whether operator is even */
10395 if( !isEvenOperator(scip, expr, &hasval, &val) )
10396 return SCIP_OKAY;
10397
10398 /* we can only treat the operator if its child is a variable or a sum */
10399 child = SCIPexprGetChildren(expr)[0];
10400 if( SCIPisExprVar(scip, child) )
10401 {
10402 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10403 hasval, val, consvars, consvals, maxnconsvars, success) );
10404 }
10405 else if( SCIPisExprSum(scip, child) )
10406 {
10407 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10408 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10409 }
10410
10411 if( *success )
10412 {
10413 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10414 }
10415
10416 return SCIP_OKAY;
10417}
10418
10419/** compares two variable pointers */
10420static
10422{ /*lint --e{715}*/
10423 SCIP_VAR** vars;
10424 SCIP_VAR* var1;
10425 SCIP_VAR* var2;
10426
10427 vars = (SCIP_VAR**) dataptr;
10428
10429 var1 = vars[ind1];
10430 var2 = vars[ind2];
10431 assert(var1 != NULL);
10432 assert(var2 != NULL);
10433
10434 /* sort variables by their unique index */
10435 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10436 return -1;
10437 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10438 return 1;
10439
10440 return 0;
10441}
10442
10443/** gets domain center of a variable which has not semi-infinite domain */
10444static
10446 SCIP* scip, /**< SCIP pointer */
10447 SCIP_VAR* var /**< variable */
10448 )
10449{
10450 SCIP_Real ub;
10451 SCIP_Real lb;
10452
10453 ub = SCIPvarGetUbGlobal(var);
10454 lb = SCIPvarGetLbGlobal(var);
10455
10456 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10457
10458 if ( SCIPisInfinity(scip, ub) )
10459 return 0.0;
10460
10461 return (ub + lb) / 2;
10462}
10463
10464/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10465static
10467 SCIP* scip, /**< SCIP pointer */
10468 SCIP_EXPR* sumexpr, /**< sum expression */
10469 SCIP_CONS* cons, /**< constraint containing the sum expression */
10470 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10471 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10472 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10473 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10474 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10475 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10476 )
10477{
10478 SYM_EXPRDATA* symdata;
10479 SCIP_EXPR** children;
10480 SCIP_EXPR** powexprs;
10481 SCIP_EXPR** prodexprs;
10482 SCIP_EXPR* child;
10483 SCIP_VAR** powvars;
10484 SCIP_VAR** prodvars;
10485 SCIP_VAR* actvar;
10486 SCIP_VAR* actvar2;
10487 SCIP_VAR* var;
10488 SCIP_VAR* var2;
10489 SCIP_Real* sumcoefs;
10490 SCIP_Real constant;
10491 SCIP_Real constant2;
10492 SCIP_Real val;
10493 SCIP_Real val2;
10494 SCIP_Bool* powexprused = NULL;
10495 int* powperm = NULL;
10496 int* prodperm = NULL;
10497 int nchildren;
10498 int nlocvars;
10499 int nodeidx;
10500 int coefnodeidx1;
10501 int coefnodeidx2;
10502 int cnt;
10503 int i;
10504 int j;
10505 int nterms;
10506 int npowexprs = 0;
10507 int nprodexprs = 0;
10508 int powcoef = 0;
10509
10510 assert(scip != NULL);
10511 assert(sumexpr != NULL);
10512 assert(cons != NULL);
10513 assert(SCIPisExprSum(scip, sumexpr));
10514 assert(consvars != NULL);
10515 assert(consvals != NULL);
10516 assert(maxnconsvars != NULL);
10517 assert(*maxnconsvars > 0);
10518 assert(handledexprs != NULL);
10519
10520 /* iterate over sum expression and extract all power and product expressions */
10521 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10522 children = SCIPexprGetChildren(sumexpr);
10523 nchildren = SCIPexprGetNChildren(sumexpr);
10524 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10525 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10526 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10527 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10528
10529 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10530 /** @todo make this work in a more general case */
10531 for( i = 0; i < nchildren; ++i )
10532 {
10533 if( SCIPisExprPower(scip, children[i]) )
10534 {
10535 SCIP_Real exponent;
10536
10537 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10538 if( powcoef == 0 )
10539 {
10540 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10541 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10542 }
10543 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10544 continue;
10545
10546 /* we only store power expressions if their child is a variable */
10547 assert(SCIPexprGetNChildren(children[i]) == 1);
10548 child = SCIPexprGetChildren(children[i])[0];
10549 if( !SCIPisExprVar(scip, child) )
10550 continue;
10551
10552 /* the power is required to be a 2 */
10553 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10554 assert(symdata != NULL);
10555 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10556
10557 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10558 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10559
10560 if( !SCIPisEQ(scip, exponent, 2.0) )
10561 continue;
10562
10563 /* we only store power expressions if the child is not multi-aggregated */
10564 var = SCIPgetVarExprVar(child);
10566 {
10567 powexprs[npowexprs] = children[i];
10568 powvars[npowexprs++] = var;
10569 }
10570 }
10571 else if( SCIPisExprProduct(scip, children[i]) )
10572 {
10573 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10574 if( powcoef == 0 )
10575 {
10576 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10577 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10578 }
10579 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10580 continue;
10581
10582 /* we only store power expressions if they have exactly two children being variables */
10583 if( SCIPexprGetNChildren(children[i]) != 2 )
10584 continue;
10585 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10586 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10587 continue;
10588
10589 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10590 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10591
10592 /* we only store product expressions if the children are not multi-aggregated */
10595 {
10596 prodexprs[nprodexprs] = children[i];
10597 prodvars[nprodexprs++] = var;
10598 prodexprs[nprodexprs] = children[i];
10599 prodvars[nprodexprs++] = var2;
10600 }
10601 }
10602 }
10603
10604 if( npowexprs == 0 || nprodexprs != npowexprs )
10605 goto FREEMEMORY;
10606
10607 /* check whether the power variables and product variables match */
10608 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10609 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10610
10611 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10612 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10613
10614 for( i = 0; i < npowexprs; ++i )
10615 {
10616 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10617 goto FREEMEMORY;
10618 }
10619
10620 /* if we reach this line, the variables match: we have found a potential norm constraint */
10621 assert(npowexprs % 2 == 0);
10622 nterms = npowexprs / 2;
10623 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10624
10625 /* add gadget of each squared difference term */
10626 cnt = 0;
10627 for( i = 0; i < nterms; ++i )
10628 {
10629 SCIP_Bool var1found = FALSE;
10630 SCIP_Bool var2found = FALSE;
10631
10632 (*consvals)[0] = 1.0;
10633 (*consvars)[0] = prodvars[cnt++];
10634 constant = 0.0;
10635 nlocvars = 1;
10636
10638 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10639
10640 if( nlocvars != 1 )
10641 {
10642 ++cnt;
10643 continue;
10644 }
10645 actvar = (*consvars)[0];
10646 val = (*consvals)[0];
10647
10648 (*consvals)[0] = 1.0;
10649 (*consvars)[0] = prodvars[cnt++];
10650 constant2 = 0.0;
10651 nlocvars = 1;
10652
10654 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10655
10656 if( nlocvars != 1 )
10657 continue;
10658 actvar2 = (*consvars)[0];
10659 val2 = (*consvals)[0];
10660
10661 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10662 * cannot be centered at the origin or they are not centered around the same point
10663 */
10664 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10668 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10669 continue;
10670
10671 /* add gadget */
10672 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10673 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10674 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10675
10676 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10677 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10678 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10679 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10680 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10681 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10682 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10683 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10684 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10685 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10686 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10687
10688 /* mark product expression as handled */
10689 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10690
10691 /* find corresponding unused power expressions and mark them as handled */
10692 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10693 {
10694 if( powexprused[j] )
10695 continue;
10696 assert(cnt >= 2);
10697
10698 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10699 {
10700 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10701 powexprused[j] = TRUE;
10702 var1found = TRUE;
10703 }
10704 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10705 {
10706 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10707 powexprused[j] = TRUE;
10708 var2found = TRUE;
10709 }
10710 }
10711 }
10712
10713 FREEMEMORY:
10714 SCIPfreeBufferArrayNull(scip, &powexprused);
10715 SCIPfreeBufferArrayNull(scip, &prodperm);
10716 SCIPfreeBufferArrayNull(scip, &powperm);
10717 SCIPfreeBufferArray(scip, &prodvars);
10718 SCIPfreeBufferArray(scip, &powvars);
10719 SCIPfreeBufferArray(scip, &prodexprs);
10720 SCIPfreeBufferArray(scip, &powexprs);
10721
10722 return SCIP_OKAY;
10723}
10724
10725/** adds symmetry information of constraint to a symmetry detection graph */
10726static
10728 SCIP* scip, /**< SCIP pointer */
10729 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10730 SCIP_CONS* cons, /**< constraint */
10731 SYM_GRAPH* graph, /**< symmetry detection graph */
10732 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10733 )
10734{ /*lint --e{850}*/
10735 SCIP_EXPRITER* it;
10736 SCIP_HASHSET* handledexprs;
10737 SCIP_EXPR* rootexpr;
10738 SCIP_EXPR* expr;
10739 SCIP_VAR** consvars;
10740 SCIP_Real* consvals;
10741 SCIP_Real constant;
10742 SCIP_Real parentcoef = 0.0;
10743 int* openidx;
10744 int maxnopenidx;
10745 int parentidx;
10746 int nconsvars;
10747 int maxnconsvars;
10748 int nlocvars;
10749 int nopenidx = 0;
10750 int consnodeidx;
10751 int nodeidx;
10752 int i;
10753 SCIP_Bool iscolored;
10754 SCIP_Bool hasparentcoef;
10755
10756 assert(scip != NULL);
10757 assert(cons != NULL);
10758 assert(graph != NULL);
10759 assert(success != NULL);
10760
10761 /* store lhs/rhs */
10763 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10764
10765 rootexpr = SCIPgetExprNonlinear(cons);
10766 assert(rootexpr != NULL);
10767
10768 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10769 expr = SCIPgetExprNonlinear(cons);
10770 assert(expr != NULL);
10771
10775
10776 /* find potential number of nodes in graph */
10777 maxnopenidx = 0;
10778 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10779 {
10781 continue;
10782
10783 ++maxnopenidx;
10784 }
10785
10786 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10787
10788 maxnconsvars = SCIPgetNVars(scip);
10789 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10790 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10791
10792 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10793 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10794
10795 /* iterate over expression tree and store nodes/edges */
10796 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10799
10800 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10801 {
10802 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10803 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10804 {
10805 SCIP_EXPR* baseexpr;
10806
10807 baseexpr = expr;
10808 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10809 expr = SCIPexpriterGetNext(it);
10810
10811 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10812
10813 /* leave the expression */
10814 continue;
10815 }
10816
10817 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10819 {
10820 --nopenidx;
10821 continue;
10822 }
10824
10825 /* find parentidx */
10826 if( expr == rootexpr )
10827 parentidx = consnodeidx;
10828 else
10829 {
10830 assert(nopenidx >= 1);
10831 parentidx = openidx[nopenidx - 1];
10832 }
10833
10834 /* possibly find a coefficient assigned to the expression by the parent */
10835 hasparentcoef = FALSE;
10836 if ( expr != rootexpr )
10837 {
10838 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10839 }
10840
10841 /* deal with different kinds of expressions and store them in the symmetry data structure */
10842 if( SCIPisExprVar(scip, expr) )
10843 {
10844 /* needed to correctly reset value when leaving expression */
10845 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10846
10847 openidx[nopenidx++] = -1;
10848
10849 assert(maxnconsvars > 0);
10850 assert(parentidx > 0);
10851
10852 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10853 if( hasparentcoef )
10854 {
10855 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10856
10857 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10858 parentidx = nodeidx;
10859 }
10860
10861 /* connect (aggregation of) variable expression with its parent */
10862 nconsvars = 1;
10863 consvars[0] = SCIPgetVarExprVar(expr);
10864 consvals[0] = 1.0;
10865 constant = 0.0;
10866
10867 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10868 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10869
10870 /* check whether variable is aggregated */
10871 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10872 {
10873 int thisidx;
10874
10875 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10876 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10877
10878 parentidx = thisidx;
10879 }
10880 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10881 nconsvars, constant) );
10882 }
10883 else if( SCIPisExprValue(scip, expr) )
10884 {
10885 assert(parentidx > 0);
10886
10887 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10888
10889 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10890
10891 /* needed to correctly reset value when leaving expression */
10892 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10893
10894 openidx[nopenidx++] = -1;
10895 }
10896 else
10897 {
10898 SCIP_Bool usedefaultgadget = TRUE;
10899
10900 assert(expr == rootexpr || parentidx > 0);
10901 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10902
10903 if( SCIPisExprSum(scip, expr) )
10904 {
10905 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10906 SCIP_EXPR** children;
10907 int sumidx;
10908 int optype;
10909 int childidx;
10910
10911 /* sums are handled by a special gadget */
10912 usedefaultgadget = FALSE;
10913
10914 /* extract all children being variables and compute the sum of active variables expression */
10915 nlocvars = 0;
10916 children = SCIPexprGetChildren(expr);
10917
10918 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10919
10920 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10921 {
10922 if( !SCIPisExprVar(scip, children[childidx]) )
10923 continue;
10924
10925 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10926 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10927
10928 /* store that we have already handled this expression */
10929 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10930 }
10931
10932 constant = SCIPgetConstantExprSum(expr);
10933
10934 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10935 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10936
10938
10939 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10940 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10941
10942 /* add the linear part of the sum */
10943 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10944
10945 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10946
10947 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10948 if( symtype == SYM_SYMTYPE_SIGNPERM )
10949 {
10950 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10951 &consvars, &consvals, &maxnconsvars, handledexprs) );
10952 }
10953
10954 /* store sumidx for children that have not been treated */
10955 openidx[nopenidx++] = sumidx;
10956 }
10957 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10958 {
10959 SCIP_Bool succ;
10960
10961 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10962 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10963
10964 if( succ )
10965 {
10966 usedefaultgadget = FALSE;
10967 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10968 }
10969 }
10970 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10971 {
10972 SCIP_Bool succ;
10973
10974 /* we can find more signed permutations for even univariate operators */
10975 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10976 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10977
10978 if( succ )
10979 {
10980 usedefaultgadget = FALSE;
10981 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10982 }
10983 }
10984
10985 if( usedefaultgadget )
10986 {
10987 int opidx;
10988 int optype;
10989
10991 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10992 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10993
10994 /* possibly add constants of expression */
10996 {
10997 SYM_EXPRDATA* symdata;
10998
10999 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
11000 assert(symdata != NULL);
11001
11002 /* if expression has multiple constants, assign colors to edges to distinguish them */
11003 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
11004 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
11005 {
11006 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
11007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
11008 }
11009
11010 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
11011 }
11012
11013 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
11014
11015 openidx[nopenidx++] = opidx;
11016 }
11017 }
11018 }
11019
11020 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
11021 SCIPfreeBufferArray(scip, &consvals);
11022 SCIPfreeBufferArray(scip, &consvars);
11023 SCIPfreeBufferArray(scip, &openidx);
11024 SCIPfreeExpriter(&it);
11025
11026 *success = TRUE;
11027
11028 return SCIP_OKAY;
11029}
11030
11031/*
11032 * Callback methods of constraint handler
11033 */
11034
11035/** copy method for constraint handler plugins (called when SCIP copies plugins) */
11036static
11037SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
11038{ /*lint --e{715}*/
11039 SCIP_CONSHDLR* targetconshdlr;
11040 SCIP_CONSHDLRDATA* sourceconshdlrdata;
11041 int i;
11042
11043 assert(scip != NULL);
11044 assert(conshdlr != NULL);
11045 assert(valid != NULL);
11046 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11047
11048 /* create basic data of constraint handler and include it to scip */
11050
11051 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11052 assert(targetconshdlr != NULL);
11053 assert(targetconshdlr != conshdlr);
11054
11055 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
11056 assert(sourceconshdlrdata != NULL);
11057
11058 /* copy nonlinear handlers */
11059 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
11060 {
11061 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
11062 }
11063
11064 *valid = TRUE;
11065
11066 return SCIP_OKAY;
11067}
11068
11069/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11070static
11071SCIP_DECL_CONSFREE(consFreeNonlinear)
11072{ /*lint --e{715}*/
11073 SCIP_CONSHDLRDATA* conshdlrdata;
11074 int i;
11075
11076 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11077 assert(conshdlrdata != NULL);
11078
11079 /* free nonlinear handlers */
11080 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11081 {
11082 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11083 assert(conshdlrdata->nlhdlrs[i] == NULL);
11084 }
11085 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11086 conshdlrdata->nlhdlrssize = 0;
11087
11088 /* free upgrade functions */
11089 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11090 {
11091 assert(conshdlrdata->consupgrades[i] != NULL);
11092 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11093 }
11094 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11095
11096 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11097
11098 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11099
11100 if( conshdlrdata->vp_randnumgen != NULL )
11101 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11102
11103 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11104 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11105 {
11106 if( conshdlrdata->vp_lp[i] != NULL )
11107 {
11108 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11109 }
11110 }
11111
11112 assert(conshdlrdata->branchrandnumgen == NULL);
11113
11114 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11115 SCIPhashmapFree(&conshdlrdata->var2expr);
11116
11117 SCIPfreeBlockMemory(scip, &conshdlrdata);
11118 SCIPconshdlrSetData(conshdlr, NULL);
11119
11120 return SCIP_OKAY;
11121}
11122
11123
11124/** initialization method of constraint handler (called after problem was transformed) */
11125static
11126SCIP_DECL_CONSINIT(consInitNonlinear)
11127{ /*lint --e{715}*/
11128 SCIP_CONSHDLRDATA* conshdlrdata;
11129 int i;
11130
11131 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11132 assert(conshdlrdata != NULL);
11133
11134 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11135 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11136 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11137 conshdlrdata->enforound = 1;
11138 /* reset numbering for auxiliary variables */
11139 conshdlrdata->auxvarid = 0;
11140
11141 for( i = 0; i < nconss; ++i )
11142 {
11143 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11144 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11145 }
11146
11147 /* sort nonlinear handlers by detection priority, in decreasing order */
11148 if( conshdlrdata->nnlhdlrs > 1 )
11149 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11150
11151 /* get heuristics for later use */
11152 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11153 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11154
11155 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11156 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11157 {
11158 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11159 }
11160
11161 /* reset statistics in constraint handler */
11162 conshdlrdata->nweaksepa = 0;
11163 conshdlrdata->ntightenlp = 0;
11164 conshdlrdata->ndesperatebranch = 0;
11165 conshdlrdata->ndesperatecutoff = 0;
11166 conshdlrdata->ndesperatetightenlp = 0;
11167 conshdlrdata->nforcelp = 0;
11168 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11169 conshdlrdata->ncanonicalizecalls = 0;
11170
11171#ifdef ENFOLOGFILE
11172 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11173#endif
11174
11175 return SCIP_OKAY;
11176}
11177
11178
11179/** deinitialization method of constraint handler (called before transformed problem is freed) */
11180static
11181SCIP_DECL_CONSEXIT(consExitNonlinear)
11182{ /*lint --e{715}*/
11183 SCIP_CONSHDLRDATA* conshdlrdata;
11184 SCIP_CONS** consssorted;
11185 int i;
11186
11187 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11188 assert(conshdlrdata != NULL);
11189
11190 if( nconss > 0 )
11191 {
11192 /* for better performance of dropVarEvents, we sort by index, descending */
11193 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11194 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11195
11196 for( i = 0; i < nconss; ++i )
11197 {
11198 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11199 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11200 }
11201
11202 SCIPfreeBufferArray(scip, &consssorted);
11203 }
11204
11205 conshdlrdata->subnlpheur = NULL;
11206 conshdlrdata->trysolheur = NULL;
11207
11208 if( conshdlrdata->vp_randnumgen != NULL )
11209 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11210
11211 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11212 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11213 {
11214 if( conshdlrdata->vp_lp[i] != NULL )
11215 {
11216 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11217 }
11218 }
11219
11220 if( conshdlrdata->branchrandnumgen != NULL )
11221 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11222
11223 /* deinitialize nonlinear handlers */
11224 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11225 {
11226 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11227 }
11228
11229 ENFOLOG(
11230 if( enfologfile != NULL )
11231 {
11232 fclose(enfologfile);
11233 enfologfile = NULL;
11234 })
11235
11236 return SCIP_OKAY;
11237}
11238
11239
11240/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11241#ifdef SCIP_DISABLED_CODE
11242static
11244{ /*lint --e{715}*/
11245 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11246 SCIPABORT(); /*lint --e{527}*/
11247
11248 return SCIP_OKAY;
11249}
11250#else
11251#define consInitpreNonlinear NULL
11252#endif
11253
11254
11255/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11256static
11257SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11258{ /*lint --e{715}*/
11259 SCIP_Bool infeasible;
11260
11261 if( nconss == 0 )
11262 return SCIP_OKAY;
11263
11264 /* skip some extra work if already known to be infeasible */
11266 return SCIP_OKAY;
11267
11268 /* simplify constraints and replace common subexpressions */
11269 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11270
11271 /* currently SCIP does not offer to communicate this,
11272 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11273 * or if a constraint expression became constant
11274 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11275 */
11276 /* assert(!infeasible); */
11277
11278 /* tell SCIP that we have something nonlinear */
11280
11281 return SCIP_OKAY;
11282}
11283
11284
11285/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11286static
11287SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11288{ /*lint --e{715}*/
11289 SCIP_CONSHDLRDATA* conshdlrdata;
11290 int i;
11291
11292 /* skip remaining initializations if we have solved already
11293 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11294 * assumes nonempty activities in expressions
11295 */
11296 switch( SCIPgetStatus(scip) )
11297 {
11302 return SCIP_OKAY;
11303 default: ;
11304 } /*lint !e788 */
11305
11306 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11307 assert(conshdlrdata != NULL);
11308
11309 /* reset one of the number of detections counter to count only current round */
11310 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11311 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11312
11313 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11314
11315 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11316 if( conshdlrdata->branchpscostweight > 0.0 )
11317 {
11318 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11319 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11320 {
11321 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11322 SCIPABORT();
11323 return SCIP_INVALIDDATA;
11324 }
11325 }
11326
11327 return SCIP_OKAY;
11328}
11329
11330
11331/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11332static
11333SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11334{ /*lint --e{715}*/
11335 SCIP_CONSHDLRDATA* conshdlrdata;
11336
11337 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11338
11339 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11340 assert(conshdlrdata != NULL);
11341
11342 /* free hash table for bilinear terms */
11343 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11344
11345 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11346 conshdlrdata->checkedvarlocks = FALSE;
11347
11348 /* drop catching new solution event, if catched before */
11349 if( conshdlrdata->newsoleventfilterpos >= 0 )
11350 {
11351 SCIP_EVENTHDLR* eventhdlr;
11352
11353 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11354 assert(eventhdlr != NULL);
11355
11356 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11357 conshdlrdata->newsoleventfilterpos = -1;
11358 }
11359
11360 return SCIP_OKAY;
11361}
11362
11363
11364/** frees specific constraint data */
11365static
11366SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11367{ /*lint --e{715}*/
11368 assert(consdata != NULL);
11369 assert(*consdata != NULL);
11370 assert((*consdata)->expr != NULL);
11371
11372 /* constraint locks should have been removed */
11373 assert((*consdata)->nlockspos == 0);
11374 assert((*consdata)->nlocksneg == 0);
11375
11376 /* free variable expressions */
11377 SCIP_CALL( freeVarExprs(scip, *consdata) );
11378
11379 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11380
11381 /* free nonlinear row representation */
11382 if( (*consdata)->nlrow != NULL )
11383 {
11384 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11385 }
11386
11387 SCIPfreeBlockMemory(scip, consdata);
11388
11389 return SCIP_OKAY;
11390}
11391
11392
11393/** transforms constraint data into data belonging to the transformed problem */
11394static
11395SCIP_DECL_CONSTRANS(consTransNonlinear)
11396{ /*lint --e{715}*/
11397 SCIP_EXPR* targetexpr;
11398 SCIP_CONSDATA* sourcedata;
11399
11400 sourcedata = SCIPconsGetData(sourcecons);
11401 assert(sourcedata != NULL);
11402
11403 /* get a copy of sourceexpr with transformed vars */
11404 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11405 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11406
11407 /* create transformed cons (only captures targetexpr, no need to copy again) */
11408 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11409 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11410 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11411 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11412 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11413 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11414
11415 /* release target expr */
11416 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11417
11418 return SCIP_OKAY;
11419}
11420
11421
11422/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11423static
11424SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11425{ /*lint --e{715}*/
11426 SCIP_CONSHDLRDATA* conshdlrdata;
11427
11428 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11429 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11430 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11431 * for now, there is an assert in detectNlhdlrs to require initial if separated
11432 */
11433 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11434
11435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11436 assert(conshdlrdata != NULL);
11437
11438 /* catch new solution event */
11439 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11440 {
11441 SCIP_EVENTHDLR* eventhdlr;
11442
11443 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11444 assert(eventhdlr != NULL);
11445
11446 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11447 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11448 }
11449
11450 /* collect all bilinear terms for which an auxvar is present
11451 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11452 * addition (and removal?) of constraints during solve
11453 * this is typically the majority of constraints, but the method should be made more flexible
11454 */
11455 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11456
11457 return SCIP_OKAY;
11458}
11459
11460
11461/** separation method of constraint handler for LP solutions */
11462static
11463SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11464{ /*lint --e{715}*/
11465 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11466
11467 return SCIP_OKAY;
11468}
11469
11470
11471/** separation method of constraint handler for arbitrary primal solutions */
11472static
11473SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11474{ /*lint --e{715}*/
11475 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11476
11477 return SCIP_OKAY;
11478}
11479
11480
11481/** constraint enforcing method of constraint handler for LP solutions */
11482static
11483SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11484{ /*lint --e{715}*/
11485 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11486
11487 return SCIP_OKAY;
11488}
11489
11490
11491/** constraint enforcing method of constraint handler for relaxation solutions */
11492static
11493SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11494{ /*lint --e{715}*/
11495 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11496
11497 return SCIP_OKAY;
11498}
11499
11500
11501/** constraint enforcing method of constraint handler for pseudo solutions */
11502static
11503SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11504{ /*lint --e{715}*/
11505 SCIP_RESULT propresult;
11506 SCIP_Longint soltag;
11507 int nchgbds;
11508 int nnotify;
11509 int c;
11510
11511 soltag = SCIPgetExprNewSoltag(scip);
11512
11514 for( c = 0; c < nconss; ++c )
11515 {
11516 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11517
11518 if( isConsViolated(scip, conss[c]) )
11520 }
11521
11522 if( *result == SCIP_FEASIBLE )
11523 return SCIP_OKAY;
11524
11525 /* try to propagate
11526 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11527 */
11528 nchgbds = 0;
11529 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11530
11531 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11532 {
11533 *result = propresult;
11534 return SCIP_OKAY;
11535 }
11536
11537 /* register all unfixed variables in all violated constraints as branching candidates */
11538 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11539 if( nnotify > 0 )
11540 {
11541 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11542
11543 return SCIP_OKAY;
11544 }
11545
11546 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11548 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11549
11550 return SCIP_OKAY;
11551}
11552
11553
11554/** feasibility check method of constraint handler for integral solutions */
11555static
11556SCIP_DECL_CONSCHECK(consCheckNonlinear)
11557{ /*lint --e{715}*/
11558 SCIP_CONSHDLRDATA* conshdlrdata;
11559 SCIP_CONSDATA* consdata;
11560 SCIP_Real maxviol;
11561 SCIP_Bool maypropfeasible;
11562 SCIP_Longint soltag;
11563 int c;
11564
11565 assert(scip != NULL);
11566 assert(conshdlr != NULL);
11567 assert(conss != NULL || nconss == 0);
11568 assert(result != NULL);
11569
11570 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11571 assert(conshdlrdata != NULL);
11572
11574 soltag = SCIPgetExprNewSoltag(scip);
11575 maxviol = 0.0;
11576 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11578
11580 maypropfeasible = FALSE;
11581
11582 /* check nonlinear constraints for feasibility */
11583 for( c = 0; c < nconss; ++c )
11584 {
11585 SCIP_Real absviol;
11586 SCIP_Real relviol;
11587
11588 assert(conss != NULL && conss[c] != NULL);
11589 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11590
11591 absviol = getConsAbsViolation(conss[c]);
11592 SCIP_CALL( getConsRelViolation(scip, conss[c], &relviol, sol, soltag) );
11593 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
11594
11595 if( absviol > SCIPfeastol(scip) )
11596 {
11598 maxviol = MAX(maxviol, absviol);
11599
11600 consdata = SCIPconsGetData(conss[c]);
11601 assert(consdata != NULL);
11602
11603 /* print reason for infeasibility */
11604 if( printreason )
11605 {
11606 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11607 SCIPinfoMessage(scip, NULL, ";\n");
11608
11609 if( consdata->lhsviol > SCIPfeastol(scip) )
11610 {
11611 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11612 }
11613 if( consdata->rhsviol > SCIPfeastol(scip) )
11614 {
11615 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11616 }
11617 }
11618 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11619 {
11620 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11621 return SCIP_OKAY;
11622 }
11623
11624 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11625 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11626 maypropfeasible = FALSE;
11627
11628 if( maypropfeasible )
11629 {
11630 if( consdata->lhsviol > SCIPfeastol(scip) )
11631 {
11632 /* check if there is a variable which may help to get the left hand side satisfied
11633 * if there is no such variable, then we cannot get feasible
11634 */
11635 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11636 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11637 maypropfeasible = FALSE;
11638 }
11639 else
11640 {
11641 assert(consdata->rhsviol > SCIPfeastol(scip));
11642 /* check if there is a variable which may help to get the right hand side satisfied
11643 * if there is no such variable, then we cannot get feasible
11644 */
11645 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11646 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11647 maypropfeasible = FALSE;
11648 }
11649 }
11650 }
11651 }
11652
11653 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11654 {
11655 SCIP_Bool success;
11656
11657 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11658
11659 /* do not pass solution to NLP heuristic if we made it feasible this way */
11660 if( success )
11661 return SCIP_OKAY;
11662 }
11663
11664 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11665 {
11666 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11667 }
11668
11669 return SCIP_OKAY;
11670}
11671
11672
11673/** domain propagation method of constraint handler */
11674static
11675SCIP_DECL_CONSPROP(consPropNonlinear)
11676{ /*lint --e{715}*/
11677 int nchgbds = 0;
11678
11679 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11680 assert(nchgbds >= 0);
11681
11682 /* TODO would it make sense to check for redundant constraints? */
11683
11684 return SCIP_OKAY;
11685}
11686
11687
11688/** presolving method of constraint handler */
11689static
11690SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11691{ /*lint --e{715}*/
11692 SCIP_CONSHDLRDATA* conshdlrdata;
11693 SCIP_Bool infeasible;
11694 int c;
11695
11697
11698 if( nconss == 0 )
11699 {
11701 return SCIP_OKAY;
11702 }
11703
11704 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11705 assert(conshdlrdata != NULL);
11706
11707 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11708 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11709 if( infeasible )
11710 {
11712 return SCIP_OKAY;
11713 }
11714
11715 /* merge constraints with the same root expression */
11716 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11717 {
11718 SCIP_Bool success;
11719
11720 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11721 if( success )
11723 }
11724
11725 /* propagate constraints */
11726 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11727 if( *result == SCIP_CUTOFF )
11728 return SCIP_OKAY;
11729
11730 /* propagate function domains (TODO integrate with simplify?) */
11731 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11732 {
11733 SCIP_RESULT localresult;
11734 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11735 if( localresult == SCIP_CUTOFF )
11736 {
11738 return SCIP_OKAY;
11739 }
11740 if( localresult == SCIP_REDUCEDDOM )
11742 }
11743
11744 /* check for redundant constraints, remove constraints that are a value expression */
11745 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11746 if( infeasible )
11747 {
11749 return SCIP_OKAY;
11750 }
11751
11752 /* try to upgrade constraints */
11753 for( c = 0; c < nconss; ++c )
11754 {
11755 SCIP_Bool upgraded;
11756
11757 /* skip inactive and deleted constraints */
11758 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11759 continue;
11760
11761 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11762 }
11763
11764 /* try to change continuous variables that appear linearly to be implicit integer */
11765 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11766 {
11767 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11768
11769 if( infeasible )
11770 {
11771 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11773 return SCIP_OKAY;
11774 }
11775 }
11776
11777 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11779 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11780 {
11781 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11782 * constraints multiple times
11783 */
11784 conshdlrdata->checkedvarlocks = TRUE;
11785
11786 for( c = 0; c < nconss; ++c )
11787 {
11788 int tmpnchgvartypes = 0;
11789 int tmpnaddconss = 0;
11790
11791 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11792 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11793 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11794
11795 if( infeasible )
11796 {
11797 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11799 return SCIP_OKAY;
11800 }
11801
11802 (*nchgvartypes) += tmpnchgvartypes;
11803 (*naddconss) += tmpnaddconss;
11804 }
11805 }
11806
11807 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11809 else
11811
11812 return SCIP_OKAY;
11813}
11814
11815
11816/** propagation conflict resolving method of constraint handler */
11817#ifdef SCIP_DISABLED_CODE
11818static
11820{ /*lint --e{715}*/
11821 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11822 SCIPABORT(); /*lint --e{527}*/
11823
11824 return SCIP_OKAY;
11825}
11826#else
11827#define consRespropNonlinear NULL
11828#endif
11829
11830
11831/** variable rounding lock method of constraint handler */
11832static
11833SCIP_DECL_CONSLOCK(consLockNonlinear)
11834{ /*lint --e{715}*/
11835 SCIP_CONSDATA* consdata;
11836 SCIP_EXPR_OWNERDATA* ownerdata;
11837 SCIP_Bool reinitsolve = FALSE;
11838
11839 assert(conshdlr != NULL);
11840 assert(cons != NULL);
11841
11842 consdata = SCIPconsGetData(cons);
11843 assert(consdata != NULL);
11844 assert(consdata->expr != NULL);
11845
11846 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11847
11848 /* check whether we need to initSolve again because
11849 * - we have enfo initialized (nenfos >= 0)
11850 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11851 */
11852 if( ownerdata->nenfos >= 0 )
11853 {
11854 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11855 reinitsolve = TRUE;
11856 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11857 reinitsolve = TRUE;
11858 }
11859
11860 if( reinitsolve )
11861 {
11862 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11863 }
11864
11865 /* add locks */
11866 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11867
11868 if( reinitsolve )
11869 {
11870 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11871 }
11872
11873 return SCIP_OKAY;
11874}
11875
11876
11877/** constraint activation notification method of constraint handler */
11878static
11879SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11880{ /*lint --e{715}*/
11881 SCIP_CONSDATA* consdata;
11882 SCIP_Bool infeasible = FALSE;
11883
11884 consdata = SCIPconsGetData(cons);
11885 assert(consdata != NULL);
11886
11887 /* simplify root expression if the constraint has been added after presolving */
11889 {
11890 SCIP_Bool replacedroot;
11891
11892 if( !consdata->issimplified )
11893 {
11894 SCIP_EXPR* simplified;
11895 SCIP_Bool changed;
11896
11897 /* simplify constraint */
11898 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11899 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11900 assert(simplified != NULL);
11901 consdata->expr = simplified;
11902 consdata->issimplified = TRUE;
11903 }
11904
11905 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11906 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11907 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11908
11909 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11910 {
11911 SCIP_CONSHDLRDATA* conshdlrdata;
11912 SCIP_EXPRITER* it;
11913 SCIP_EXPR* expr;
11914
11915 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11916 assert(conshdlrdata != NULL);
11917
11919 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11921 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11922 {
11923 SCIP_EXPR* child;
11924 SCIP_EXPR* hashmapexpr;
11925
11926 child = SCIPexpriterGetChildExprDFS(it);
11927 if( !SCIPisExprVar(scip, child) )
11928 continue;
11929
11930 /* check which expression is stored in the hashmap for the var of child */
11931 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11932 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11933 if( hashmapexpr != NULL && hashmapexpr != child )
11934 {
11936 }
11937 }
11938 SCIPfreeExpriter(&it);
11939 }
11940 }
11941
11942 /* store variable expressions */
11944 {
11945 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11946 }
11947
11948 /* add manually locks to constraints that are not checked for feasibility */
11949 if( !SCIPconsIsChecked(cons) )
11950 {
11951 assert(consdata->nlockspos == 0);
11952 assert(consdata->nlocksneg == 0);
11953
11954 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11955 }
11956
11957 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11958 {
11959 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11960 }
11961
11962 /* TODO deal with infeasibility */
11963 assert(!infeasible);
11964
11965 return SCIP_OKAY;
11966}
11967
11968
11969/** constraint deactivation notification method of constraint handler */
11970static
11971SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11972{ /*lint --e{715}*/
11973 SCIP_CONSHDLRDATA* conshdlrdata;
11974
11975 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11976 assert(conshdlrdata != NULL);
11977
11979 {
11980 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11981 }
11982
11984 {
11985 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11987 }
11988
11989 /* remove locks that have been added in consActiveExpr() */
11990 if( !SCIPconsIsChecked(cons) )
11991 {
11992 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11993
11994 assert(SCIPconsGetData(cons)->nlockspos == 0);
11995 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11996 }
11997
11998 return SCIP_OKAY;
11999}
12000
12001
12002/** constraint enabling notification method of constraint handler */
12003static
12004SCIP_DECL_CONSENABLE(consEnableNonlinear)
12005{ /*lint --e{715}*/
12006 SCIP_CONSHDLRDATA* conshdlrdata;
12007
12008 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12009 assert(conshdlrdata != NULL);
12010
12012 {
12013 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12014 }
12015
12016 return SCIP_OKAY;
12017}
12018
12019
12020/** constraint disabling notification method of constraint handler */
12021static
12022SCIP_DECL_CONSDISABLE(consDisableNonlinear)
12023{ /*lint --e{715}*/
12024 SCIP_CONSHDLRDATA* conshdlrdata;
12025
12026 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12027 assert(conshdlrdata != NULL);
12028
12030 {
12031 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12032 }
12033
12034 return SCIP_OKAY;
12035}
12036
12037/** variable deletion of constraint handler */
12038#ifdef SCIP_DISABLED_CODE
12039static
12041{ /*lint --e{715}*/
12042 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12043 SCIPABORT(); /*lint --e{527}*/
12044
12045 return SCIP_OKAY;
12046}
12047#else
12048#define consDelvarsNonlinear NULL
12049#endif
12050
12051
12052/** constraint display method of constraint handler */
12053static
12054SCIP_DECL_CONSPRINT(consPrintNonlinear)
12055{ /*lint --e{715}*/
12056 SCIP_CONSDATA* consdata;
12057
12058 consdata = SCIPconsGetData(cons);
12059 assert(consdata != NULL);
12060 assert(consdata->expr != NULL);
12061
12062 /* print left hand side for ranged constraints */
12063 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12064 {
12065 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12066 }
12067
12068 /* print expression */
12069 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
12070
12071 /* print right hand side */
12072 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12073 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12074 else if( !SCIPisInfinity(scip, consdata->rhs) )
12075 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12076 else if( !SCIPisInfinity(scip, -consdata->lhs) )
12077 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12078 else
12079 SCIPinfoMessage(scip, file, " [free]");
12080
12081 return SCIP_OKAY;
12082}
12083
12084
12085/** constraint copying method of constraint handler */
12086static
12087SCIP_DECL_CONSCOPY(consCopyNonlinear)
12088{ /*lint --e{715}*/
12089 SCIP_CONSHDLR* targetconshdlr;
12090 SCIP_EXPR* targetexpr = NULL;
12091 SCIP_CONSDATA* sourcedata;
12092
12093 assert(cons != NULL);
12094
12095 sourcedata = SCIPconsGetData(sourcecons);
12096 assert(sourcedata != NULL);
12097
12098 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12099 assert(targetconshdlr != NULL);
12100
12101 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12102
12103 if( targetexpr == NULL )
12104 *valid = FALSE;
12105
12106 *cons = NULL;
12107 if( *valid )
12108 {
12109 /* create copy (only capture targetexpr, no need to copy again) */
12110 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12111 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12112 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12113 }
12114
12115 if( targetexpr != NULL )
12116 {
12117 /* release target expr */
12118 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12119 }
12120
12121 return SCIP_OKAY;
12122}
12123
12124
12125/** constraint parsing method of constraint handler */
12126static
12127SCIP_DECL_CONSPARSE(consParseNonlinear)
12128{ /*lint --e{715}*/
12129 SCIP_Real lhs;
12130 SCIP_Real rhs;
12131 char* endptr;
12132 SCIP_EXPR* consexprtree;
12133
12134 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12135
12136 assert(scip != NULL);
12137 assert(success != NULL);
12138 assert(str != NULL);
12139 assert(name != NULL);
12140 assert(cons != NULL);
12141
12142 *success = FALSE;
12143
12144 /* return if string empty */
12145 if( !*str )
12146 return SCIP_OKAY;
12147
12148 endptr = (char*)str;
12149
12150 /* set left and right hand side to their default values */
12151 lhs = -SCIPinfinity(scip);
12152 rhs = SCIPinfinity(scip);
12153
12154 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12155
12156 /* check for left hand side */
12157 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12158 {
12159 /* there is a number coming, maybe it is a left-hand-side */
12160 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12161 {
12162 SCIPerrorMessage("error parsing number from <%s>\n", str);
12163 return SCIP_READERROR;
12164 }
12165
12166 /* ignore whitespace */
12167 SCIP_CALL( SCIPskipSpace(&endptr) );
12168
12169 if( endptr[0] != '<' || endptr[1] != '=' )
12170 {
12171 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12172 lhs = -SCIPinfinity(scip);
12173 }
12174 else
12175 {
12176 /* it was indeed a left-hand-side, so continue parsing after it */
12177 str = endptr + 2;
12178
12179 /* ignore whitespace */
12180 SCIP_CALL( SCIPskipSpace((char**)&str) );
12181 }
12182 }
12183
12184 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12185
12186 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12187 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12188
12189 /* check for left or right hand side */
12190 SCIP_CALL( SCIPskipSpace((char**)&str) );
12191
12192 /* check for free constraint */
12193 if( strncmp(str, "[free]", 6) == 0 )
12194 {
12195 if( !SCIPisInfinity(scip, -lhs) )
12196 {
12197 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12198 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12199 return SCIP_OKAY;
12200 }
12201 *success = TRUE;
12202 }
12203 else
12204 {
12205 switch( *str )
12206 {
12207 case '<':
12208 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12209 break;
12210 case '=':
12211 if( !SCIPisInfinity(scip, -lhs) )
12212 {
12213 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12214 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12215 return SCIP_OKAY;
12216 }
12217 else
12218 {
12219 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12220 lhs = rhs;
12221 }
12222 break;
12223 case '>':
12224 if( !SCIPisInfinity(scip, -lhs) )
12225 {
12226 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12227 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12228 return SCIP_OKAY;
12229 }
12230 else
12231 {
12232 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12233 break;
12234 }
12235 case '\0':
12236 *success = TRUE;
12237 break;
12238 default:
12239 SCIPerrorMessage("unexpected character %c\n", *str);
12240 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12241 return SCIP_OKAY;
12242 }
12243 }
12244
12245 /* create constraint */
12246 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12247 consexprtree, lhs, rhs, FALSE,
12248 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12249 assert(*cons != NULL);
12250
12251 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12252
12253 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12254
12255 return SCIP_OKAY;
12256}
12257
12258
12259/** constraint method of constraint handler which returns the variables (if possible) */
12260static
12261SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12262{ /*lint --e{715}*/
12263 SCIP_CONSDATA* consdata;
12264 int i;
12265
12266 consdata = SCIPconsGetData(cons);
12267 assert(consdata != NULL);
12268
12269 /* store variable expressions if not done so far */
12270 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12271
12272 /* check whether array is too small in order to store all variables */
12273 if( varssize < consdata->nvarexprs )
12274 {
12275 *success = FALSE;
12276 return SCIP_OKAY;
12277 }
12278
12279 for( i = 0; i < consdata->nvarexprs; ++i )
12280 {
12281 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12282 assert(vars[i] != NULL);
12283 }
12284
12285 *success = TRUE;
12286
12287 return SCIP_OKAY;
12288}
12289
12290/** constraint method of constraint handler which returns the number of variables (if possible) */
12291static
12292SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12293{ /*lint --e{715}*/
12294 SCIP_CONSDATA* consdata;
12295
12296 consdata = SCIPconsGetData(cons);
12297 assert(consdata != NULL);
12298
12299 /* store variable expressions if not done so far */
12300 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12301
12302 *nvars = consdata->nvarexprs;
12303 *success = TRUE;
12304
12305 return SCIP_OKAY;
12306}
12307
12308/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12309#ifdef SCIP_DISABLED_CODE
12310static
12312{ /*lint --e{715}*/
12313 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12314 SCIPABORT(); /*lint --e{527}*/
12315
12316 return SCIP_OKAY;
12317}
12318#else
12319#define consGetDiveBdChgsNonlinear NULL
12320#endif
12321
12322/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12323static
12324SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12325{ /*lint --e{715}*/
12326 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12327
12328 return SCIP_OKAY;
12329}
12330
12331/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12332static
12333SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12334{ /*lint --e{715}*/
12335 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12336
12337 return SCIP_OKAY;
12338}
12339
12340/** output method of cons_nonlinear statistics table to output file stream 'file' */
12341static
12342SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12343{ /*lint --e{715}*/
12344 SCIP_CONSHDLR* conshdlr;
12345 SCIP_CONSHDLRDATA* conshdlrdata;
12346
12347 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12348 assert(conshdlr != NULL);
12349
12350 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12351 assert(conshdlrdata != NULL);
12352
12353 /* print statistics for constraint handler */
12354 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12355 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12356 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12357 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12358 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12359 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12360 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12361 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12362 SCIPinfoMessage(scip, file, "\n");
12363 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12364 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12365 SCIPinfoMessage(scip, file, "\n");
12366
12367 return SCIP_OKAY;
12368}
12369
12370/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
12371static
12372SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
12373{
12374 SCIP_CONSHDLR* conshdlr;
12375 SCIP_CONSHDLRDATA* conshdlrdata;
12376
12377 assert(scip != NULL);
12378 assert(table != NULL);
12379 assert(datatree != NULL);
12380
12381 /* Find the constraint handler */
12382 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12383 assert(conshdlr != NULL);
12384
12385 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12386 assert(conshdlrdata != NULL);
12387
12388 /* Insert statistics */
12389 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
12390 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
12391 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
12392 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
12393 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
12394 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
12395 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
12396
12397 return SCIP_OKAY;
12398}
12399
12400/** output method of nlhdlr statistics table to output file stream 'file' */
12401static
12402SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12403{ /*lint --e{715}*/
12404 SCIP_CONSHDLR* conshdlr;
12405 SCIP_CONSHDLRDATA* conshdlrdata;
12406
12407 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12408 assert(conshdlr != NULL);
12409
12410 /* skip nlhdlr table if there never were active nonlinear constraints */
12411 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12412 return SCIP_OKAY;
12413
12414 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12415 assert(conshdlrdata != NULL);
12416
12417 /* print statistics for nonlinear handlers */
12418 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12419
12420 return SCIP_OKAY;
12421}
12422
12423/** collect method of nlhdlr statistics table to SCIP_DATATREE */
12424static
12425SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
12426{ /*lint --e{715}*/
12427 SCIP_CONSHDLR* conshdlr;
12428 SCIP_CONSHDLRDATA* conshdlrdata;
12429
12430 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12431 assert(conshdlr != NULL);
12432
12433 /* skip nlhdlr table if there never were active nonlinear constraints */
12434 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12435 return SCIP_OKAY;
12436
12437 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12438 assert(conshdlrdata != NULL);
12439
12440 /* collect statistics for nonlinear handlers */
12441 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
12442
12443 return SCIP_OKAY;
12444}
12445
12446/** execution method of display nlhdlrs dialog */
12447static
12448SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12449{ /*lint --e{715}*/
12450 SCIP_CONSHDLR* conshdlr;
12451 SCIP_CONSHDLRDATA* conshdlrdata;
12452 int i;
12453
12454 /* add dialog to history of dialogs that have been executed */
12455 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12456
12457 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12458 assert(conshdlr != NULL);
12459
12460 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12461 assert(conshdlrdata != NULL);
12462
12463 /* display list of nonlinear handler */
12464 SCIPdialogMessage(scip, NULL, "\n");
12465 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12466 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12467 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12468 {
12469 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12470 assert(nlhdlr != NULL);
12471
12472 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12473 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12476 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12477 SCIPdialogMessage(scip, NULL, "\n");
12478 }
12479 SCIPdialogMessage(scip, NULL, "\n");
12480
12481 /* next dialog will be root dialog again */
12482 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12483
12484 return SCIP_OKAY;
12485}
12486
12487/*
12488 * constraint handler specific interface methods
12489 */
12490
12491/** creates the handler for nonlinear constraints and includes it in SCIP */
12493 SCIP* scip /**< SCIP data structure */
12494 )
12495{
12496 SCIP_CONSHDLRDATA* conshdlrdata;
12497 SCIP_DIALOG* parentdialog;
12498
12499 /* create nonlinear constraint handler data */
12500 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12501 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12502 conshdlrdata->curboundstag = 1;
12503 conshdlrdata->lastboundrelax = 1;
12504 conshdlrdata->curpropboundstag = 1;
12505 conshdlrdata->newsoleventfilterpos = -1;
12506 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12507 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12508 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12509
12510 /* include constraint handler */
12516 conshdlrCopyNonlinear,
12517 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12518 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12519 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12520 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12521 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12522 consActiveNonlinear, consDeactiveNonlinear,
12523 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12524 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12525 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12526 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12527
12528 /* add nonlinear constraint handler parameters */
12529 /* TODO organize into more subcategories */
12530 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12531 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12532 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12533
12534 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12535 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12536 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12537
12538 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12539 "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",
12540 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12541
12542 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12543 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12544 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12545
12546 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12547 "by how much to relax constraint sides during bound tightening",
12548 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12549
12550 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12551 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12552 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12553
12554 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12555 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12556 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12557
12558 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12559 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12560 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12561
12562 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12563 "maximal number of auxiliary expressions per bilinear term",
12564 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12565
12566 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12567 "whether to reformulate products of binary variables during presolving",
12568 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12569
12570 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12571 "whether to use the AND constraint handler for reformulating binary products",
12572 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12573
12574 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12575 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12576 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12577
12578 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12579 "whether to forbid multiaggregation of nonlinear variables",
12580 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12581
12582 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12583 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12584 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12585
12586 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12587 "whether to (re)run propagation in enforcement",
12588 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12589
12590 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12591 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12592 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12593
12594 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12595 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12596 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12597
12598 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12599 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12600 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12601
12602 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12603 "whether to force \"strong\" cuts in enforcement",
12604 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12605
12606 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12607 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12608 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12609
12610 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12611 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12612 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12613
12614 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12615 "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",
12616 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12617
12618 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12619 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12620 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12621
12622 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12623 "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)",
12624 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12625
12626 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12627 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12628 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12629
12630 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12631 "whether to use external branching candidates and branching rules for branching",
12632 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12633
12634 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12635 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12636 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12637
12638 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12639 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12640 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12641
12642 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12643 "weight by how much to consider the violation assigned to a variable for its branching score",
12644 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12645
12646 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12647 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12648 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12649
12650 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12651 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12652 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12653
12654 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12655 "weight by how much to consider the pseudo cost of a variable for its branching score",
12656 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12657
12658 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12659 "weight by how much to consider the domain width in branching score",
12660 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12661
12662 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12663 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12664 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12665
12666 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12667 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12668 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12669
12670 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12671 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12672 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12673
12674 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12675 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12676 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12677
12678 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12679 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12680 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12681
12682 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12683 "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)",
12684 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12685
12686 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12687 "whether to assume that any constraint in the presolved problem is convex",
12688 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
12689
12690 /* include handler for bound change events */
12691 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12692 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12693 assert(conshdlrdata->eventhdlr != NULL);
12694
12695 /* include tables for statistics */
12698 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
12700
12703 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
12705
12706 /* create, include, and release display nlhdlrs dialog */
12707 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12708 {
12709 SCIP_DIALOG* dialog;
12710
12711 assert(parentdialog != NULL);
12712 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12713
12715 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12717 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12718 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12719 }
12720
12721 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12722 processNewSolutionEvent, NULL) );
12723
12724 return SCIP_OKAY;
12725}
12726
12727/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12729 SCIP* scip, /**< SCIP data structure */
12730 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12731 int priority, /**< priority of upgrading method */
12732 SCIP_Bool active, /**< should the upgrading method by active by default? */
12733 const char* conshdlrname /**< name of the constraint handler */
12734 )
12735{
12736 SCIP_CONSHDLR* conshdlr;
12737 SCIP_CONSHDLRDATA* conshdlrdata;
12738 CONSUPGRADE* consupgrade;
12740 char paramdesc[SCIP_MAXSTRLEN];
12741 int i;
12742
12743 assert(conshdlrname != NULL );
12744 assert(nlconsupgd != NULL);
12745
12746 /* find the nonlinear constraint handler */
12747 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12748 if( conshdlr == NULL )
12749 {
12750 SCIPerrorMessage("nonlinear constraint handler not found\n");
12751 return SCIP_PLUGINNOTFOUND;
12752 }
12753
12754 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12755 assert(conshdlrdata != NULL);
12756
12757 /* check whether upgrade method exists already */
12758 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12759 {
12760 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12761 {
12762#ifdef SCIP_DEBUG
12763 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12764#endif
12765 return SCIP_OKAY;
12766 }
12767 }
12768
12769 /* create a nonlinear constraint upgrade data object */
12770 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12771 consupgrade->consupgd = nlconsupgd;
12772 consupgrade->priority = priority;
12773 consupgrade->active = active;
12774
12775 /* insert nonlinear constraint upgrade method into constraint handler data */
12776 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12777 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12778
12779 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12780 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12781 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12782 conshdlrdata->consupgrades[i] = consupgrade;
12783 conshdlrdata->nconsupgrades++;
12784
12785 /* adds parameter to turn on and off the upgrading step */
12786 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12787 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12789 paramname, paramdesc,
12790 &consupgrade->active, FALSE, active, NULL, NULL) );
12791
12792 return SCIP_OKAY;
12793}
12794
12795/** creates and captures a nonlinear constraint
12796 *
12797 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12798 */
12800 SCIP* scip, /**< SCIP data structure */
12801 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12802 const char* name, /**< name of constraint */
12803 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12804 SCIP_Real lhs, /**< left hand side of constraint */
12805 SCIP_Real rhs, /**< right hand side of constraint */
12806 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12807 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12808 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12809 * Usually set to TRUE. */
12810 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12811 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12812 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12813 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12814 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12815 * Usually set to TRUE. */
12816 SCIP_Bool local, /**< is constraint only valid locally?
12817 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12818 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12819 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12820 * adds coefficients to this constraint. */
12821 SCIP_Bool dynamic, /**< is constraint subject to aging?
12822 * Usually set to FALSE. Set to TRUE for own cuts which
12823 * are separated as constraints. */
12824 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12825 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12826 )
12827{
12828 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12829 SCIP_CONSHDLR* conshdlr;
12830
12831 /* find the nonlinear constraint handler */
12832 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12833 if( conshdlr == NULL )
12834 {
12835 SCIPerrorMessage("nonlinear constraint handler not found\n");
12836 return SCIP_PLUGINNOTFOUND;
12837 }
12838
12839 /* create constraint */
12840 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12841 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12842
12843 return SCIP_OKAY;
12844}
12845
12846/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12847 *
12848 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12849 *
12850 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12851 *
12852 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12853 */
12855 SCIP* scip, /**< SCIP data structure */
12856 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12857 const char* name, /**< name of constraint */
12858 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12859 SCIP_Real lhs, /**< left hand side of constraint */
12860 SCIP_Real rhs /**< right hand side of constraint */
12861 )
12862{
12863 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12865
12866 return SCIP_OKAY;
12867}
12868
12869/** creates and captures a quadratic nonlinear constraint
12870 *
12871 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12872 */
12874 SCIP* scip, /**< SCIP data structure */
12875 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12876 const char* name, /**< name of constraint */
12877 int nlinvars, /**< number of linear terms */
12878 SCIP_VAR** linvars, /**< array with variables in linear part */
12879 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12880 int nquadterms, /**< number of quadratic terms */
12881 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12882 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12883 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12884 SCIP_Real lhs, /**< left hand side of quadratic equation */
12885 SCIP_Real rhs, /**< right hand side of quadratic equation */
12886 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12887 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12888 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12889 * Usually set to TRUE. */
12890 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12891 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12892 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12893 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12894 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12895 * Usually set to TRUE. */
12896 SCIP_Bool local, /**< is constraint only valid locally?
12897 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12898 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12899 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12900 * adds coefficients to this constraint. */
12901 SCIP_Bool dynamic, /**< is constraint subject to aging?
12902 * Usually set to FALSE. Set to TRUE for own cuts which
12903 * are separated as constraints. */
12904 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12905 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12906 )
12907{
12908 SCIP_CONSHDLR* conshdlr;
12909 SCIP_EXPR* expr;
12910 int i;
12911
12912 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12913 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12914
12915 /* check data for infinity or nan values */
12916 for( i = 0; i < nlinvars; ++i )
12917 {
12918 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
12919 {
12920 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
12921 return SCIP_INVALIDDATA;
12922 }
12923 }
12924 for( i = 0; i < nquadterms; ++i )
12925 {
12926 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
12927 {
12928 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
12929 return SCIP_INVALIDDATA;
12930 }
12931 }
12932 /* lhs and rhs will be checked in createCons */
12933
12934 /* get nonlinear constraint handler */
12935 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12936 if( conshdlr == NULL )
12937 {
12938 SCIPerrorMessage("nonlinear constraint handler not found\n");
12939 return SCIP_PLUGINNOTFOUND;
12940 }
12941
12942 /* create quadratic expression */
12943 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12944 assert(expr != NULL);
12945
12946 /* create nonlinear constraint */
12947 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12948 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12949
12950 /* release quadratic expression (captured by constraint now) */
12951 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12952
12953 return SCIP_OKAY;
12954}
12955
12956/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12957 *
12958 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12959 *
12960 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12961 *
12962 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12963 */
12965 SCIP* scip, /**< SCIP data structure */
12966 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12967 const char* name, /**< name of constraint */
12968 int nlinvars, /**< number of linear terms */
12969 SCIP_VAR** linvars, /**< array with variables in linear part */
12970 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12971 int nquadterms, /**< number of quadratic terms */
12972 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12973 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12974 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12975 SCIP_Real lhs, /**< left hand side of quadratic equation */
12976 SCIP_Real rhs /**< right hand side of quadratic equation */
12977 )
12978{
12979 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12981
12982 return SCIP_OKAY;
12983}
12984
12985/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12986 *
12987 * \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$
12988 *
12989 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12990 */
12992 SCIP* scip, /**< SCIP data structure */
12993 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12994 const char* name, /**< name of constraint */
12995 int nvars, /**< number of variables on left hand side of constraint (n) */
12996 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12997 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12998 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12999 SCIP_Real constant, /**< constant on left hand side (gamma) */
13000 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
13001 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
13002 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
13003 )
13004{
13005 SCIP_EXPR* expr;
13006 SCIP_EXPR* lhssum;
13007 SCIP_EXPR* terms[2];
13008 SCIP_Real termcoefs[2];
13009 int i;
13010
13011 assert(vars != NULL || nvars == 0);
13012
13013 /* check values for infinity or nan */
13014 for( i = 0; i < nvars; ++i )
13015 {
13016 if( coefs != NULL && ( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) ) )
13017 {
13018 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13019 return SCIP_INVALIDDATA;
13020 }
13021 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, offsets[i])) )
13022 {
13023 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13024 return SCIP_INVALIDDATA;
13025 }
13026 }
13027 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
13028 {
13029 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
13030 return SCIP_INVALIDDATA;
13031 }
13032 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
13033 {
13034 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
13035 return SCIP_INVALIDDATA;
13036 }
13037 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
13038 {
13039 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
13040 return SCIP_INVALIDDATA;
13041 }
13042 /* lhs and rhs will be checked in createCons */
13043
13044 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
13045 for( i = 0; i < nvars; ++i )
13046 {
13047 SCIP_EXPR* varexpr;
13048 SCIP_EXPR* powexpr;
13049
13050 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
13051 if( offsets != NULL && offsets[i] != 0.0 )
13052 {
13053 SCIP_EXPR* sum;
13054 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
13055 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
13056 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
13057 }
13058 else
13059 {
13060 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
13061 }
13062
13063 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
13064 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
13065 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
13066 }
13067
13068 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
13069 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
13070 termcoefs[0] = 1.0;
13071
13072 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
13073 termcoefs[1] = -rhscoeff;
13074
13075 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
13076
13077 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13078 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13079
13080 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
13081
13082 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13083
13084 return SCIP_OKAY;
13085}
13086
13087/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
13088 *
13089 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
13090 *
13091 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13092 */
13094 SCIP* scip, /**< SCIP data structure */
13095 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13096 const char* name, /**< name of constraint */
13097 SCIP_VAR* x, /**< nonlinear variable x in constraint */
13098 SCIP_VAR* z, /**< linear variable z in constraint */
13099 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
13100 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
13101 SCIP_Real zcoef, /**< coefficient of z in constraint */
13102 SCIP_Real lhs, /**< left hand side of constraint */
13103 SCIP_Real rhs /**< right hand side of constraint */
13104 )
13105{
13106 SCIP_EXPR* xexpr;
13107 SCIP_EXPR* terms[2];
13108 SCIP_Real coefs[2];
13109 SCIP_EXPR* sumexpr;
13110
13111 assert(x != NULL);
13112 assert(z != NULL);
13113
13114 if( !SCIPisFinite(exponent) )
13115 {
13116 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13117 return SCIP_INVALIDDATA;
13118 }
13119
13120 if( !SCIPisFinite(xoffset) )
13121 {
13122 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13123 return SCIP_INVALIDDATA;
13124 }
13125
13126 if( !SCIPisFinite(zcoef) )
13127 {
13128 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13129 return SCIP_INVALIDDATA;
13130 }
13131
13132 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
13133 if( xoffset != 0.0 )
13134 {
13135 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
13136 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
13137
13138 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13139 }
13140 else
13141 {
13142 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
13143 }
13144 coefs[0] = 1.0;
13145
13146 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
13147 coefs[1] = zcoef;
13148
13149 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
13150
13151 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
13152
13153 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13154 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13155 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13156 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
13157
13158 return SCIP_OKAY;
13159}
13160
13161/** gets tag indicating current local variable bounds */
13163 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13164 )
13165{
13166 SCIP_CONSHDLRDATA* conshdlrdata;
13167
13168 assert(conshdlr != NULL);
13169 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13170
13171 return conshdlrdata->curboundstag;
13172}
13173
13174/** gets the `curboundstag` from the last time where variable bounds were relaxed */
13176 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13177 )
13178{
13179 SCIP_CONSHDLRDATA* conshdlrdata;
13180
13181 assert(conshdlr != NULL);
13182 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13183
13184 return conshdlrdata->lastboundrelax;
13185}
13186
13187/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
13188 *
13189 * @attention This method is not intended for normal use.
13190 * These tags are maintained by the event handler for variable bound change events.
13191 * This method is used by some unittests.
13192 */
13194 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13195 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
13196 )
13197{
13198 SCIP_CONSHDLRDATA* conshdlrdata;
13199
13200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13201 assert(conshdlrdata != NULL);
13202
13203 ++conshdlrdata->curboundstag;
13204 assert(conshdlrdata->curboundstag > 0);
13205
13206 if( boundrelax )
13207 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13208}
13209
13210/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13212 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13213 )
13214{
13215 assert(conshdlr != NULL);
13216
13217 return SCIPconshdlrGetData(conshdlr)->var2expr;
13218}
13219
13220/** processes a rowprep for cut addition and maybe report branchscores */
13222 SCIP* scip, /**< SCIP data structure */
13223 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13224 SCIP_CONS* cons, /**< nonlinear constraint */
13225 SCIP_EXPR* expr, /**< expression */
13226 SCIP_ROWPREP* rowprep, /**< cut to be added */
13227 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13228 SCIP_VAR* auxvar, /**< auxiliary variable */
13229 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13230 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13231 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13232 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13233 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13234 SCIP_RESULT* result /**< pointer to store the result */
13235 )
13236{
13237 SCIP_Real cutviol;
13238 SCIP_CONSHDLRDATA* conshdlrdata;
13239 SCIP_Real auxvarvalue = SCIP_INVALID;
13240 SCIP_Bool sepasuccess;
13241 SCIP_Real estimateval = SCIP_INVALID;
13242 SCIP_Real mincutviolation;
13243
13244 assert(nlhdlr != NULL);
13245 assert(cons != NULL);
13246 assert(expr != NULL);
13247 assert(rowprep != NULL);
13248 assert(auxvar != NULL);
13249 assert(result != NULL);
13250
13251 /* decide on minimal violation of cut */
13252 if( sol == NULL )
13253 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13254 else
13255 mincutviolation = SCIPfeastol(scip);
13256
13257 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13258 assert(conshdlrdata != NULL);
13259
13260 sepasuccess = TRUE;
13261
13262 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13263 if( cutviol > 0.0 )
13264 {
13265 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13266
13267 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13268 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13269 {
13270 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13271 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13272 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13273 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13274 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13275 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13276 *
13277 * if we are overestimating, we have z >= c'x-b >= f(x)
13278 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13279 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13280 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13281 *
13282 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13283 */
13284 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13285 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13286 {
13287 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13288 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13289 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13290 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13291 sepasuccess = FALSE;
13292 }
13293 }
13294
13295 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13296 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13297 }
13298 else
13299 {
13300 sepasuccess = FALSE;
13301 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13302 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13303 }
13304
13305 /* clean up estimator */
13306 if( sepasuccess )
13307 {
13308 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13309 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13310 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13311 SCIPprintRowprep(scip, rowprep, enfologfile); )
13312
13313 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13314 * instead, may even scale them down, that is, scale so that max coef is close to 1
13315 */
13316 if( !allowweakcuts )
13317 {
13318 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13319
13320 if( !sepasuccess )
13321 {
13322 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13323 }
13324 else
13325 {
13326 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13327 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13328 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13329 if( sepasuccess )
13330 sepasuccess = cutviol > mincutviolation;
13331 }
13332
13333 if( sepasuccess && auxvalue != SCIP_INVALID )
13334 {
13335 /* check whether cut is weak now
13336 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13337 * reconstructing estimateval from cutviol (TODO improve or remove?)
13338 */
13339 SCIP_Real auxvarcoef = 0.0;
13340 int i;
13341
13342 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13343 * it should be...
13344 */
13345 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13346 {
13347 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13348 {
13349 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13350 break;
13351 }
13352 }
13353
13354 if( auxvarcoef == 0.0 ||
13355 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13356 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13357 {
13358 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13359 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13360 sepasuccess = FALSE;
13361 }
13362 }
13363 }
13364 else
13365 {
13366 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13367
13368 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13369 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13370 */
13371 if( !branchscoresuccess )
13373
13374 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13375
13376 if( !sepasuccess )
13377 {
13378 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13379 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13380 }
13381
13382 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13383 * changed
13384 */
13385 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13386 {
13387 SCIP_Real violscore;
13388
13389#ifdef BRSCORE_ABSVIOL
13390 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13391#else
13392 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13393#endif
13394 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13395
13396 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13397 * - were fixed,
13398 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13399 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13400 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13401 * so I'm disabling the assert for now
13402 */
13403 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13404 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13405 }
13406 }
13407 }
13408
13409 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13410 if( sepasuccess )
13411 {
13412 SCIP_ROW* row;
13413
13414 if( conshdlrdata->branchdualweight > 0.0 )
13415 {
13416 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13417 * skip if gap is zero
13418 */
13419 if( auxvalue == SCIP_INVALID )
13420 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13421 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13422 {
13423 char gap[40];
13424 /* coverity[secure_coding] */
13425 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13426 strcat(SCIProwprepGetName(rowprep), gap);
13427 }
13428 }
13429
13430 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13431
13432 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13433 {
13434 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13436 }
13437 else if( !SCIPisCutApplicable(scip, row) )
13438 {
13439 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13440 }
13441 else
13442 {
13443 SCIP_Bool infeasible;
13444
13445 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13446 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13447
13448 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13449 * if we haven't found strong cuts before)
13450 */
13451 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13452
13453 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13454 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13456
13457 if( infeasible )
13458 {
13461 }
13462 else
13463 {
13466 }
13467 }
13468
13469 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13470 }
13471 else if( branchscoresuccess )
13472 {
13473 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13474 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13475
13476 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13477 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13478 */
13480 }
13481 else
13482 {
13483 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13484 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13485 " (!)" : ""); )
13486 }
13487
13488 return SCIP_OKAY;
13489}
13490
13491/** returns whether all nonlinear constraints are assumed to be convex */
13493 SCIP_CONSHDLR* conshdlr
13494 )
13495{
13496 SCIP_CONSHDLRDATA* conshdlrdata;
13497
13498 assert(conshdlr != NULL);
13499
13500 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13501 assert(conshdlrdata != NULL);
13502
13503 return conshdlrdata->assumeconvex;
13504}
13505
13506/** collects all bilinear terms for a given set of constraints
13507 *
13508 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13509 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13510 */
13512 SCIP* scip, /**< SCIP data structure */
13513 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13514 SCIP_CONS** conss, /**< nonlinear constraints */
13515 int nconss /**< total number of nonlinear constraints */
13516 )
13517{
13518 assert(conshdlr != NULL);
13519 assert(conss != NULL || nconss == 0);
13520
13521 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13522
13523 return SCIP_OKAY;
13524}
13525
13526/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13527 *
13528 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13529 */
13531 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13532 )
13533{
13534 SCIP_CONSHDLRDATA* conshdlrdata;
13535
13536 assert(conshdlr != NULL);
13537
13538 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13539 assert(conshdlrdata != NULL);
13540
13541 return conshdlrdata->nbilinterms;
13542}
13543
13544/** returns all bilinear terms that are contained in all nonlinear constraints
13545 *
13546 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13547 * @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.
13548 */
13550 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13551 )
13552{
13553 SCIP_CONSHDLRDATA* conshdlrdata;
13554
13555 assert(conshdlr != NULL);
13556
13557 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13558 assert(conshdlrdata != NULL);
13559
13560 return conshdlrdata->bilinterms;
13561}
13562
13563/** returns the index of the bilinear term representing the product of the two given variables
13564 *
13565 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13566 * @return The method returns -1 if the variables do not appear bilinearly.
13567 */
13569 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13570 SCIP_VAR* x, /**< first variable */
13571 SCIP_VAR* y /**< second variable */
13572 )
13573{
13574 SCIP_CONSHDLRDATA* conshdlrdata;
13576 int idx;
13577
13578 assert(conshdlr != NULL);
13579 assert(x != NULL);
13580 assert(y != NULL);
13581
13582 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13583 assert(conshdlrdata != NULL);
13584
13585 if( conshdlrdata->bilinhashtable == NULL )
13586 {
13587 return -1;
13588 }
13589
13590 /* ensure that x.index <= y.index */
13591 if( SCIPvarCompare(x, y) == 1 )
13592 {
13593 SCIPswapPointers((void**)&x, (void**)&y);
13594 }
13595 assert(SCIPvarCompare(x, y) < 1);
13596
13597 /* use a new entry to find the image in the bilinear hash table */
13598 entry.x = x;
13599 entry.y = y;
13600 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13601 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13602 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13603 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13604
13605 return idx;
13606}
13607
13608/** returns the bilinear term that represents the product of two given variables
13609 *
13610 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13611 * @return The method returns NULL if the variables do not appear bilinearly.
13612 */
13614 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13615 SCIP_VAR* x, /**< first variable */
13616 SCIP_VAR* y /**< second variable */
13617 )
13618{
13619 SCIP_CONSHDLRDATA* conshdlrdata;
13620 int idx;
13621
13622 assert(conshdlr != NULL);
13623 assert(x != NULL);
13624 assert(y != NULL);
13625
13626 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13627 assert(conshdlrdata != NULL);
13628
13629 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13630 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13631
13632 if( idx >= 0 )
13633 {
13634 return &conshdlrdata->bilinterms[idx];
13635 }
13636
13637 return NULL;
13638}
13639
13640/** evaluates an auxiliary expression for a bilinear term */
13642 SCIP* scip, /**< SCIP data structure */
13643 SCIP_VAR* x, /**< first variable of the bilinear term */
13644 SCIP_VAR* y, /**< second variable of the bilinear term */
13645 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13646 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13647 )
13648{
13649 assert(scip != NULL);
13650 assert(x != NULL);
13651 assert(y != NULL);
13652 assert(auxexpr != NULL);
13653 assert(auxexpr->auxvar != NULL);
13654
13655 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13656 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13657}
13658
13659/** stores the variables of a bilinear term in the data of the constraint handler */
13661 SCIP* scip, /**< SCIP data structure */
13662 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13663 SCIP_VAR* x, /**< first variable */
13664 SCIP_VAR* y, /**< second variable */
13665 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13666 int nlockspos, /**< number of positive expression locks */
13667 int nlocksneg /**< number of negative expression locks */
13668 )
13669{
13670 SCIP_CONSHDLRDATA* conshdlrdata;
13672 int idx;
13673
13674 assert(conshdlr != NULL);
13675
13676 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13677 assert(conshdlrdata != NULL);
13678
13679 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13680
13681 term = &conshdlrdata->bilinterms[idx];
13682 assert(term != NULL);
13683 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13684 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) */
13685
13686 /* store and capture auxiliary variable */
13687 if( auxvar != NULL )
13688 {
13689 term->aux.var = auxvar;
13690 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13691 }
13692
13693 return SCIP_OKAY;
13694}
13695
13696/** stores the variables of a bilinear term in the data of the constraint handler */
13698 SCIP* scip, /**< SCIP data structure */
13699 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13700 SCIP_VAR* x, /**< first variable */
13701 SCIP_VAR* y, /**< second variable */
13702 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13703 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13704 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13705 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13706 SCIP_Real cst, /**< constant of the auxiliary expression */
13707 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13708 )
13709{
13710 SCIP_CONSHDLRDATA* conshdlrdata;
13713 int idx;
13714 int nlockspos;
13715 int nlocksneg;
13716 SCIP_Bool added;
13717
13718 assert(conshdlr != NULL);
13719
13720 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13721 assert(conshdlrdata != NULL);
13722
13723 nlockspos = overestimate ? 1 : 0;
13724 nlocksneg = overestimate ? 0 : 1;
13725
13726 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13727
13728 term = &conshdlrdata->bilinterms[idx];
13729 assert(term != NULL);
13730 assert(SCIPvarCompare(term->x, term->y) < 1);
13731
13732 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13733 {
13734 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13735 /* this is the case where we are adding an implicitly defined relation for a product that has already
13736 * been explicitly defined; convert auxvar into an auxexpr */
13737
13738 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13739 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13740 return SCIP_OKAY;
13741
13742 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13743 auxvarexpr->cst = 0.0;
13744 auxvarexpr->coefs[0] = 1.0;
13745 auxvarexpr->coefs[1] = 0.0;
13746 auxvarexpr->coefs[2] = 0.0;
13747 auxvarexpr->auxvar = term->aux.var;
13748 auxvarexpr->underestimate = term->nlocksneg > 0;
13749 auxvarexpr->overestimate = term->nlockspos > 0;
13750
13751 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13752 term->aux.exprs = NULL;
13753
13754 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13755
13756 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13757 assert(added);
13758 }
13759
13760 /* create and add auxexpr */
13761 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13762 auxexpr->underestimate = !overestimate;
13763 auxexpr->overestimate = overestimate;
13764 auxexpr->auxvar = auxvar;
13765 auxexpr->coefs[0] = coefaux;
13766 if( term->x == x )
13767 {
13768 assert(term->y == y);
13769 auxexpr->coefs[1] = coefx;
13770 auxexpr->coefs[2] = coefy;
13771 }
13772 else
13773 {
13774 assert(term->x == y);
13775 assert(term->y == x);
13776 auxexpr->coefs[1] = coefy;
13777 auxexpr->coefs[2] = coefx;
13778 }
13779 auxexpr->cst = cst;
13780 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13781
13782 if( !added )
13783 {
13784 SCIPfreeBlockMemory(scip, &auxexpr);
13785 }
13786 else if( auxvar != NULL )
13787 { /* capture auxiliary variable */
13788 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13789 }
13790
13791 return SCIP_OKAY;
13792}
13793
13794/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13796 SCIP* scip, /**< SCIP data structure */
13797 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13798 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13799 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13800 void* fundata, /**< data for function evaluation (can be NULL) */
13801 SCIP_Real* xstar, /**< point to be separated */
13802 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13803 int nallvars, /**< half of the length of box */
13804 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13805 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13806 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13807 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13808 )
13809{
13810 SCIP_Real* corner;
13811 SCIP_Real* funvals;
13812 int* nonfixedpos;
13813 SCIP_Real maxfaceterror;
13814 int nvars; /* number of nonfixed variables */
13815 unsigned int ncorners;
13816 unsigned int i;
13817 int j;
13818
13819 assert(scip != NULL);
13820 assert(conshdlr != NULL);
13821 assert(function != NULL);
13822 assert(xstar != NULL);
13823 assert(box != NULL);
13824 assert(success != NULL);
13825 assert(facetcoefs != NULL);
13826 assert(facetconstant != NULL);
13827
13828 *success = FALSE;
13829
13830 /* identify fixed variables */
13831 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13832 nvars = 0;
13833 for( j = 0; j < nallvars; ++j )
13834 {
13835 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13836 continue;
13837 nonfixedpos[nvars] = j;
13838 nvars++;
13839 }
13840
13841 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13842 * if too many variables are not fixed, then we do nothing currently
13843 */
13844 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13845 {
13846 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13847 SCIPfreeBufferArray(scip, &nonfixedpos);
13848 return SCIP_OKAY;
13849 }
13850
13851 /* compute f(v^i) for each corner v^i of [l,u] */
13852 ncorners = POWEROFTWO(nvars);
13853 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13854 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13855 for( j = 0; j < nallvars; ++j )
13856 {
13857 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13858 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13859 }
13860 for( i = 0; i < ncorners; ++i )
13861 {
13862 SCIPdebugMsg(scip, "corner %u: ", i);
13863 for( j = 0; j < nvars; ++j )
13864 {
13865 int varpos = nonfixedpos[j];
13866 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13867 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13868 */
13869 if( (i >> j) & 0x1 )
13870 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13871 else
13872 corner[varpos] = box[2 * varpos ]; /* lb of var */
13873 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13874 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13875 }
13876
13877 funvals[i] = function(corner, nallvars, fundata);
13878
13879 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13880
13881 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13882 {
13883 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13884 goto CLEANUP;
13885 }
13886 }
13887
13888 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13889 BMSclearMemoryArray(facetcoefs, nallvars);
13890
13891 if( nvars == 1 )
13892 {
13893 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13894
13895 /* check whether target has been missed */
13896 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13897 {
13898 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13899 *success = FALSE;
13900 }
13901 }
13902 else if( nvars == 2 && SCIPlapackIsAvailable() )
13903 {
13904 int idx1 = nonfixedpos[0];
13905 int idx2 = nonfixedpos[1];
13906 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13907 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13908 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13909 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13910 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13911 SCIP_Real coefs[2] = { 0.0, 0.0 };
13912
13913 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13914
13915 facetcoefs[idx1] = coefs[0];
13916 facetcoefs[idx2] = coefs[1];
13917 }
13918 else
13919 {
13920 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13921 }
13922 if( !*success )
13923 {
13924 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13925 goto CLEANUP;
13926 }
13927
13928 /*
13929 * check and adjust facet with the algorithm of Rikun et al.
13930 */
13931
13932 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13933
13934 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13935 if( maxfaceterror > 0.0 )
13936 {
13937 SCIP_CONSHDLRDATA* conshdlrdata;
13938 SCIP_Real midval;
13939 SCIP_Real feastol;
13940
13942
13943 /* evaluate function in middle point to get some idea for a scaling */
13944 for( j = 0; j < nvars; ++j )
13945 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13946 midval = function(corner, nallvars, fundata);
13947 if( midval == SCIP_INVALID )
13948 midval = 1.0;
13949
13950 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13951 assert(conshdlrdata != NULL);
13952
13953 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13954 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13955 {
13956 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13957 *success = FALSE;
13958 goto CLEANUP;
13959 }
13960
13961 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13962
13963 if( overestimate )
13964 *facetconstant += maxfaceterror;
13965 else
13966 *facetconstant -= maxfaceterror;
13967 }
13968
13969 /* if we made it until here, then we have a nice facet */
13970 assert(*success);
13971
13972CLEANUP:
13973 /* free allocated memory */
13974 SCIPfreeBufferArray(scip, &corner);
13975 SCIPfreeBufferArray(scip, &funvals);
13976 SCIPfreeBufferArray(scip, &nonfixedpos);
13977
13978 return SCIP_OKAY;
13979}
13980
13981/*
13982 * constraint specific interface methods
13983 */
13984
13985/** returns the expression of the given nonlinear constraint */
13987 SCIP_CONS* cons /**< constraint data */
13988 )
13989{
13990 SCIP_CONSDATA* consdata;
13991
13992 assert(cons != NULL);
13994
13995 consdata = SCIPconsGetData(cons);
13996 assert(consdata != NULL);
13997
13998 return consdata->expr;
13999}
14000
14001/** gets the left hand side of a nonlinear constraint */
14003 SCIP_CONS* cons /**< constraint data */
14004 )
14005{
14006 SCIP_CONSDATA* consdata;
14007
14008 assert(cons != NULL);
14010
14011 consdata = SCIPconsGetData(cons);
14012 assert(consdata != NULL);
14013
14014 return consdata->lhs;
14015}
14016
14017/** gets the right hand side of a nonlinear constraint */
14019 SCIP_CONS* cons /**< constraint data */
14020 )
14021{
14022 SCIP_CONSDATA* consdata;
14023
14024 assert(cons != NULL);
14026
14027 consdata = SCIPconsGetData(cons);
14028 assert(consdata != NULL);
14029
14030 return consdata->rhs;
14031}
14032
14033/** gets the nonlinear constraint as a nonlinear row representation. */
14035 SCIP* scip, /**< SCIP data structure */
14036 SCIP_CONS* cons, /**< constraint */
14037 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14038 )
14039{
14040 SCIP_CONSDATA* consdata;
14041
14042 assert(cons != NULL);
14043 assert(nlrow != NULL);
14045
14046 consdata = SCIPconsGetData(cons);
14047 assert(consdata != NULL);
14048
14049 if( consdata->nlrow == NULL )
14050 {
14051 SCIP_CALL( createNlRow(scip, cons) );
14052 }
14053 assert(consdata->nlrow != NULL);
14054 *nlrow = consdata->nlrow;
14055
14056 return SCIP_OKAY;
14057}
14058
14059/** returns the curvature of the expression of a given nonlinear constraint
14060 *
14061 * @note The curvature information is computed during CONSINITSOL.
14062 */
14064 SCIP_CONS* cons /**< constraint data */
14065 )
14066{
14067 SCIP_CONSDATA* consdata;
14068
14069 assert(cons != NULL);
14071
14072 consdata = SCIPconsGetData(cons);
14073 assert(consdata != NULL);
14074
14075 return consdata->curv;
14076}
14077
14078/** checks whether expression of constraint can be represented as quadratic form
14079 *
14080 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
14081 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
14082 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
14083 */
14085 SCIP* scip, /**< SCIP data structure */
14086 SCIP_CONS* cons, /**< constraint data */
14087 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
14088 )
14089{
14090 SCIP_CONSDATA* consdata;
14091
14092 assert(scip != NULL);
14093 assert(cons != NULL);
14094 assert(isquadratic != NULL);
14096
14097 consdata = SCIPconsGetData(cons);
14098 assert(consdata != NULL);
14099 assert(consdata->expr != NULL);
14100
14101 /* check whether constraint expression is quadratic in extended formulation */
14102 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
14103
14104 /* if not quadratic in non-extended formulation, then do indicate quadratic */
14105 if( *isquadratic )
14106 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
14107
14108 return SCIP_OKAY;
14109}
14110
14111/** changes left-hand-side of a nonlinear constraint
14112 *
14113 * @attention This method can only be called in the problem stage.
14114 */
14116 SCIP* scip, /**< SCIP data structure */
14117 SCIP_CONS* cons, /**< constraint data */
14118 SCIP_Real lhs /**< new left-hand-side */
14119 )
14120{
14121 SCIP_CONSDATA* consdata;
14122
14123 assert(scip != NULL);
14124 assert(cons != NULL);
14126
14128 {
14129 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14130 return SCIP_INVALIDCALL;
14131 }
14132
14133 /* we should have an original constraint */
14135
14136 consdata = SCIPconsGetData(cons);
14137 assert(consdata != NULL);
14138
14139 if( consdata->lhs == lhs )
14140 return SCIP_OKAY;
14141
14142 consdata->lhs = lhs;
14143
14144 /* not sure we care about any of these flags for original constraints */
14145 consdata->ispropagated = FALSE;
14146
14147 return SCIP_OKAY;
14148}
14149
14150/** changes right-hand-side of a nonlinear constraint
14151 *
14152 * @attention This method can only be called in the problem stage.
14153 */
14155 SCIP* scip, /**< SCIP data structure */
14156 SCIP_CONS* cons, /**< constraint data */
14157 SCIP_Real rhs /**< new right-hand-side */
14158 )
14159{
14160 SCIP_CONSDATA* consdata;
14161
14162 assert(scip != NULL);
14163 assert(cons != NULL);
14165
14167 {
14168 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14169 return SCIP_INVALIDCALL;
14170 }
14171
14172 /* we should have an original constraint */
14174
14175 consdata = SCIPconsGetData(cons);
14176 assert(consdata != NULL);
14177
14178 if( consdata->rhs == rhs )
14179 return SCIP_OKAY;
14180
14181 consdata->rhs = rhs;
14182
14183 /* not sure we care about any of these flags for original constraints */
14184 consdata->ispropagated = FALSE;
14185
14186 return SCIP_OKAY;
14187}
14188
14189/** changes expression of a nonlinear constraint
14190 *
14191 * @attention This method can only be called in the problem stage.
14192 */
14194 SCIP* scip, /**< SCIP data structure */
14195 SCIP_CONS* cons, /**< constraint data */
14196 SCIP_EXPR* expr /**< new expression */
14197 )
14198{
14199 SCIP_CONSHDLR* conshdlr;
14200 SCIP_CONSDATA* consdata;
14201
14202 assert(scip != NULL);
14203 assert(cons != NULL);
14204 assert(expr != NULL);
14205
14207 {
14208 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14209 return SCIP_INVALIDCALL;
14210 }
14211
14212 /* we should have an original constraint */
14214
14215 conshdlr = SCIPconsGetHdlr(cons);
14216 assert(conshdlr != NULL);
14217 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14218
14219 consdata = SCIPconsGetData(cons);
14220 assert(consdata != NULL);
14221 assert(consdata->expr != NULL);
14222
14223 /* we should not have collected additional data for the expr
14224 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14225 */
14226 assert(consdata->nvarexprs == 0);
14227 assert(consdata->varexprs == NULL);
14228 assert(!consdata->catchedevents);
14229
14230 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14231
14232 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14233 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14234
14235 /* not sure we care about any of these flags for original constraints */
14236 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14237 consdata->issimplified = FALSE;
14238 consdata->ispropagated = FALSE;
14239
14240 return SCIP_OKAY;
14241}
14242
14243/** adds coef * var to nonlinear constraint
14244 *
14245 * @attention This method can only be called in the problem stage.
14246 */
14248 SCIP* scip, /**< SCIP data structure */
14249 SCIP_CONS* cons, /**< constraint data */
14250 SCIP_VAR* var, /**< variable */
14251 SCIP_Real coef /**< coefficient */
14252 )
14253{
14254 SCIP_CONSHDLR* conshdlr;
14255 SCIP_CONSDATA* consdata;
14256 SCIP_EXPR* varexpr;
14257
14258 assert(scip != NULL);
14259 assert(cons != NULL);
14260
14262 {
14263 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14264 return SCIP_INVALIDCALL;
14265 }
14266
14267 /* we should have an original constraint */
14269
14270 if( coef == 0.0 )
14271 return SCIP_OKAY;
14272
14273 conshdlr = SCIPconsGetHdlr(cons);
14274 assert(conshdlr != NULL);
14275 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14276
14277 consdata = SCIPconsGetData(cons);
14278 assert(consdata != NULL);
14279 assert(consdata->expr != NULL);
14280
14281 /* we should not have collected additional data for it
14282 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14283 */
14284 assert(consdata->nvarexprs == 0);
14285 assert(consdata->varexprs == NULL);
14286 assert(!consdata->catchedevents);
14287
14288 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14289
14290 /* append to sum, if consdata->expr is sum and not used anywhere else */
14291 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14292 {
14293 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14294 }
14295 else
14296 {
14297 /* create new expression = 1 * consdata->expr + coef * var */
14298 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14299 SCIP_Real coefs[2] = { 1.0, coef };
14300
14301 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14302
14303 /* release old root expr */
14304 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14305 }
14306
14307 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14308
14309 /* not sure we care about any of these flags for original constraints */
14310 consdata->issimplified = FALSE;
14311 consdata->ispropagated = FALSE;
14312
14313 return SCIP_OKAY;
14314}
14315
14316/** adds coef * expr to nonlinear constraint
14317 *
14318 * @attention This method can only be called in the problem stage.
14319 */
14321 SCIP* scip, /**< SCIP data structure */
14322 SCIP_CONS* cons, /**< nonlinear constraint */
14323 SCIP_EXPR* expr, /**< expression */
14324 SCIP_Real coef /**< coefficient */
14325 )
14326{
14327 SCIP_CONSHDLR* conshdlr;
14328 SCIP_CONSDATA* consdata;
14329 SCIP_EXPR* exprowned;
14330
14331 assert(scip != NULL);
14332 assert(cons != NULL);
14333
14335 {
14336 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14337 return SCIP_INVALIDCALL;
14338 }
14339
14340 /* we should have an original constraint */
14342
14343 if( coef == 0.0 )
14344 return SCIP_OKAY;
14345
14346 conshdlr = SCIPconsGetHdlr(cons);
14347 assert(conshdlr != NULL);
14348 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14349
14350 consdata = SCIPconsGetData(cons);
14351 assert(consdata != NULL);
14352 assert(consdata->expr != NULL);
14353
14354 /* free quadratic representation, if any is stored */
14355 SCIPfreeExprQuadratic(scip, consdata->expr);
14356
14357 /* free varexprs in consdata, in case they have been stored
14358 * (e.g., by a call to consGet(N)VarsNonlinear)
14359 */
14360 SCIP_CALL( freeVarExprs(scip, consdata) );
14361
14362 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14363 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14364
14365 /* append to sum, if consdata->expr is sum and not used anywhere else */
14366 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14367 {
14368 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14369 }
14370 else
14371 {
14372 /* create new expression = 1 * consdata->expr + coef * var */
14373 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14374 SCIP_Real coefs[2] = { 1.0, coef };
14375
14376 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14377
14378 /* release old root expr */
14379 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14380 }
14381
14382 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14383
14384 /* not sure we care about any of these flags for original constraints */
14385 consdata->issimplified = FALSE;
14386 consdata->ispropagated = FALSE;
14387
14388 return SCIP_OKAY;
14389}
14390
14391/** computes value of constraint expression in a given solution
14392 *
14393 * Stores value of constraint expression in sol in activity.
14394 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14395 */
14397 SCIP* scip, /**< SCIP data structure */
14398 SCIP_CONS* cons, /**< constraint */
14399 SCIP_SOL* sol, /**< solution */
14400 SCIP_Real* activity /**< buffer to store computed activity */
14401 )
14402{
14403 SCIP_CONSDATA* consdata;
14404
14405 assert(cons != NULL);
14406 assert(activity != NULL);
14407
14408 consdata = SCIPconsGetData(cons);
14409 assert(consdata != NULL);
14410
14411 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14412 *activity = SCIPexprGetEvalValue(consdata->expr);
14413
14414 return SCIP_OKAY;
14415}
14416
14417/** gets absolute violation of nonlinear constraint
14418 *
14419 * This function evaluates the constraints in the given solution.
14420 *
14421 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14422 */
14424 SCIP* scip, /**< SCIP data structure */
14425 SCIP_CONS* cons, /**< constraint */
14426 SCIP_SOL* sol, /**< solution to check */
14427 SCIP_Real* viol /**< buffer to store computed violation */
14428 )
14429{
14430 assert(cons != NULL);
14431 assert(viol != NULL);
14432
14433 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14434 *viol = getConsAbsViolation(cons);
14435
14436 return SCIP_OKAY;
14437}
14438
14439/** gets scaled violation of nonlinear constraint
14440 *
14441 * This function evaluates the constraints in the given solution.
14442 *
14443 * The scaling that is applied to the absolute violation of the constraint
14444 * depends on the setting of parameter constraints/nonlinear/violscale.
14445 */
14447 SCIP* scip, /**< SCIP data structure */
14448 SCIP_CONS* cons, /**< constraint */
14449 SCIP_SOL* sol, /**< solution to check */
14450 SCIP_Real* viol /**< buffer to store computed violation */
14451 )
14452{
14453 assert(cons != NULL);
14454 assert(viol != NULL);
14455
14456 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14457 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14458
14459 return SCIP_OKAY;
14460}
14461
14462/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14464 SCIP* scip, /**< SCIP data structure */
14465 SCIP_CONS* cons, /**< nonlinear constraint */
14466 SCIP_VAR** var, /**< pointer to store the variable */
14467 SCIP_Real* coef /**< pointer to store the coefficient */
14468 )
14469{
14470 SCIP_CONSDATA* consdata;
14471
14472 assert(cons != NULL);
14473 assert(var != NULL);
14474 assert(coef != NULL);
14475
14476 /* check for a linear variable that can be increased or decreased without harming feasibility */
14478
14479 consdata = SCIPconsGetData(cons);
14480 assert(consdata != NULL);
14481
14482 *var = consdata->linvardecr;
14483 *coef = consdata->linvardecrcoef;
14484}
14485
14486/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14488 SCIP* scip, /**< SCIP data structure */
14489 SCIP_CONS* cons, /**< nonlinear constraint */
14490 SCIP_VAR** var, /**< pointer to store the variable */
14491 SCIP_Real* coef /**< pointer to store the coefficient */
14492 )
14493{
14494 SCIP_CONSDATA* consdata;
14495
14496 assert(cons != NULL);
14497 assert(var != NULL);
14498 assert(coef != NULL);
14499
14500 /* check for a linear variable that can be increased or decreased without harming feasibility */
14502
14503 consdata = SCIPconsGetData(cons);
14504 assert(consdata != NULL);
14505
14506 *var = consdata->linvarincr;
14507 *coef = consdata->linvarincrcoef;
14508}
14509
14510
14511/*
14512 * Methods for Expressions in Nonlinear Constraints
14513 */
14514
14515/** returns the number of positive rounding locks of an expression */
14517 SCIP_EXPR* expr /**< expression */
14518 )
14519{
14520 assert(expr != NULL);
14522
14523 return SCIPexprGetOwnerData(expr)->nlockspos;
14524}
14525
14526/** returns the number of negative rounding locks of an expression */
14528 SCIP_EXPR* expr /**< expression */
14529 )
14530{
14531 assert(expr != NULL);
14533
14534 return SCIPexprGetOwnerData(expr)->nlocksneg;
14535}
14536
14537/** returns the variable used for linearizing a given expression (return value might be NULL)
14538 *
14539 * @note for variable expression it returns the corresponding variable
14540 */
14542 SCIP_EXPR* expr /**< expression */
14543 )
14544{
14545 SCIP_EXPR_OWNERDATA* ownerdata;
14546
14547 assert(expr != NULL);
14548
14549 ownerdata = SCIPexprGetOwnerData(expr);
14550 assert(ownerdata != NULL);
14551
14552 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14553}
14554
14555/** returns the number of enforcements for an expression */
14557 SCIP_EXPR* expr /**< expression */
14558 )
14559{
14560 assert(expr != NULL);
14562
14563 return SCIPexprGetOwnerData(expr)->nenfos;
14564}
14565
14566/** returns the data for one of the enforcements of an expression */
14568 SCIP_EXPR* expr, /**< expression */
14569 int idx, /**< position of enforcement in enfos array */
14570 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14571 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14572 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14573 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14574 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14575 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14576 )
14577{
14578 SCIP_EXPR_OWNERDATA* ownerdata;
14579
14580 assert(expr != NULL);
14581
14582 ownerdata = SCIPexprGetOwnerData(expr);
14583 assert(ownerdata != NULL);
14584 assert(idx >= 0);
14585 assert(idx < ownerdata->nenfos);
14586 assert(ownerdata->enfos[idx] != NULL);
14587 assert(nlhdlr != NULL);
14588
14589 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14590
14591 if( nlhdlrexprdata != NULL )
14592 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14593
14594 if( nlhdlrparticipation != NULL )
14595 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14596
14597 if( sepabelowusesactivity != NULL )
14598 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14599
14600 if( sepaaboveusesactivity != NULL )
14601 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14602
14603 if( auxvalue != NULL )
14604 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14605}
14606
14607/** sets the auxiliary value of expression for one of the enforcements of an expression */
14609 SCIP_EXPR* expr, /**< expression */
14610 int idx, /**< position of enforcement in enfos array */
14611 SCIP_Real auxvalue /**< the new value of auxval */
14612 )
14613{
14614 SCIP_EXPR_OWNERDATA* ownerdata;
14615
14616 assert(expr != NULL);
14617
14618 ownerdata = SCIPexprGetOwnerData(expr);
14619 assert(ownerdata != NULL);
14620
14621 assert(idx >= 0);
14622 assert(idx < ownerdata->nenfos);
14623 assert(ownerdata->enfos[idx] != NULL);
14624
14625 ownerdata->enfos[idx]->auxvalue = auxvalue;
14626}
14627
14628/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14629 *
14630 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14631 */
14633 SCIP_EXPR* expr /**< expression */
14634 )
14635{
14636 assert(expr != NULL);
14638
14639 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14640}
14641
14642/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14643 *
14644 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14645 */
14647 SCIP_EXPR* expr /**< expression */
14648 )
14649{
14650 assert(expr != NULL);
14652
14653 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14654}
14655
14656/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14657 *
14658 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14659 */
14661 SCIP_EXPR* expr /**< expression */
14662 )
14663{
14664 assert(expr != NULL);
14666
14667 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14668}
14669
14670/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14671 *
14672 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14673 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14674 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14675 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14676 * and also increments this count for all variables in the expression.
14677 *
14678 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14679 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14680 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14681 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14682 */
14684 SCIP* scip, /**< SCIP data structure */
14685 SCIP_EXPR* expr, /**< expression */
14686 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14687 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14688 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14689 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14690 )
14691{
14692 SCIP_EXPR_OWNERDATA* ownerdata;
14693
14694 assert(expr != NULL);
14695
14696 ownerdata = SCIPexprGetOwnerData(expr);
14697 assert(ownerdata != NULL);
14698
14699 /* do not store auxvar request for variable expressions */
14700 if( useauxvar && SCIPisExprVar(scip, expr) )
14701 useauxvar = FALSE;
14702
14703 if( ownerdata->nenfos >= 0 &&
14704 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14705 (ownerdata->nauxvaruses == 0 && useauxvar)
14706 ) )
14707 {
14708 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14709 * we require additional enforcement methods, that is,
14710 * - activity of expr was not used before but will be used now, or
14711 * - auxiliary variable of expr was not required before but will be used now
14712 */
14713 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14714 }
14715
14716 if( useauxvar )
14717 ++ownerdata->nauxvaruses;
14718
14719 if( useactivityforprop )
14720 ++ownerdata->nactivityusesprop;
14721
14722 if( useactivityforsepabelow || useactivityforsepaabove )
14723 ++ownerdata->nactivityusessepa;
14724
14725 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14726 * information is used in detectNlhdlr()
14727 */
14728 if( useactivityforsepabelow )
14729 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14730 if( useactivityforsepaabove )
14731 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14732
14733 if( useactivityforprop )
14734 {
14735 /* if activity will be used for propagation, then make sure there is a valid activity
14736 * this way, we can do a reversepropcall after detectNlhdlr
14737 */
14739 }
14740
14741 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14742 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14743 {
14744 SCIP_EXPRITER* it;
14745
14746 /* create and initialize iterator */
14749
14750 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14751 if( SCIPisExprVar(scip, expr) )
14752 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14753
14754 /* free iterator */
14755 SCIPfreeExpriter(&it);
14756 }
14757
14758 return SCIP_OKAY;
14759}
14760
14761/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14762 *
14763 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14764 * Assume that f(x) is associated with auxiliary variable z.
14765 *
14766 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14767 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14768 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14769 *
14770 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14771 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14772 */
14774 SCIP* scip, /**< SCIP data structure */
14775 SCIP_EXPR* expr, /**< expression */
14776 SCIP_SOL* sol, /**< solution */
14777 SCIP_Longint soltag, /**< tag of solution */
14778 SCIP_Real* viol, /**< buffer to store computed violation */
14779 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14780 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14781 )
14782{
14783 assert(scip != NULL);
14784 assert(expr != NULL);
14785 assert(viol != NULL);
14786
14787 /* make sure expression has been evaluated */
14788 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14789
14790 /* get violation from internal method */
14791 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14792
14793 return SCIP_OKAY;
14794}
14795
14796/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14797 *
14798 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14799 * Assume that f(w) is associated with auxiliary variable z.
14800 *
14801 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14802 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14803 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14804 *
14805 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14806 * both `violover` and `violunder` are set to TRUE.
14807 */
14809 SCIP* scip, /**< SCIP data structure */
14810 SCIP_EXPR* expr, /**< expression */
14811 SCIP_Real auxvalue, /**< the value of f(w) */
14812 SCIP_SOL* sol, /**< solution that has been evaluated */
14813 SCIP_Real* viol, /**< buffer to store computed violation */
14814 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14815 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14816 )
14817{
14818 assert(scip != NULL);
14819 assert(expr != NULL);
14820 assert(viol != NULL);
14821
14822 /* get violation from internal method */
14823 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14824
14825 return SCIP_OKAY;
14826}
14827
14828
14829/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14830 *
14831 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14832 * Assume that f(w) is associated with auxiliary variable z.
14833 *
14834 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14835 * the absolute violation divided by max(1,|f(w)|).
14836 *
14837 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14838 * both `violover` and `violunder` are set to TRUE.
14839 */
14841 SCIP* scip, /**< SCIP data structure */
14842 SCIP_EXPR* expr, /**< expression */
14843 SCIP_Real auxvalue, /**< the value of f(w) */
14844 SCIP_SOL* sol, /**< solution that has been evaluated */
14845 SCIP_Real* viol, /**< buffer to store computed violation */
14846 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14847 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14848 )
14849{
14850 assert(scip != NULL);
14851 assert(expr != NULL);
14852 assert(viol != NULL);
14853
14854 /* get violation from internal method */
14855 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14856
14857 if( !SCIPisInfinity(scip, *viol) )
14858 {
14859 assert(auxvalue != SCIP_INVALID);
14860 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14861 *viol /= MAX(1.0, REALABS(auxvalue));
14862 }
14863
14864 return SCIP_OKAY;
14865}
14866
14867/** returns bounds on the expression
14868 *
14869 * This gives an intersection of bounds from
14870 * - activity calculation (SCIPexprGetActivity()), if valid,
14871 * - auxiliary variable, if present,
14872 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14873 *
14874 * @note The returned interval can be empty!
14875 */
14877 SCIP* scip, /**< SCIP data structure */
14878 SCIP_EXPR* expr /**< expression */
14879 )
14880{
14881 SCIP_EXPR_OWNERDATA* ownerdata;
14882 SCIP_CONSHDLRDATA* conshdlrdata;
14883 SCIP_INTERVAL bounds;
14884
14885 assert(scip != NULL);
14886 assert(expr != NULL);
14887
14888 ownerdata = SCIPexprGetOwnerData(expr);
14889 assert(ownerdata != NULL);
14890
14891 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14892 assert(conshdlrdata != NULL);
14893
14894 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14895
14896 /* start with propbounds if they belong to current propagation */
14897 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14898 {
14899 bounds = ownerdata->propbounds;
14900 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14901 }
14902 else
14904
14905 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14906 {
14907 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14908 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14910 }
14911
14912 if( ownerdata->auxvar != NULL )
14913 {
14914 /* apply auxiliary variable bounds to bounds */
14915 SCIP_INTERVAL auxvarbounds;
14916
14917 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14918 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14919 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14920 }
14921
14922 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14923
14924 return bounds;
14925}
14926
14927/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14928 * corresponding (auxiliary) variable (if any)
14929 *
14930 * @attention this function should only be called during domain propagation in cons_nonlinear
14931 */
14933 SCIP* scip, /**< SCIP data structure */
14934 SCIP_EXPR* expr, /**< expression to be tightened */
14935 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14936 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14937 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14938 )
14939{
14940 SCIP_EXPR_OWNERDATA* ownerdata;
14941 SCIP_CONSHDLRDATA* conshdlrdata;
14942
14943 assert(scip != NULL);
14944 assert(expr != NULL);
14945 assert(cutoff != NULL);
14946
14947 ownerdata = SCIPexprGetOwnerData(expr);
14948 assert(ownerdata != NULL);
14949 assert(ownerdata->conshdlr != NULL);
14950
14951 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14952 assert(conshdlrdata != NULL);
14953
14954 /* the code below assumes that current activity is valid
14955 * if it turns out that we cannot ensure that, then we should change code
14956 */
14957 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14959
14960 *cutoff = FALSE;
14961
14962#ifdef DEBUG_PROP
14963 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14964 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14965 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14966#endif
14967
14968 if( SCIPexprIsIntegral(expr) )
14969 {
14970 /* apply integrality to new bounds
14971 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14972 */
14973 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14974 newbounds.inf = SCIPceil(scip, newbounds.inf);
14975 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14976 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14977#ifdef DEBUG_PROP
14978 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14979#endif
14980 }
14981
14983 {
14984 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14985
14986 *cutoff = TRUE;
14987 return SCIP_OKAY;
14988 }
14989
14990 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14991 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14992 {
14993 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14994
14995 *cutoff = TRUE;
14996 return SCIP_OKAY;
14997 }
14998
14999 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
15000 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
15001 {
15002 /* if already having propbounds in expr, then tighten newbounds by propbounds */
15003 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
15004 }
15005 else
15006 {
15007 /* first time we have propbounds for expr in this propagation rounds:
15008 * intersect with activity (though don't let it become empty if very close intervals)
15009 */
15010 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
15011 }
15012#ifdef DEBUG_PROP
15013 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
15014#endif
15015
15016 /* check if the new bounds lead to an empty interval */
15018 {
15019 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
15020
15021 *cutoff = TRUE;
15022 return SCIP_OKAY;
15023 }
15024
15025 /* if expr is not constant or variable, then store newbounds in expr->propbounds
15026 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
15027 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
15028 */
15029 if( SCIPexprGetNChildren(expr) > 0 )
15030 {
15031 ownerdata->propbounds = newbounds;
15032 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
15033 }
15034
15035 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
15036 * propagation or update of auxvar bounds
15037 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
15038 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
15039 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
15040 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
15041 * one or should we not even update propbounds to newbounds if the update is small?
15042 */
15043 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
15044 {
15045#ifdef DEBUG_PROP
15046 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);
15047#endif
15048 return SCIP_OKAY;
15049 }
15050
15051 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
15052 {
15053 /* add expression to propagation queue if not there yet and not var or constant and
15054 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
15055 */
15056#ifdef DEBUG_PROP
15057 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
15058#endif
15059 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
15060 ownerdata->inpropqueue = TRUE;
15061 }
15062
15063 /* update bounds on variable or auxiliary variable */
15064 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
15065
15066 return SCIP_OKAY;
15067}
15068
15069/** mark constraints that include this expression to be propagated again
15070 *
15071 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
15072 * a change of variable bounds, e.g., because new information on the expression is available
15073 * that could potentially lead to tighter expression activity values.
15074 *
15075 * Note, that this call marks also constraints for propagation which only share some variable
15076 * with this expression.
15077 */
15079 SCIP* scip, /**< SCIP data structure */
15080 SCIP_EXPR* expr /**< expression to propagate again */
15081 )
15082{
15083 SCIP_EXPRITER* it;
15084 SCIP_CONSDATA* consdata;
15085 SCIP_EXPR_OWNERDATA* ownerdata;
15086 int c;
15087
15088 assert(scip != NULL);
15089 assert(expr != NULL);
15090
15091 ownerdata = SCIPexprGetOwnerData(expr);
15092 assert(ownerdata != NULL);
15093
15094 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
15095
15098
15099 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
15100 {
15101 if( !SCIPisExprVar(scip, expr) )
15102 continue;
15103
15104 ownerdata = SCIPexprGetOwnerData(expr);
15105 assert(ownerdata != NULL);
15106
15107 for( c = 0; c < ownerdata->nconss; ++c )
15108 {
15109 consdata = SCIPconsGetData(ownerdata->conss[c]);
15110 assert(consdata != NULL);
15111 consdata->ispropagated = FALSE;
15112 }
15113 }
15114
15115 SCIPfreeExpriter(&it);
15116
15117 return SCIP_OKAY;
15118}
15119
15120/** adds violation-branching score to an expression
15121 *
15122 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
15123 * The expression must either be a variable expression or have an aux-variable.
15124 * In the latter case, branching on auxiliary variables must have been enabled.
15125 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
15126 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
15127 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
15128 *
15129 * @see SCIPaddExprsViolScoreNonlinear()
15130 */
15132 SCIP* scip, /**< SCIP data structure */
15133 SCIP_EXPR* expr, /**< expression where to add branching score */
15134 SCIP_Real violscore /**< violation score to add to expression */
15135 )
15136{
15137 SCIP_EXPR_OWNERDATA* ownerdata;
15138 SCIP_CONSHDLRDATA* conshdlrdata;
15139
15140 assert(scip != NULL);
15141 assert(expr != NULL);
15142 assert(violscore >= 0.0);
15143
15144 ownerdata = SCIPexprGetOwnerData(expr);
15145 assert(ownerdata != NULL);
15146
15147 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15148 assert(conshdlrdata != NULL);
15149
15150 /* if not allowing to branch on auxvars, then expr must be a var-expr */
15151 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
15152 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
15153 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
15154
15155 /* reset branching score if we are in a different enfo round */
15156 if( ownerdata->violscoretag != conshdlrdata->enforound )
15157 {
15158 ownerdata->violscoresum = violscore;
15159 ownerdata->violscoremax = violscore;
15160 ownerdata->nviolscores = 1;
15161 ownerdata->violscoretag = conshdlrdata->enforound;
15162 return;
15163 }
15164
15165 ownerdata->violscoresum += violscore;
15166 if( violscore > ownerdata->violscoremax )
15167 ownerdata->violscoremax = violscore;
15168 ++ownerdata->nviolscores;
15169}
15170
15171/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
15172 *
15173 * Each expression must either be a variable expression or have an aux-variable.
15174 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
15175 * variables present in `exprs`.
15176 */
15178 SCIP* scip, /**< SCIP data structure */
15179 SCIP_EXPR** exprs, /**< expressions where to add branching score */
15180 int nexprs, /**< number of expressions */
15181 SCIP_Real violscore, /**< violation score to add to expression */
15182 SCIP_SOL* sol, /**< current solution */
15183 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
15184 )
15185{
15186 SCIP_EXPRITER* it;
15187 SCIP_EXPR** varexprs;
15188 SCIP_EXPR* e;
15189 int nvars;
15190 int varssize;
15191 int i;
15192
15193 assert(exprs != NULL || nexprs == 0);
15194 assert(success != NULL);
15195
15196 if( nexprs == 0 )
15197 {
15198 *success = FALSE;
15199 return SCIP_OKAY;
15200 }
15201
15202 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
15203 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
15204 {
15205 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15206 return SCIP_OKAY;
15207 }
15208
15209 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15210 nvars = 0;
15211 varssize = 5;
15212 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15213
15216
15217 for( i = 0; i < nexprs; ++i )
15218 {
15219 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15220 {
15221 assert(e != NULL);
15222
15223 if( SCIPisExprVar(scip, e) )
15224 {
15225 /* add variable expression to vars array */
15226 if( varssize == nvars )
15227 {
15228 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15229 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15230 }
15231 assert(varssize > nvars);
15232
15233 varexprs[nvars++] = e;
15234 }
15235 }
15236 }
15237
15238 SCIPfreeExpriter(&it);
15239
15240 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15241
15242 SCIPfreeBufferArray(scip, &varexprs);
15243
15244 return SCIP_OKAY;
15245}
15246
15247/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15249 SCIP_EXPR* expr /**< expression */
15250 )
15251{
15252 SCIP_EXPR_OWNERDATA* ownerdata;
15253 SCIP_CONSHDLRDATA* conshdlrdata;
15254
15255 assert(expr != NULL);
15256
15257 ownerdata = SCIPexprGetOwnerData(expr);
15258 assert(ownerdata != NULL);
15259
15260 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15261 assert(conshdlrdata != NULL);
15262
15263 if( conshdlrdata->enforound != ownerdata->violscoretag )
15264 return 0.0;
15265
15266 if( ownerdata->nviolscores == 0 )
15267 return 0.0;
15268
15269 switch( conshdlrdata->branchscoreagg )
15270 {
15271 case 'a' :
15272 /* average */
15273 return ownerdata->violscoresum / ownerdata->nviolscores;
15274
15275 case 'm' :
15276 /* maximum */
15277 return ownerdata->violscoremax;
15278
15279 case 's' :
15280 /* sum */
15281 return ownerdata->violscoresum;
15282
15283 default:
15284 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15285 SCIPABORT();
15286 return SCIP_INVALID;
15287 }
15288}
15289
15290/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15291 *
15292 * @see SCIPexprGetDerivative()
15293 */
15295 SCIP* scip, /**< SCIP data structure */
15296 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15297 SCIP_VAR* var /**< variable (needs to be in the expression) */
15298 )
15299{
15300 SCIP_EXPR_OWNERDATA* ownerdata;
15301 SCIP_CONSHDLRDATA* conshdlrdata;
15302 SCIP_EXPR* varexpr;
15303
15304 assert(scip != NULL);
15305 assert(expr != NULL);
15306 assert(var != NULL);
15307
15308 /* return 0.0 for value expression */
15309 if( SCIPisExprValue(scip, expr) )
15310 {
15311 assert(SCIPexprGetDerivative(expr) == 0.0);
15312 return 0.0;
15313 }
15314
15315 /* check if an error occurred during the last SCIPevalExprGradient() call */
15316 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15317 return SCIP_INVALID;
15318
15319 ownerdata = SCIPexprGetOwnerData(expr);
15320 assert(ownerdata != NULL);
15321
15322 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15323 assert(conshdlrdata != NULL);
15324
15325 /* use variable to expressions mapping which is stored in the constraint handler data */
15326 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15327
15328 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15329 assert(varexpr != NULL);
15330 assert(SCIPisExprVar(scip, varexpr));
15331
15332 /* use difftag to decide whether the variable belongs to the expression */
15333 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15334}
15335
15336/** 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)
15337 *
15338 * @see SCIPexprGetBardot()
15339 */
15341 SCIP* scip, /**< SCIP data structure */
15342 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15343 SCIP_VAR* var /**< variable (needs to be in the expression) */
15344 )
15345{
15346 SCIP_EXPR_OWNERDATA* ownerdata;
15347 SCIP_CONSHDLRDATA* conshdlrdata;
15348 SCIP_EXPR* varexpr;
15349
15350 assert(scip != NULL);
15351 assert(expr != NULL);
15352 assert(var != NULL);
15353
15354 /* return 0.0 for value expression */
15355 if( SCIPisExprValue(scip, expr) )
15356 return 0.0;
15357
15358 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15359 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15360 return SCIP_INVALID;
15361
15362 ownerdata = SCIPexprGetOwnerData(expr);
15363 assert(ownerdata != NULL);
15364
15365 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15366 assert(conshdlrdata != NULL);
15367
15368 /* use variable to expressions mapping which is stored in the constraint handler data;
15369 * if this fails it means that we are asking for the var's component of H*u for a var
15370 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15371 */
15372 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15373
15374 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15375 assert(varexpr != NULL);
15376 assert(SCIPisExprVar(scip, varexpr));
15377
15378 /* use difftag to decide whether the variable belongs to the expression */
15379 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15380}
15381
15382/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15383 *
15384 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15385 */
15387 SCIP* scip, /**< SCIP data structure */
15388 SCIP_EXPR* expr, /**< quadratic expression */
15389 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15390 )
15391{
15392 SCIP_Real auxvalue;
15393 int nlinexprs;
15394 SCIP_Real* lincoefs;
15395 SCIP_EXPR** linexprs;
15396 int nquadexprs;
15397 int nbilinexprs;
15398 int i;
15399
15400 assert(scip != NULL);
15401 assert(expr != NULL);
15402
15403 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15404
15405 /* linear terms */
15406 for( i = 0; i < nlinexprs; ++i )
15407 {
15408 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15409 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15410 }
15411
15412 /* quadratic terms */
15413 for( i = 0; i < nquadexprs; ++i )
15414 {
15415 SCIP_EXPR* quadexprterm;
15416 SCIP_Real lincoef;
15417 SCIP_Real sqrcoef;
15418 SCIP_Real solval;
15419
15420 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15421
15422 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15423
15424 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15425 auxvalue += (lincoef + sqrcoef * solval) * solval;
15426 }
15427
15428 /* bilinear terms */
15429 for( i = 0; i < nbilinexprs; ++i )
15430 {
15431 SCIP_EXPR* expr1;
15432 SCIP_EXPR* expr2;
15433 SCIP_Real coef;
15434
15435 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15436
15440 }
15441
15442 return auxvalue;
15443}
15444
15445/**@addtogroup PublicNlhdlrInterfaceMethods
15446 * @{
15447 */
15448
15449/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15451 SCIP* scip, /**< SCIP data structure */
15452 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15453 const char* name, /**< name of nonlinear handler (must not be NULL) */
15454 const char* desc, /**< description of nonlinear handler (can be NULL) */
15455 int detectpriority, /**< detection priority of nonlinear handler */
15456 int enfopriority, /**< enforcement priority of nonlinear handler */
15457 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15458 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15459 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15460 )
15461{
15462 SCIP_CONSHDLR* conshdlr;
15463 SCIP_CONSHDLRDATA* conshdlrdata;
15464
15465 assert(scip != NULL);
15466 assert(nlhdlr != NULL);
15467 assert(detect != NULL);
15468
15469 /* find myself */
15470 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15471 if( conshdlr == NULL )
15472 {
15473 SCIPerrorMessage("nonlinear constraint handler not found");
15474 return SCIP_PLUGINNOTFOUND;
15475 }
15476
15477 /* create nlhdlr */
15478 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15479
15480 /* include into constraint handler */
15481 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15482 assert(conshdlrdata != NULL);
15483
15484 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15485
15486 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15487 ++conshdlrdata->nnlhdlrs;
15488
15489 /* sort nonlinear handlers by detection priority, in decreasing order
15490 * will happen in INIT, so only do when called late
15491 */
15492 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15493 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15494
15495 return SCIP_OKAY;
15496}
15497
15498/** get number of nonlinear handler */
15500 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15501 )
15502{
15503 SCIP_CONSHDLRDATA* conshdlrdata;
15504
15505 assert(conshdlr != NULL);
15506
15507 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15508 assert(conshdlrdata != NULL);
15509
15510 return conshdlrdata->nnlhdlrs;
15511}
15512
15513/** get nonlinear handlers */
15515 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15516 )
15517{
15518 SCIP_CONSHDLRDATA* conshdlrdata;
15519
15520 assert(conshdlr != NULL);
15521
15522 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15523 assert(conshdlrdata != NULL);
15524
15525 return conshdlrdata->nlhdlrs;
15526}
15527
15528/** returns a nonlinear handler of a given name (or NULL if not found) */
15530 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15531 const char* name /**< name of nonlinear handler */
15532 )
15533{
15534 SCIP_CONSHDLRDATA* conshdlrdata;
15535 int h;
15536
15537 assert(conshdlr != NULL);
15538 assert(name != NULL);
15539
15540 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15541 assert(conshdlrdata != NULL);
15542
15543 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15544 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15545 return conshdlrdata->nlhdlrs[h];
15546
15547 return NULL;
15548}
15549
15550/** gives expression data that a given nonlinear handler stored in an expression
15551 *
15552 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15553 */
15555 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15556 SCIP_EXPR* expr /**< expression */
15557 )
15558{
15559 SCIP_EXPR_OWNERDATA* ownerdata;
15560 int e;
15561
15562 assert(nlhdlr != NULL);
15563 assert(expr != NULL);
15564
15565 ownerdata = SCIPexprGetOwnerData(expr);
15566 assert(ownerdata != NULL);
15567
15568 for( e = 0; e < ownerdata->nenfos; ++e )
15569 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15570 return ownerdata->enfos[e]->nlhdlrexprdata;
15571
15572 return NULL;
15573}
15574
15575/** @} */
static GRAPHNODE ** active
SCIP_VAR * h
SCIP_VAR * w
SCIP_VAR * a
SCIP_VAR ** y
SCIP_VAR ** x
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:90
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:89
#define CONSHDLR_DESC
Definition cons_and.c:86
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:100
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:94
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:87
#define CONSHDLR_PROPFREQ
Definition cons_and.c:91
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:99
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:92
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:95
#define CONSHDLR_NAME
Definition cons_and.c:85
#define CONSHDLR_DELAYPROP
Definition cons_and.c:96
Constraint handler for AND constraints, .
constraint handler for bound disjunction constraints
Constraint handler for linear constraints in their most general form, .
static SCIP_Bool isBinaryProduct(SCIP *scip, SCIP_EXPR *expr)
static SCIP_RETCODE createExprVar(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR **expr, SCIP_VAR *var)
static SCIP_Real computeVertexPolyhedralMaxFacetError(SCIP *scip, SCIP_Bool overestimate, SCIP_Real *funvals, SCIP_Real *box, int nallvars, int nvars, int *nonfixedpos, SCIP_Real *facetcoefs, SCIP_Real facetconstant)
static SCIP_Bool isEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *hasvalue, SCIP_Real *value)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_EXPRITER *it, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result, SCIP_Bool *success)
#define ENFOLOG(x)
#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_RETCODE analyzeViolation(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *maxabsconsviol, SCIP_Real *maxrelconsviol, SCIP_Real *minauxviol, SCIP_Real *maxauxviol, SCIP_Real *maxvarboundviol)
static SCIP_RETCODE presolveRedundantConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss, int *nchgbds)
static SCIP_RETCODE enforceExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result)
static SCIP_RETCODE reversePropQueue(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool *infeasible, int *ntightenings)
#define BRANCH_RANDNUMINITSEED
static SCIP_RETCODE dropVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE forbidNonlinearVariablesMultiaggration(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE computeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
static SCIP_RETCODE propagateLocks(SCIP *scip, SCIP_EXPR *expr, int nlockspos, int nlocksneg)
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
static SCIP_RETCODE bilinTermAddAuxExpr(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSNONLINEAR_BILINTERM *term, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Bool *added)
static SCIP_RETCODE freeVarExprs(SCIP *scip, SCIP_CONSDATA *consdata)
#define DIALOG_NAME
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol)
#define consRespropNonlinear
static SCIP_RETCODE consSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
static void addExprsViolScore(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE tightenAuxVarBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL bounds, SCIP_Bool *cutoff, int *ntightenings)
#define TABLE_DESC_NLHDLR
static SCIP_RETCODE replaceBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_HASHMAP *exprmap, SCIP_EXPRITER *it, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE computeVertexPolyhedralFacetBivariate(SCIP *scip, SCIP_Bool overestimate, SCIP_Real p1[2], SCIP_Real p2[2], SCIP_Real p3[2], SCIP_Real p4[2], SCIP_Real p1val, SCIP_Real p2val, SCIP_Real p3val, SCIP_Real p4val, SCIP_Real xstar[2], SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
static SCIP_RETCODE tryAddGadgetEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
#define consInitpreNonlinear
static SCIP_RETCODE addExprViolScoresAuxVars(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore, SCIP_VAR **auxvars, int nauxvars, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE detectNlhdlr(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE computeVertexPolyhedralFacetLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_Real *xstar, SCIP_Real *box, int nallvars, int *nonfixedpos, SCIP_Real *funvals, int nvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
#define TABLE_EARLIEST_STAGE_NLHDLR
#define VERTEXPOLY_RANDNUMINITSEED
static SCIP_RETCODE getFactorizedBinaryQuadraticExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *sumexpr, int minterms, SCIP_EXPR **newexpr, int *naddconss)
#define consDelvarsNonlinear
static SCIP_RETCODE reformulateFactorizedBinaryQuadratic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_VAR *facvar, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_EXPR **newexpr, int *naddconss)
static SCIP_RETCODE getConsRelViolation(SCIP *scip, SCIP_CONS *cons, SCIP_Real *viol, SCIP_SOL *sol, SCIP_Longint soltag)
#define consGetDiveBdChgsNonlinear
static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE getBinaryProductExprDo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, SCIP_Bool empathy4and)
static SCIP_RETCODE registerBranchingCandidatesAllUnfixed(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
static SCIP_Bool isIntervalBetter(SCIP *scip, SCIP_Bool subsetsufficient, SCIP_INTERVAL newinterval, SCIP_INTERVAL oldinterval)
static SCIP_RETCODE detectNlhdlrs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define TABLE_EARLIEST_STAGE_NONLINEAR
static SCIP_RETCODE getBinaryProductExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *exprmap, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
#define TABLE_DESC_NONLINEAR
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getViolSplitWeight(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var, SCIP_SOL *sol)
static SCIP_RETCODE freeEnfoData(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool freeauxvar)
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE getBilinearBinaryTerms(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_VAR **xs, SCIP_VAR **ys, int *childidxs, int *nterms)
static SCIP_RETCODE storeVarExprs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata)
static SCIP_RETCODE buildVertexPolyhedralSeparationLP(SCIP *scip, int nvars, SCIP_LPI **lp)
static SCIP_RETCODE tryAddGadgetSquaredDifference(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_CONS *cons, SYM_GRAPH *graph, int sumnodeidx, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs)
static SCIP_RETCODE tryAddGadgetBilinearProductSignedPerm(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE propConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool force, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
static SCIP_RETCODE forwardPropExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *rootexpr, SCIP_Bool tightenauxvars, SCIP_Bool *infeasible, int *ntightenings)
static SCIP_RETCODE consEnfo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_Bool isSingleLockedCand(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Bool branchAuxNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE presolveImplint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nchgvartypes, SCIP_Bool *infeasible)
#define TABLE_NAME_NONLINEAR
#define TABLE_NAME_NLHDLR
static SCIP_RETCODE tryAddGadgetEvenOperatorSum(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
static SCIP_RETCODE deinitSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE ensureLocVarsArraySize(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **vals, int nelems, int *maxnelems)
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE 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_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
#define VERTEXPOLY_MAXPERTURBATION
static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE catchVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
#define DIALOG_ISSUBMENU
static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
#define VERTEXPOLY_USEDUALSIMPLEX
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)
static SCIP_RETCODE collectBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, BRANCHCAND *cands, int *ncands)
static SCIP_RETCODE branching(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_RESULT *result)
static SCIP_RETCODE bilinearTermsInsertAll(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define VERTEXPOLY_ADJUSTFACETFACTOR
#define TABLE_POSITION_NONLINEAR
static SCIP_RETCODE initSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE removeSingleLockedVars(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRITER *it, SCIP_HASHMAP *exprcands)
static SCIP_RETCODE branchingIntegralOrNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Longint soltag, SCIP_Real maxrelconsviol, SCIP_Bool *branchintegral, SCIP_Bool *cutoff)
static void findUnlockedLinearVar(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
static SCIP_RETCODE propExprDomains(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getConsAbsViolation(SCIP_CONS *cons)
static SCIP_RETCODE bilinearTermsFree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
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)
static SCIP_RETCODE presolveMergeConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
static SCIP_Real getDomainCenter(SCIP *scip, SCIP_VAR *var)
#define TABLE_POSITION_NLHDLR
static SCIP_RETCODE ensureOpenArraySizeSymdetect(SCIP *scip, int **openidx, int nelems, int *maxnelems)
static SCIP_RETCODE canonicalizeConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_PRESOLTIMING presoltiming, SCIP_Bool *infeasible, int *ndelconss, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
#define 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:312
#define SCIPdebugAddSolVal(scip, var, val)
Definition debug.h:311
#define NULL
Definition def.h:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define EPSROUND(x, eps)
Definition def.h:200
#define EPSISINT(x, eps)
Definition def.h:202
#define SCIP_REAL_MAX
Definition def.h:165
#define SCIP_INVALID
Definition def.h:185
#define SCIP_INTERVAL_INFINITY
Definition def.h:187
#define SCIP_Bool
Definition def.h:98
#define MIN(x, y)
Definition def.h:231
#define MAX3(x, y, z)
Definition def.h:235
#define SCIP_Real
Definition def.h:163
#define ABS(x)
Definition def.h:223
#define EPSFRAC(x, eps)
Definition def.h:201
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIP_CALL_ABORT(x)
Definition def.h:341
#define SCIP_LONGINT_FORMAT
Definition def.h:155
#define SCIPABORT()
Definition def.h:334
#define REALABS(x)
Definition def.h:189
#define SCIP_CALL(x)
Definition def.h:362
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)
struct SCIP_ConsNonlinear_BilinTerm SCIP_CONSNONLINEAR_BILINTERM
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)
struct SCIP_ConsNonlinear_Auxexpr SCIP_CONSNONLINEAR_AUXEXPR
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:398
SCIP_Bool SCIPisExprVaridx(SCIP *scip, SCIP_EXPR *expr)
SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
Definition expr_abs.c:546
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition expr_sum.c:1154
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:3209
SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
Definition expr_pow.c:3234
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:1117
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_value.c:274
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:3185
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNObjVars(SCIP *scip)
Definition scip_prob.c:2616
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2340
int SCIPgetNImplVars(SCIP *scip)
Definition scip_prob.c:2387
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2569
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
int SCIPgetNTotalVars(SCIP *scip)
Definition scip_prob.c:3064
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition misc.c:3576
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3482
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition misc.c:3833
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition misc.c:3860
SCIP_Bool SCIPhashsetIsEmpty(SCIP_HASHSET *hashset)
Definition misc.c:4027
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition misc.c:3843
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition misc.c:3802
SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
Definition misc.c:3901
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
#define SCIPhashTwo(a, b)
Definition pub_misc.h:568
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:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2596
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition lpi_clp.cpp:1179
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition lpi_clp.cpp:3947
SCIP_RETCODE SCIPlpiChgObjsen(SCIP_LPI *lpi, SCIP_OBJSEN objsen)
Definition lpi_clp.cpp:1232
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition lpi_clp.cpp:3861
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition lpi_clp.cpp:643
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition lpi_clp.cpp:2637
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition lpi_clp.cpp:3720
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition lpi_clp.cpp:2816
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition lpi_clp.cpp:1908
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition lpi_clp.cpp:1833
SCIP_RETCODE SCIPlpiLoadColLP(SCIP_LPI *lpi, SCIP_OBJSEN objsen, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition lpi_clp.cpp:677
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition lpi_clp.cpp:531
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition lpi_clp.cpp:1252
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition lpi_clp.cpp:1447
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition lpi_clp.cpp:1429
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:4067
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsgPrint
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
#define SCIPdebugMsg
void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:167
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition scip_param.c:326
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10511
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition misc.c:10498
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition lp.c:17545
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition lp.c:17534
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition lp.c:17509
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4346
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5112
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4778
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4316
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4336
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:4735
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8409
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition cons.c:8507
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8558
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition cons.c:8688
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8698
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8450
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8628
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition cons.c:8486
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8389
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition cons.c:8496
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8638
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8568
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8658
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:225
SCIP_RETCODE SCIPinsertDatatreeLong(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Longint value)
SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
Definition dialog.c:436
SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
Definition dialog.c:1013
SCIP_RETCODE SCIPdialoghdlrAddHistory(SCIP_DIALOGHDLR *dialoghdlr, SCIP_DIALOG *dialog, const char *command, SCIP_Bool escapecommand)
Definition dialog.c:725
SCIP_RETCODE SCIPincludeDialog(SCIP *scip, SCIP_DIALOG **dialog, SCIP_DECL_DIALOGCOPY((*dialogcopy)), SCIP_DECL_DIALOGEXEC((*dialogexec)), SCIP_DECL_DIALOGDESC((*dialogdesc)), SCIP_DECL_DIALOGFREE((*dialogfree)), const char *name, const char *desc, SCIP_Bool issubmenu, SCIP_DIALOGDATA *dialogdata)
Definition scip_dialog.c:59
SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
Definition dialog.c:1046
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition scip_event.c:241
SCIP_IMPLINTTYPE SCIPeventGetNewImpltype(SCIP_EVENT *event)
Definition event.c:1513
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition event.c:1567
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:293
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:333
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:4054
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:1059
SCIP_IMPLINTTYPE SCIPexprGetIntegrality(SCIP_EXPR *expr)
Definition expr.c:4091
SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
Definition scip_expr.c:1817
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1661
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3872
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition expr.c:4226
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:2040
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition expr_pow.c:3448
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1490
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition scip_expr.c:1692
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition expriter.c:969
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition scip_expr.c:1677
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:930
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition expr.c:3933
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition expr.c:3972
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1479
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition scip_expr.c:2083
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition expr.c:3959
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition expr.c:4101
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition expr.c:4262
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:4141
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition scip_expr.c:1274
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1554
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition expriter.c:756
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1468
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:2420
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1443
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:1457
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:1406
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:2362
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition scip_expr.c:1512
SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:740
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition expr_value.c:298
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:1501
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition expr.c:3946
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition expr.c:4044
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition scip_expr.c:1845
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:2402
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition expr.c:4000
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3882
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition expr_sum.c:1569
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:1344
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition expr_var.c:424
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition expriter.c:838
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition expr.c:4028
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:4186
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:707
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition scip_expr.c:2376
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:696
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_IMPLINTTYPE integrality)
Definition expr.c:4111
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:1307
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition scip_expr.c:1435
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:3862
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition scip_expr.c:2121
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition expr.c:4015
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:1798
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1742
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition expr.c:3895
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition expriter.c:721
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition scip_heur.c:263
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition heur.c:1467
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)
struct SCIP_Interval SCIP_INTERVAL
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition scip_lp.c:253
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition scip_lp.c:444
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition scip_lp.c:434
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition scip_mem.h:91
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#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:177
SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:227
int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:187
SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:207
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:167
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:277
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:247
int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
Definition nlhdlr.c:197
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8513
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
Definition lp.c:17850
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
const char * SCIProwGetName(SCIP_ROW *row)
Definition lp.c:17745
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1814
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17706
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition scip_sepa.c:345
SCIP_SOLORIGIN SCIPsolGetOrigin(SCIP_SOL *sol)
Definition sol.c:4145
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:884
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition sol.c:4274
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition scip_sol.c:608
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1506
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition scip_sol.c:1719
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:453
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1765
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:2005
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:101
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_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition scip_table.c:62
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition scip_timing.c:76
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_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:6401
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition scip_var.c:5176
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition var.c:23683
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23478
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition scip_var.c:11350
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23386
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24268
SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
Definition var.c:23506
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23900
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition var.c:23618
SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
Definition scip_var.c:10218
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24142
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23652
SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:225
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition scip_var.c:5634
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition scip_var.c:11188
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition scip_var.c:5570
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23490
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition scip_var.c:10113
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24642
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24234
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24653
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24120
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
Definition var.c:23463
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17274
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4328
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition misc.c:1019
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition misc.c:995
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition misc.c:1081
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition misc.c:1236
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition misc.c:1132
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition misc.c:10245
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition misc.c:10223
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition misc.c:6144
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:5581
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
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)
return SCIP_OKAY
SCIPfreeSol(scip, &heurdata->sol))
SCIPfreeRandom(scip, &heurdata->randnumgen)
int c
SCIP_Bool cutoff
SCIPcreateRandom(scip, &heurdata->randnumgen, DEFAULT_RANDSEED, TRUE))
static SCIP_SOL * sol
int nlpcands
int r
SCIP_Real obj
SCIP_VAR ** lpcands
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
SCIP_Real * lpcandsfrac
static SCIP_Bool propagate
static SCIP_VAR ** vars
SCIP_Real alpha
NLP local search primal heuristic using sub-SCIPs.
primal heuristic that tries a given solution
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition implics.c:1141
static volatile int nterms
Definition interrupt.c:47
SCIP_Bool SCIPlapackIsAvailable(void)
SCIP_RETCODE SCIPlapackSolveLinearEquations(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
interface methods for lapack functions
static const char * paramname[]
Definition lpi_msk.c:5172
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition nlhdlr.c:402
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:354
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition nlhdlr.c:753
SCIP_RETCODE SCIPnlhdlrCollectStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, SCIP_DATATREE *datatree)
Definition nlhdlr.c:797
private functions of nonlinear handlers of nonlinear constraints
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition nlhdlr.h:140
#define SCIPnlhdlrResetNDetectionslast(nlhdlr)
Definition nlhdlr.h:138
#define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
Definition nlhdlr.h:139
nonlinear handlers for convex and concave expressions, respectively
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)
#define SCIPisFinite(x)
Definition pub_misc.h:82
methods for sorting joint arrays of various types
public methods for data tree structure
public functions to work with algebraic expressions
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
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::@055261256347130033265073212045155110332303333345 aux
SCIP_Real sup
SCIP_Real inf
structs for symmetry computations
methods for dealing with symmetry detection graphs
struct SCIP_Clock SCIP_CLOCK
Definition type_clock.h:49
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:955
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:937
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSEXIT(x)
Definition type_cons.h:136
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:866
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:768
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSDISABLE(x)
Definition type_cons.h:735
struct SYM_Graph SYM_GRAPH
Definition type_cons.h:68
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition type_cons.h:919
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:505
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:884
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:611
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:690
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:844
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:705
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:560
#define SCIP_DECL_CONSENABLE(x)
Definition type_cons.h:720
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:675
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:809
#define SCIP_DECL_CONSINIT(x)
Definition type_cons.h:126
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
#define SCIP_DECL_CONSDELVARS(x)
Definition type_cons.h:752
struct SCIP_Dialog SCIP_DIALOG
Definition type_dialog.h:50
#define SCIP_DECL_DIALOGEXEC(x)
Definition type_dialog.h:96
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition type_event.h:127
#define SCIP_EVENTTYPE_TYPECHANGED
Definition type_event.h:86
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition type_event.h:106
#define SCIP_EVENTTYPE_FORMAT
Definition type_event.h:157
#define SCIP_EVENTTYPE_BOUNDRELAXED
Definition type_event.h:126
#define SCIP_EVENTTYPE_SOLFOUND
Definition type_event.h:146
uint64_t SCIP_EVENTTYPE
Definition type_event.h:156
#define SCIP_EVENTTYPE_IMPLTYPECHANGED
Definition type_event.h:87
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition type_event.h:125
struct SCIP_Expr SCIP_EXPR
Definition type_expr.h:55
struct SCIP_ExprIter SCIP_EXPRITER
Definition type_expr.h:722
#define SCIP_DECL_EXPR_OWNERCREATE(x)
Definition type_expr.h:143
SCIP_EXPRCURV
Definition type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition type_expr.h:63
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
@ SCIP_EXPRCURV_UNKNOWN
Definition type_expr.h:62
@ SCIP_EXPRCURV_CONCAVE
Definition type_expr.h:64
#define SCIP_EXPRITER_VISITINGCHILD
Definition type_expr.h:695
#define SCIP_DECL_EXPR_OWNERPRINT(x)
Definition type_expr.h:109
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition type_expr.h:80
SCIP_MONOTONE
Definition type_expr.h:70
@ SCIP_MONOTONE_CONST
Definition type_expr.h:74
@ SCIP_MONOTONE_UNKNOWN
Definition type_expr.h:71
@ SCIP_MONOTONE_INC
Definition type_expr.h:72
@ SCIP_MONOTONE_DEC
Definition type_expr.h:73
#define SCIP_DECL_EXPR_INTEVALVAR(x)
Definition type_expr.h:163
@ SCIP_EXPRITER_BFS
Definition type_expr.h:717
@ SCIP_EXPRITER_DFS
Definition type_expr.h:718
@ SCIP_EXPRITER_RTOPOLOGIC
Definition type_expr.h:716
struct SYM_ExprData SYM_EXPRDATA
Definition type_expr.h:56
#define SCIP_DECL_EXPR_MAPEXPR(x)
Definition type_expr.h:182
#define SCIP_DECL_EXPR_OWNERFREE(x)
Definition type_expr.h:95
#define SCIP_EXPRITER_LEAVEEXPR
Definition type_expr.h:697
#define SCIP_DECL_EXPR_OWNEREVALACTIVITY(x)
Definition type_expr.h:125
#define SCIP_EXPRITER_ENTEREXPR
Definition type_expr.h:694
struct SCIP_Heur SCIP_HEUR
Definition type_heur.h:76
@ SCIP_BRANCHDIR_DOWNWARDS
@ SCIP_BRANCHDIR_UPWARDS
struct SCIP_Clique SCIP_CLIQUE
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
struct SCIP_Col SCIP_COL
Definition type_lp.h:99
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
@ SCIP_SIDETYPE_RIGHT
Definition type_lp.h:66
@ SCIP_SIDETYPE_LEFT
Definition type_lp.h:65
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
@ SCIP_LPSOLSTAT_UNBOUNDEDRAY
Definition type_lp.h:46
struct SCIP_LPi SCIP_LPI
Definition type_lpi.h:106
@ 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
struct SCIP_RowPrep SCIP_ROWPREP
Definition type_misc.h:173
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_SORTINDCOMP(x)
Definition type_misc.h:181
struct SCIP_RandNumGen SCIP_RANDNUMGEN
Definition type_misc.h:127
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:192
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_PtrArray SCIP_PTRARRAY
Definition type_misc.h:124
struct SCIP_HashSet SCIP_HASHSET
Definition type_misc.h:112
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
struct SCIP_Queue SCIP_QUEUE
Definition type_misc.h:76
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition type_nlhdlr.h:52
#define SCIP_DECL_NLHDLREVALAUX(x)
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition type_nlhdlr.h:53
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition type_nlhdlr.h:54
unsigned int SCIP_NLHDLR_METHOD
Definition type_nlhdlr.h:57
#define SCIP_DECL_NLHDLRDETECT(x)
#define SCIP_NLHDLR_METHOD_NONE
Definition type_nlhdlr.h:50
struct SCIP_Nlhdlr SCIP_NLHDLR
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
#define SCIP_NLHDLR_METHOD_ALL
Definition type_nlhdlr.h:55
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition type_nlhdlr.h:51
struct SCIP_NlRow SCIP_NLROW
Definition type_nlp.h:41
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_BRANCHED
Definition type_result.h:54
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SOLVELP
Definition type_result.h:55
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_LPERROR
@ SCIP_READERROR
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ 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
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
@ SCIP_SOLORIGIN_LPSOL
Definition type_sol.h:44
@ SCIP_STATUS_OPTIMAL
Definition type_stat.h:43
@ SCIP_STATUS_UNBOUNDED
Definition type_stat.h:45
@ SCIP_STATUS_INFORUNBD
Definition type_stat.h:46
@ SCIP_STATUS_INFEASIBLE
Definition type_stat.h:44
enum SYM_Symtype SYM_SYMTYPE
@ SYM_CONSOPTYPE_SUM
@ SYM_CONSOPTYPE_COEF
@ SYM_CONSOPTYPE_SQDIFF
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_DECL_TABLEOUTPUT(x)
Definition type_table.h:124
#define SCIP_DECL_TABLECOLLECT(x)
Definition type_table.h:133
#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
struct SCIP_Node SCIP_NODE
Definition type_tree.h:63
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
enum SCIP_ImplintType SCIP_IMPLINTTYPE
Definition type_var.h:117
@ SCIP_IMPLINTTYPE_NONE
Definition type_var.h:90
@ SCIP_IMPLINTTYPE_STRONG
Definition type_var.h:106
@ SCIP_IMPLINTTYPE_WEAK
Definition type_var.h:91
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:53
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141