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/cons_setppc.h"
71#include "scip/heur_subnlp.h"
72#include "scip/heur_trysol.h"
73#include "scip/lapack_calls.h"
74#include "scip/debug.h"
75#include "scip/dialog_default.h"
76#include "scip/scip_expr.h"
77#include "scip/symmetry_graph.h"
78#include "scip/prop_symmetry.h"
80#include "scip/pub_misc_sort.h"
81#include "scip/scip_datatree.h"
82
83/* fundamental constraint handler properties */
84#define CONSHDLR_NAME "nonlinear"
85#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
86#define CONSHDLR_ENFOPRIORITY 50 /**< priority of the constraint handler for constraint enforcing */
87#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
90#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
91
92/* optional constraint handler properties */
93#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
94#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
95#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
96
97#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
98#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
99#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
100
101#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
102#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
103
104/* properties of the nonlinear constraint handler statistics table */
105#define TABLE_NAME_NONLINEAR "cons_nonlinear"
106#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
107#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
108#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
109
110/* properties of the nonlinear handler statistics table */
111#define TABLE_NAME_NLHDLR "nlhdlr"
112#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
113#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
114#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
115
116#define DIALOG_NAME "nlhdlrs"
117#define DIALOG_DESC "display nonlinear handlers"
118#define DIALOG_ISSUBMENU FALSE
119
120#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
121#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
122#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
123#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
124
125#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
126
127#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
128
129/** translate from one value of infinity to another
130 *
131 * if val is &ge; infty1, then give infty2, else give val
132 */
133#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
134
135/** translates x to 2^x for non-negative integer x */
136#define POWEROFTWO(x) (0x1u << (x))
137
138#ifdef ENFO_LOGGING
139#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
140FILE* enfologfile = NULL;
141#else
142#define ENFOLOG(x)
143#endif
144
145/*
146 * Data structures
147 */
148
149/** enforcement data of an expression */
150typedef struct
151{
152 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
153 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
154 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
155 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
156 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
157 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
158 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
159} EXPRENFO;
160
161/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
162struct SCIP_Expr_OwnerData
163{
164 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
165
166 /* locks and monotonicity */
167 int nlockspos; /**< positive locks counter */
168 int nlocksneg; /**< negative locks counter */
169 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
170 int monotonicitysize; /**< length of monotonicity array */
171
172 /* propagation (in addition to activity that is stored in expr) */
173 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
174 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
175 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
176
177 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
178 EXPRENFO** enfos; /**< enforcements */
179 int nenfos; /**< number of enforcements, or -1 if not initialized */
180 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
181 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
182 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
183 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
184 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
185
186 /* branching */
187 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
188 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
189 int nviolscores; /**< number of violation scores stored for this expression */
190 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
191
192 /* additional data for variable expressions (TODO move into sub-struct?) */
193 SCIP_CONS** conss; /**< constraints in which this variable appears */
194 int nconss; /**< current number of constraints in conss */
195 int consssize; /**< length of conss array */
196 SCIP_Bool consssorted; /**< is the array of constraints sorted */
197
198 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
199};
200
201/** constraint data for nonlinear constraints */
202struct SCIP_ConsData
203{
204 /* data that defines the constraint: expression and sides */
205 SCIP_EXPR* expr; /**< expression that represents this constraint */
206 SCIP_Real lhs; /**< left-hand side */
207 SCIP_Real rhs; /**< right-hand side */
208
209 /* variables */
210 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
211 int nvarexprs; /**< total number of variable expressions */
212 SCIP_Bool catchedevents; /**< do we catch events on variables? */
213
214 /* constraint violation */
215 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
216 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
217 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
218 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
219
220 /* status flags */
221 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
222 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
223
224 /* locks */
225 int nlockspos; /**< number of positive locks */
226 int nlocksneg; /**< number of negative locks */
227
228 /* repair infeasible solutions */
229 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
230 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
231 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
232 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
233
234 /* miscellaneous */
235 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
236 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
237 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
238};
239
240/** constraint upgrade method */
241typedef struct
242{
243 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
244 int priority; /**< priority of upgrading method */
245 SCIP_Bool active; /**< is upgrading enabled */
247
248/** constraint handler data */
249struct SCIP_ConshdlrData
250{
251 /* nonlinear handler */
252 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
253 int nnlhdlrs; /**< number of nonlinear handlers */
254 int nlhdlrssize; /**< size of nlhdlrs array */
255 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
256 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
257 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
258
259 /* constraint upgrades */
260 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
261 int consupgradessize; /**< size of consupgrades array */
262 int nconsupgrades; /**< number of constraint upgrade methods */
263
264 /* other plugins */
265 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
266 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
267 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
268
269 /* tags and counters */
270 int auxvarid; /**< unique id for the next auxiliary variable */
271 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
272 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
273 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
274 unsigned int enforound; /**< total number of enforcement calls, including current one */
275 int lastconsindex; /**< last used consindex, plus one */
276
277 /* activity intervals and domain propagation */
278 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
279 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
280 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
281 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
282 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
283
284 /* parameters */
285 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
286 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
287 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
288 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
289 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
290 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
291 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
292 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
293 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
294 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
295 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
296 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
297 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
298 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
299 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
300 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
301 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
302 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
303 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
304 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
305 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 */
306 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
307 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) */
308 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
309 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
310 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
311 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
312 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
313 SCIP_Real branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
314 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
315 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
316 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
317 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
318 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
319 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
320 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
321 SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
322 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) */
323 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
324
325 /* statistics */
326 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
327 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
328 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 */
329 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
330 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
331 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
332 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
333 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
334
335 /* facets of envelops of vertex-polyhedral functions */
336 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
337 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
338
339 /* hashing of bilinear terms */
340 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
341 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
342 int nbilinterms; /**< total number of bilinear terms */
343 int bilintermssize; /**< size of bilinterms array */
344 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
345
346 /* branching */
347 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
348 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
349
350 /* misc */
351 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
352 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
353 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
354};
355
356/** branching candidate with various scores */
357typedef struct
358{
359 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
360 SCIP_VAR* var; /**< variable that is branching candidate */
361 SCIP_Real auxviol; /**< aux-violation score of candidate */
362 SCIP_Real domain; /**< domain score of candidate */
363 SCIP_Real dual; /**< dual score of candidate */
364 SCIP_Real pscost; /**< pseudo-cost score of candidate */
365 SCIP_Real vartype; /**< variable type score of candidate */
366 SCIP_Real fractionality; /**< fractionality score of candidate */
367 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
368} BRANCHCAND;
369
370/*
371 * Local methods
372 */
373
374/* forward declaration */
375static
377 SCIP* scip, /**< SCIP data structure */
378 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
379 SCIP_EXPR* rootexpr, /**< expression */
380 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
381 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
382 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
383 );
384
385/** frees auxiliary variables of expression, if any */
386static
388 SCIP* scip, /**< SCIP data structure */
389 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
390 )
391{
392 SCIP_EXPR_OWNERDATA* mydata;
393
394 assert(scip != NULL);
395 assert(expr != NULL);
396
397 mydata = SCIPexprGetOwnerData(expr);
398 assert(mydata != NULL);
399
400 if( mydata->auxvar == NULL )
401 return SCIP_OKAY;
402
403 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
404
405 /* remove variable locks
406 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
407 */
408 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
409
410 /* release auxiliary variable */
411 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
412 assert(mydata->auxvar == NULL);
413
414 return SCIP_OKAY;
415}
416
417/** frees data used for enforcement of expression, that is, nonlinear handlers
418 *
419 * can also clear indicators whether expr needs enforcement methods, that is,
420 * free an associated auxiliary variable and reset the nactivityuses counts
421 */
422static
424 SCIP* scip, /**< SCIP data structure */
425 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
426 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
427 )
428{
429 SCIP_EXPR_OWNERDATA* mydata;
430 int e;
431
432 mydata = SCIPexprGetOwnerData(expr);
433 assert(mydata != NULL);
434
435 if( freeauxvar )
436 {
437 /* free auxiliary variable */
438 SCIP_CALL( freeAuxVar(scip, expr) );
439 assert(mydata->auxvar == NULL);
440
441 /* reset count on activity and auxvar usage */
442 mydata->nactivityusesprop = 0;
443 mydata->nactivityusessepa = 0;
444 mydata->nauxvaruses = 0;
445 }
446
447 /* free data stored by nonlinear handlers */
448 for( e = 0; e < mydata->nenfos; ++e )
449 {
450 SCIP_NLHDLR* nlhdlr;
451
452 assert(mydata->enfos[e] != NULL);
453
454 nlhdlr = mydata->enfos[e]->nlhdlr;
455 assert(nlhdlr != NULL);
456
457 if( mydata->enfos[e]->issepainit )
458 {
459 /* call the separation deinitialization callback of the nonlinear handler */
460 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
461 mydata->enfos[e]->issepainit = FALSE;
462 }
463
464 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
465 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
466 {
467 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
468 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
469 }
470
471 /* free enfo data */
472 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
473 }
474
475 /* free array with enfo data */
476 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
477
478 /* we need to look at this expression in detect again */
479 mydata->nenfos = -1;
480
481 return SCIP_OKAY;
482}
483
484/** callback that frees data that this conshdlr stored in an expression */
485static
487{
488 assert(scip != NULL);
489 assert(expr != NULL);
490 assert(ownerdata != NULL);
491 assert(*ownerdata != NULL);
492
493 /* expression should not be locked anymore */
494 assert((*ownerdata)->nlockspos == 0);
495 assert((*ownerdata)->nlocksneg == 0);
496
497 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
498
499 /* expression should not be enforced anymore */
500 assert((*ownerdata)->nenfos <= 0);
501 assert((*ownerdata)->auxvar == NULL);
502
503 if( SCIPisExprVar(scip, expr) )
504 {
505 SCIP_CONSHDLRDATA* conshdlrdata;
506 SCIP_VAR* var;
507
508 /* there should be no constraints left that still use this variable */
509 assert((*ownerdata)->nconss == 0);
510 /* thus, there should also be no variable event catched (via this exprhdlr) */
511 assert((*ownerdata)->filterpos == -1);
512
513 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
514
515 /* update var2expr hashmap in conshdlrdata */
516 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
517 assert(conshdlrdata != NULL);
518
519 var = SCIPgetVarExprVar(expr);
520 assert(var != NULL);
521
522 /* remove var -> expr map from hashmap if present
523 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
524 * if variable-expression stored for var is different, then also do nothing)
525 */
526 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
527 {
528 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
529 }
530 }
531
532 SCIPfreeBlockMemory(scip, ownerdata);
533
534 return SCIP_OKAY;
535}
536
537static
539{ /*lint --e{715}*/
540 assert(ownerdata != NULL);
541
542 /* print nl handlers associated to expr */
543 if( ownerdata->nenfos > 0 )
544 {
545 int i;
546 SCIPinfoMessage(scip, file, " {");
547
548 for( i = 0; i < ownerdata->nenfos; ++i )
549 {
550 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
551 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
552 SCIPinfoMessage(scip, file, "a");
553 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
554 SCIPinfoMessage(scip, file, "u");
555 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
556 SCIPinfoMessage(scip, file, "o");
557 if( i < ownerdata->nenfos-1 )
558 SCIPinfoMessage(scip, file, ", ");
559 }
560
561 SCIPinfoMessage(scip, file, "}");
562 }
563
564 /* print aux var associated to expr */
565 if( ownerdata->auxvar != NULL )
566 {
567 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
568 }
569 SCIPinfoMessage(scip, file, "\n");
570
571 return SCIP_OKAY;
572}
573
574/** possibly reevaluates and then returns the activity of the expression
575 *
576 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
577 */
578static
580{
581 SCIP_CONSHDLRDATA* conshdlrdata;
582
583 assert(scip != NULL);
584 assert(expr != NULL);
585 assert(ownerdata != NULL);
586
587 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
588 assert(conshdlrdata != NULL);
589
590 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
591 {
592 /* update activity of expression */
593 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
594
595 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
596 }
597
598 return SCIP_OKAY;
599}
600
601/** callback that creates data that this conshdlr wants to store in an expression */
602static
604{
605 assert(scip != NULL);
606 assert(expr != NULL);
607 assert(ownerdata != NULL);
608
610 (*ownerdata)->nenfos = -1;
611 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
612
613 if( SCIPisExprVar(scip, expr) )
614 {
615 SCIP_CONSHDLRDATA* conshdlrdata;
616 SCIP_VAR* var;
617
618 (*ownerdata)->filterpos = -1;
619
620 /* add to var2expr hashmap if not having expr for var yet */
621
622 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
623 assert(conshdlrdata != NULL);
624
625 var = SCIPgetVarExprVar(expr);
626
627 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
628 {
629 /* store the variable expression in the hashmap */
630 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
631 }
632 else
633 {
634 /* if expr was just created, then it shouldn't already be stored as image of var */
635 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
636 }
637 }
638 else
639 {
640 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
641 (*ownerdata)->filterpos = -2;
642 }
643
644 *ownerfree = exprownerFree;
645 *ownerprint = exprownerPrint;
646 *ownerevalactivity = exprownerEvalactivity;
647
648 return SCIP_OKAY;
649}
650
651/** creates a variable expression or retrieves from hashmap in conshdlr data */
652static
654 SCIP* scip, /**< SCIP data structure */
655 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
656 SCIP_EXPR** expr, /**< pointer where to store expression */
657 SCIP_VAR* var /**< variable to be stored */
658 )
659{
660 assert(conshdlr != NULL);
661 assert(expr != NULL);
662 assert(var != NULL);
663
664 /* get variable expression representing the given variable if there is one already */
665 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
666
667 if( *expr == NULL )
668 {
669 /* create a new variable expression; this also captures the expression */
670 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
671 assert(*expr != NULL);
672 /* exprownerCreate should have added var->expr to var2expr */
673 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
674 }
675 else
676 {
677 /* only capture already existing expr to get a consistent uses-count */
678 SCIPcaptureExpr(*expr);
679 }
680
681 return SCIP_OKAY;
682}
683
684/* map var exprs to var-expr from var2expr hashmap */
685static
687{ /*lint --e{715}*/
688 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
689
690 assert(sourcescip != NULL);
691 assert(targetscip != NULL);
692 assert(sourceexpr != NULL);
693 assert(targetexpr != NULL);
694 assert(*targetexpr == NULL);
695 assert(mapexprdata != NULL);
696
697 /* do not provide map if not variable */
698 if( !SCIPisExprVar(sourcescip, sourceexpr) )
699 return SCIP_OKAY;
700
701 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
702
703 return SCIP_OKAY;
704}
705
706/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
707static
709{ /*lint --e{715}*/
710 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
711 SCIP_VAR* var;
712
713 assert(sourcescip != NULL);
714 assert(targetscip != NULL);
715 assert(sourceexpr != NULL);
716 assert(targetexpr != NULL);
717 assert(*targetexpr == NULL);
718 assert(mapexprdata != NULL);
719
720 /* do not provide map if not variable */
721 if( !SCIPisExprVar(sourcescip, sourceexpr) )
722 return SCIP_OKAY;
723
724 var = SCIPgetVarExprVar(sourceexpr);
725 assert(var != NULL);
726
727 /* transform variable */
728 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
729 assert(var != NULL);
730
731 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
732
733 return SCIP_OKAY;
734}
735
736/** stores all variable expressions into a given constraint */
737static
739 SCIP* scip, /**< SCIP data structure */
740 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
741 SCIP_CONSDATA* consdata /**< constraint data */
742 )
743{
744 SCIP_CONSHDLRDATA* conshdlrdata;
745 int varexprssize;
746 int i;
747
748 assert(consdata != NULL);
749
750 /* skip if we have stored the variable expressions already */
751 if( consdata->varexprs != NULL )
752 return SCIP_OKAY;
753
754 assert(consdata->varexprs == NULL);
755 assert(consdata->nvarexprs == 0);
756
757 /* get an upper bound on number of variable expressions */
758 if( consdata->issimplified )
759 {
760 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
761 * so we cannot have more variable expression than the number of active variables
762 */
763 varexprssize = SCIPgetNVars(scip);
764 }
765 else
766 {
767 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
768 }
769
770 /* create array to store all variable expressions */
771 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
772
773 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
774 assert(varexprssize >= consdata->nvarexprs);
775
776 /* shrink array if there are less variables in the expression than in the problem */
777 if( varexprssize > consdata->nvarexprs )
778 {
779 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
780 }
781
782 conshdlrdata = SCIPconshdlrGetData(conshdlr);
783 assert(conshdlrdata != NULL);
784 assert(conshdlrdata->var2expr != NULL);
785
786 /* ensure that for every variable an entry exists in the var2expr hashmap
787 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
788 */
789 for( i = 0; i < consdata->nvarexprs; ++i )
790 {
791 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
792 {
793 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
794 }
795 }
796
797 return SCIP_OKAY;
798}
799
800/** frees all variable expression stored in storeVarExprs() */
801static
803 SCIP* scip, /**< SCIP data structure */
804 SCIP_CONSDATA* consdata /**< constraint data */
805 )
806{
807 int i;
808
809 assert(consdata != NULL);
810
811 /* skip if we have stored the variable expressions already */
812 if( consdata->varexprs == NULL )
813 return SCIP_OKAY;
814
815 assert(consdata->varexprs != NULL);
816 assert(consdata->nvarexprs >= 0);
817 assert(!consdata->catchedevents);
818
819 /* release variable expressions */
820 for( i = 0; i < consdata->nvarexprs; ++i )
821 {
822 assert(consdata->varexprs[i] != NULL);
823 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
824 assert(consdata->varexprs[i] == NULL);
825 }
826
827 /* free variable expressions */
828 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
829 consdata->varexprs = NULL;
830 consdata->nvarexprs = 0;
831
832 return SCIP_OKAY;
833}
834
835/** interval evaluation of variables as used in bound tightening
836 *
837 * Returns slightly relaxed local variable bounds of a variable as interval.
838 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
839 */
840static
841SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
842{
843 SCIP_INTERVAL interval;
844 SCIP_CONSHDLRDATA* conshdlrdata;
845 SCIP_Real lb;
846 SCIP_Real ub;
847
848 assert(scip != NULL);
849 assert(var != NULL);
850
851 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
852 assert(conshdlrdata != NULL);
853
854 if( conshdlrdata->globalbounds )
855 {
858 }
859 else
860 {
863 }
864 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
865
866 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
868 {
869 lb = EPSROUND(lb, 0.0); /*lint !e835*/
870 ub = EPSROUND(ub, 0.0); /*lint !e835*/
871 }
872
873 /* integer variables should always have integral bounds in SCIP */
874 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
875 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
876
877 switch( conshdlrdata->varboundrelax )
878 {
879 case 'n' : /* no relaxation */
880 break;
881
882 case 'a' : /* relax by absolute value */
883 {
884 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
886 break;
887
888 if( !SCIPisInfinity(scip, -lb) )
889 {
890 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
891 SCIP_Real bnd = floor(lb);
892 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
893 }
894
895 if( !SCIPisInfinity(scip, ub) )
896 {
897 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
898 SCIP_Real bnd = ceil(ub);
899 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
900 }
901
902 break;
903 }
904
905 case 'b' : /* relax always by absolute value */
906 {
907 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
909 break;
910
911 if( !SCIPisInfinity(scip, -lb) )
912 lb -= conshdlrdata->varboundrelaxamount;
913
914 if( !SCIPisInfinity(scip, ub) )
915 ub += conshdlrdata->varboundrelaxamount;
916
917 break;
918 }
919
920 case 'r' : /* relax by relative value */
921 {
922 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
924 break;
925
926 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
927 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
928 * further, do not relax beyond next integer value
929 */
930 if( !SCIPisInfinity(scip, -lb) )
931 {
932 SCIP_Real bnd = floor(lb);
933 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
934 }
935
936 if( !SCIPisInfinity(scip, ub) )
937 {
938 SCIP_Real bnd = ceil(ub);
939 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
940 }
941
942 break;
943 }
944
945 default :
946 {
947 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
948 SCIPABORT();
949 break;
950 }
951 }
952
953 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
956 assert(lb <= ub);
957
958 SCIPintervalSetBounds(&interval, lb, ub);
959
960 return interval;
961}
962
963/** compares two nonlinear constraints by its index
964 *
965 * Usable as compare operator in array sort functions.
966 */
967static
968SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
969{
970 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
971 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
972
973 assert(consdata1 != NULL);
974 assert(consdata2 != NULL);
975
976 return consdata1->consindex - consdata2->consindex;
977}
978
979/** processes variable fixing or bound change event */
980static
981SCIP_DECL_EVENTEXEC(processVarEvent)
982{ /*lint --e{715}*/
983 SCIP_EVENTTYPE eventtype;
984 SCIP_EXPR* expr;
985 SCIP_EXPR_OWNERDATA* ownerdata;
986 SCIP_Bool boundtightened = FALSE;
987
988 eventtype = SCIPeventGetType(event);
990
991 assert(eventdata != NULL);
992 expr = (SCIP_EXPR*) eventdata;
993 assert(SCIPisExprVar(scip, expr));
994
995 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
999
1000 ownerdata = SCIPexprGetOwnerData(expr);
1001 assert(ownerdata != NULL);
1002 /* we only catch varevents for variables in constraints, so there should be constraints */
1003 assert(ownerdata->nconss > 0);
1004 assert(ownerdata->conss != NULL);
1005
1006 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1007 boundtightened = TRUE;
1008
1009 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1010 * however, if the boundchange is smaller than epsilon, such an event will be omitted
1011 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1012 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1013 * as a boundtightening (and usually it is, I would think)
1014 */
1015 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1016 boundtightened = TRUE;
1017
1018 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1019 * because we will round the bounds and no longer consider relaxing them
1020 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1021 * (mainly to avoid a failing assert, see github issue #70)
1022 * 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
1023 */
1025 && ( !EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) /*lint !e835*/
1026 || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0) ) ) /*lint !e835*/
1027 boundtightened = TRUE;
1028
1029 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1030 * - propagation can only find something new if a bound was tightened
1031 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1032 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1033 */
1034 if( boundtightened )
1035 {
1036 SCIP_CONSDATA* consdata;
1037 int c;
1038
1039 for( c = 0; c < ownerdata->nconss; ++c )
1040 {
1041 assert(ownerdata->conss[c] != NULL);
1042 consdata = SCIPconsGetData(ownerdata->conss[c]);
1043
1044 /* if bound tightening, then mark constraints to be propagated again
1045 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1046 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1047 * the locks don't help since they are not available separately for each constraint
1048 */
1049 consdata->ispropagated = FALSE;
1050 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1051
1052 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1054 {
1055 consdata->issimplified = FALSE;
1056 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1057 }
1058 }
1059 }
1060
1061 /* update curboundstag, lastboundrelax, and expr activity */
1062 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1063 {
1064 SCIP_CONSHDLRDATA* conshdlrdata;
1065 SCIP_INTERVAL activity;
1066
1067 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1068 assert(conshdlrdata != NULL);
1069
1070 /* increase tag on bounds */
1071 ++conshdlrdata->curboundstag;
1072 assert(conshdlrdata->curboundstag > 0);
1073
1074 /* remember also if we relaxed bounds now */
1075 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1076 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1077
1078 /* update the activity of the var-expr here immediately
1079 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1080 */
1081 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1082 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1083#ifdef DEBUG_PROP
1084 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1085#endif
1086 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1087 }
1088
1089 return SCIP_OKAY;
1090}
1091
1092/** registers event handler to catch variable events on variable
1093 *
1094 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1095 * When an event occurs, all stored constraints are notified.
1096 */
1097static
1099 SCIP* scip, /**< SCIP data structure */
1100 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1101 SCIP_EXPR* expr, /**< variable expression */
1102 SCIP_CONS* cons /**< nonlinear constraint */
1103 )
1104{
1105 SCIP_EXPR_OWNERDATA* ownerdata;
1106
1107 assert(eventhdlr != NULL);
1108 assert(expr != NULL);
1109 assert(SCIPisExprVar(scip, expr));
1110 assert(cons != NULL);
1111
1112 ownerdata = SCIPexprGetOwnerData(expr);
1113 assert(ownerdata != NULL);
1114
1115#ifndef NDEBUG
1116 /* assert that constraint does not double-catch variable */
1117 {
1118 int i;
1119 for( i = 0; i < ownerdata->nconss; ++i )
1120 assert(ownerdata->conss[i] != cons);
1121 }
1122#endif
1123
1124 /* append cons to ownerdata->conss */
1125 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1126 ownerdata->conss[ownerdata->nconss++] = cons;
1127 /* we're not capturing the constraint here to avoid circular references */
1128
1129 /* updated sorted flag */
1130 if( ownerdata->nconss <= 1 )
1131 ownerdata->consssorted = TRUE;
1132 else if( ownerdata->consssorted )
1133 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) < 0;
1134
1135 /* catch variable events, if not done so yet (first constraint) */
1136 if( ownerdata->filterpos < 0 )
1137 {
1138 SCIP_EVENTTYPE eventtype;
1139
1140 assert(ownerdata->nconss == 1);
1141
1143
1144 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1145 assert(ownerdata->filterpos >= 0);
1146 }
1147
1148 return SCIP_OKAY;
1149}
1150
1151/** catch variable events */
1152static
1154 SCIP* scip, /**< SCIP data structure */
1155 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1156 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1157 )
1158{
1159 SCIP_CONSHDLRDATA* conshdlrdata;
1160 SCIP_CONSDATA* consdata;
1161 SCIP_EXPR* expr;
1162 int i;
1163
1164 assert(eventhdlr != NULL);
1165 assert(cons != NULL);
1166
1167 consdata = SCIPconsGetData(cons);
1168 assert(consdata != NULL);
1169 assert(consdata->varexprs != NULL);
1170 assert(consdata->nvarexprs >= 0);
1171
1172 /* check if we have catched variable events already */
1173 if( consdata->catchedevents )
1174 return SCIP_OKAY;
1175
1176 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1177 assert(conshdlrdata != NULL);
1178#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1179 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1180#endif
1181
1182 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1183
1184 for( i = 0; i < consdata->nvarexprs; ++i )
1185 {
1186 expr = consdata->varexprs[i];
1187
1188 assert(expr != NULL);
1189 assert(SCIPisExprVar(scip, expr));
1190
1191 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1192
1193 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1194 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1195 */
1196 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1197 {
1198 SCIP_INTERVAL activity;
1199 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1200 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1201 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1202#ifdef DEBUG_PROP
1203 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1204#endif
1205 }
1206 }
1207
1208 consdata->catchedevents = TRUE;
1209
1210 return SCIP_OKAY;
1211}
1212
1213/** unregisters event handler to catch variable events on variable
1214 *
1215 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1216 * If this was the last constraint, then the event handler is unregistered for this variable.
1217 */
1218static
1220 SCIP* scip, /**< SCIP data structure */
1221 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1222 SCIP_EXPR* expr, /**< variable expression */
1223 SCIP_CONS* cons /**< expr constraint */
1224 )
1225{
1226 SCIP_EXPR_OWNERDATA* ownerdata;
1227 int pos;
1228
1229 assert(eventhdlr != NULL);
1230 assert(expr != NULL);
1231 assert(SCIPisExprVar(scip, expr));
1232 assert(cons != NULL);
1233
1234 ownerdata = SCIPexprGetOwnerData(expr);
1235 assert(ownerdata != NULL);
1236 assert(ownerdata->nconss > 0);
1237
1238 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1239 {
1240 pos = ownerdata->nconss-1;
1241 }
1242 else
1243 {
1244 if( !ownerdata->consssorted )
1245 {
1246 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1247 ownerdata->consssorted = TRUE;
1248 }
1249
1250 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1251 {
1252 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1253 return SCIP_ERROR;
1254 }
1255 assert(pos >= 0 && pos < ownerdata->nconss);
1256 }
1257 assert(ownerdata->conss[pos] == cons);
1258
1259 /* move last constraint into position of removed constraint */
1260 if( pos < ownerdata->nconss-1 )
1261 {
1262 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1263 ownerdata->consssorted = FALSE;
1264 }
1265 --ownerdata->nconss;
1266
1267 /* drop variable events if that was the last constraint */
1268 if( ownerdata->nconss == 0 )
1269 {
1270 SCIP_EVENTTYPE eventtype;
1271
1272 assert(ownerdata->filterpos >= 0);
1273
1275
1276 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1277 ownerdata->filterpos = -1;
1278 }
1279
1280 return SCIP_OKAY;
1281}
1282
1283/** drop variable events */
1284static
1286 SCIP* scip, /**< SCIP data structure */
1287 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1288 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1289 )
1290{
1291 SCIP_CONSDATA* consdata;
1292 int i;
1293
1294 assert(eventhdlr != NULL);
1295 assert(cons != NULL);
1296
1297 consdata = SCIPconsGetData(cons);
1298 assert(consdata != NULL);
1299
1300 /* check if we have catched variable events already */
1301 if( !consdata->catchedevents )
1302 return SCIP_OKAY;
1303
1304 assert(consdata->varexprs != NULL);
1305 assert(consdata->nvarexprs >= 0);
1306
1307 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1308
1309 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1310 {
1311 assert(consdata->varexprs[i] != NULL);
1312
1313 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1314 }
1315
1316 consdata->catchedevents = FALSE;
1317
1318 return SCIP_OKAY;
1319}
1320
1321/** creates and captures a nonlinear constraint
1322 *
1323 * @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
1324 */
1325static
1327 SCIP* scip, /**< SCIP data structure */
1328 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1329 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1330 const char* name, /**< name of constraint */
1331 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1332 SCIP_Real lhs, /**< left hand side of constraint */
1333 SCIP_Real rhs, /**< right hand side of constraint */
1334 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1335 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1336 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1337 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1338 * Usually set to TRUE. */
1339 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1340 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1341 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1342 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1343 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1344 * Usually set to TRUE. */
1345 SCIP_Bool local, /**< is constraint only valid locally?
1346 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1347 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1348 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1349 * adds coefficients to this constraint. */
1350 SCIP_Bool dynamic, /**< is constraint subject to aging?
1351 * Usually set to FALSE. Set to TRUE for own cuts which
1352 * are separated as constraints. */
1353 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1354 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1355 )
1356{
1357 SCIP_CONSHDLRDATA* conshdlrdata;
1358 SCIP_CONSDATA* consdata;
1359
1360 assert(conshdlr != NULL);
1361 assert(expr != NULL);
1362
1363 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1364 assert(conshdlrdata != NULL);
1365
1366 if( local && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
1367 {
1368 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1369 return SCIP_INVALIDCALL;
1370 }
1371
1372 /* TODO we should allow for non-initial nonlinear constraints */
1373 if( !initial )
1374 {
1375 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1376 return SCIP_INVALIDCALL;
1377 }
1378
1379 if( isnan(lhs) || isnan(rhs) )
1380 {
1381 SCIPerrorMessage("%s hand side of nonlinear constraint <%s> is nan\n",
1382 isnan(lhs) ? "left" : "right", name);
1383 return SCIP_INVALIDDATA;
1384 }
1385
1386 /* create constraint data */
1388
1389 if( copyexpr )
1390 {
1391 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1392 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1393 }
1394 else
1395 {
1396 consdata->expr = expr;
1397 SCIPcaptureExpr(consdata->expr);
1398 }
1399 consdata->lhs = lhs;
1400 consdata->rhs = rhs;
1401 consdata->consindex = conshdlrdata->lastconsindex++;
1402 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1403
1404 /* create constraint */
1405 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1406 local, modifiable, dynamic, removable, FALSE) );
1407
1408 return SCIP_OKAY;
1409}
1410
1411/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1412 *
1413 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1414 * Assume that f(x) is associated with auxiliary variable z.
1415 *
1416 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1417 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1418 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1419 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1420 *
1421 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1422 */
1423static
1425 SCIP* scip, /**< SCIP data structure */
1426 SCIP_EXPR* expr, /**< expression */
1427 SCIP_SOL* sol, /**< solution that has been evaluated */
1428 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1429 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1430 )
1431{
1432 SCIP_EXPR_OWNERDATA* ownerdata;
1433 SCIP_Real auxvarvalue;
1434
1435 assert(expr != NULL);
1436
1437 ownerdata = SCIPexprGetOwnerData(expr);
1438 assert(ownerdata != NULL);
1439 assert(ownerdata->auxvar != NULL);
1440
1441 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1442 {
1443 if( violunder != NULL )
1444 *violunder = TRUE;
1445 if( violover != NULL )
1446 *violover = TRUE;
1447 return SCIPinfinity(scip);
1448 }
1449
1450 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1451
1452 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1453 {
1454 if( violunder != NULL )
1455 *violunder = FALSE;
1456 if( violover != NULL )
1457 *violover = TRUE;
1458 return auxvarvalue - SCIPexprGetEvalValue(expr);
1459 }
1460
1461 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1462 {
1463 if( violunder != NULL )
1464 *violunder = TRUE;
1465 if( violover != NULL )
1466 *violover = FALSE;
1467 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1468 }
1469
1470 if( violunder != NULL )
1471 *violunder = FALSE;
1472 if( violover != NULL )
1473 *violover = FALSE;
1474 return 0.0;
1475}
1476
1477/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1478 *
1479 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1480 * Assume that f(w) is associated with auxiliary variable z.
1481 *
1482 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1483 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1484 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1485 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1486 *
1487 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1488 */
1489static
1491 SCIP* scip, /**< SCIP data structure */
1492 SCIP_EXPR* expr, /**< expression */
1493 SCIP_Real auxvalue, /**< value of f(w) */
1494 SCIP_SOL* sol, /**< solution that has been evaluated */
1495 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1496 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1497 )
1498{
1499 SCIP_EXPR_OWNERDATA* ownerdata;
1500 SCIP_Real auxvarvalue;
1501
1502 assert(expr != NULL);
1503
1504 ownerdata = SCIPexprGetOwnerData(expr);
1505 assert(ownerdata != NULL);
1506 assert(ownerdata->auxvar != NULL);
1507
1508 if( auxvalue == SCIP_INVALID )
1509 {
1510 if( violunder != NULL )
1511 *violunder = TRUE;
1512 if( violover != NULL )
1513 *violover = TRUE;
1514 return SCIPinfinity(scip);
1515 }
1516
1517 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1518
1519 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1520 {
1521 if( violunder != NULL )
1522 *violunder = FALSE;
1523 if( violover != NULL )
1524 *violover = TRUE;
1525 return auxvarvalue - auxvalue;
1526 }
1527
1528 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1529 {
1530 if( violunder != NULL )
1531 *violunder = TRUE;
1532 if( violover != NULL )
1533 *violover = FALSE;
1534 return auxvalue - auxvarvalue;
1535 }
1536
1537 if( violunder != NULL )
1538 *violunder = FALSE;
1539 if( violover != NULL )
1540 *violover = FALSE;
1541
1542 return 0.0;
1543}
1544
1545/** computes violation of a constraint */
1546static
1548 SCIP* scip, /**< SCIP data structure */
1549 SCIP_CONS* cons, /**< constraint */
1550 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1551 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1552 )
1553{
1554 SCIP_CONSDATA* consdata;
1555 SCIP_Real activity;
1556
1557 assert(scip != NULL);
1558 assert(cons != NULL);
1559
1560 consdata = SCIPconsGetData(cons);
1561 assert(consdata != NULL);
1562
1563 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1564 activity = SCIPexprGetEvalValue(consdata->expr);
1565
1566 /* consider constraint as violated if it is undefined in the current point */
1567 if( activity == SCIP_INVALID )
1568 {
1569 consdata->lhsviol = SCIPinfinity(scip);
1570 consdata->rhsviol = SCIPinfinity(scip);
1571 return SCIP_OKAY;
1572 }
1573
1574 /* compute violations */
1575 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1576 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1577
1578 return SCIP_OKAY;
1579}
1580
1581/** returns absolute violation of a constraint
1582 *
1583 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1584 */
1585static
1587 SCIP_CONS* cons /**< constraint */
1588 )
1589{
1590 SCIP_CONSDATA* consdata;
1591
1592 assert(cons != NULL);
1593
1594 consdata = SCIPconsGetData(cons);
1595 assert(consdata != NULL);
1596
1597 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1598}
1599
1600/** computes relative violation of a constraint
1601 *
1602 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1603 */
1604static
1606 SCIP* scip, /**< SCIP data structure */
1607 SCIP_CONS* cons, /**< constraint */
1608 SCIP_Real* viol, /**< buffer to store violation */
1609 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1610 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1611 )
1612{
1613 SCIP_CONSHDLR* conshdlr;
1614 SCIP_CONSHDLRDATA* conshdlrdata;
1615 SCIP_CONSDATA* consdata;
1616 SCIP_Real scale;
1617
1618 assert(cons != NULL);
1619 assert(viol != NULL);
1620
1621 conshdlr = SCIPconsGetHdlr(cons);
1622 assert(conshdlr != NULL);
1623
1624 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1625 assert(conshdlrdata != NULL);
1626
1627 *viol = getConsAbsViolation(cons);
1628
1629 if( conshdlrdata->violscale == 'n' )
1630 return SCIP_OKAY;
1631
1632 if( SCIPisInfinity(scip, *viol) )
1633 return SCIP_OKAY;
1634
1635 consdata = SCIPconsGetData(cons);
1636 assert(consdata != NULL);
1637
1638 if( conshdlrdata->violscale == 'a' )
1639 {
1640 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1641
1642 /* consider value of side that is violated for scaling, too */
1643 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1644 {
1645 assert(!SCIPisInfinity(scip, -consdata->lhs));
1646 scale = REALABS(consdata->lhs);
1647 }
1648 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1649 {
1650 assert(!SCIPisInfinity(scip, consdata->rhs));
1651 scale = REALABS(consdata->rhs);
1652 }
1653
1654 *viol /= scale;
1655 return SCIP_OKAY;
1656 }
1657
1658 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1659 assert(conshdlrdata->violscale == 'g');
1660 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1661 {
1662 /* we need the varexprs to conveniently access the gradient */
1663 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1664
1665 /* update cached value of norm of gradient */
1666 consdata->gradnorm = 0.0;
1667
1668 /* compute gradient */
1669 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1670
1671 /* gradient evaluation error -> no scaling */
1672 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1673 {
1674 int i;
1675 for( i = 0; i < consdata->nvarexprs; ++i )
1676 {
1677 SCIP_Real deriv;
1678
1679 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1680 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1681 if( deriv == SCIP_INVALID )
1682 {
1683 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1684 consdata->gradnorm = 0.0;
1685 break;
1686 }
1687
1688 consdata->gradnorm += deriv*deriv;
1689 }
1690 }
1691 consdata->gradnorm = sqrt(consdata->gradnorm);
1692 consdata->gradnormsoltag = soltag;
1693 }
1694
1695 *viol /= MAX(1.0, consdata->gradnorm);
1696
1697 return SCIP_OKAY;
1698}
1699
1700/** returns whether constraint is currently violated
1701 *
1702 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1703 */
1704static
1706 SCIP* scip, /**< SCIP data structure */
1707 SCIP_CONS* cons /**< constraint */
1708 )
1709{
1710 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1711}
1712
1713/** checks for a linear variable that can be increased or decreased without harming feasibility */
1714static
1716 SCIP* scip, /**< SCIP data structure */
1717 SCIP_CONS* cons /**< constraint */
1718 )
1719{
1720 SCIP_CONSDATA* consdata;
1721 int poslock;
1722 int neglock;
1723 int i;
1724
1725 assert(cons != NULL);
1726
1727 consdata = SCIPconsGetData(cons);
1728 assert(consdata != NULL);
1729
1730 consdata->linvarincr = NULL;
1731 consdata->linvardecr = NULL;
1732 consdata->linvarincrcoef = 0.0;
1733 consdata->linvardecrcoef = 0.0;
1734
1735 /* root expression is not a sum -> no unlocked linear variable available */
1736 if( !SCIPisExprSum(scip, consdata->expr) )
1737 return;
1738
1739 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1740 {
1741 SCIP_EXPR* child;
1742
1743 child = SCIPexprGetChildren(consdata->expr)[i];
1744 assert(child != NULL);
1745
1746 /* check whether the child is a variable expression */
1747 if( SCIPisExprVar(scip, child) )
1748 {
1749 SCIP_VAR* var = SCIPgetVarExprVar(child);
1750 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1751
1752 if( coef > 0.0 )
1753 {
1754 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1755 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1756 }
1757 else
1758 {
1759 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1760 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1761 }
1763
1764 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1765 {
1766 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1767 * if we have already one candidate, then take the one where the loss in the objective function is less
1768 */
1769 if( (consdata->linvardecr == NULL) ||
1770 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1771 {
1772 consdata->linvardecr = var;
1773 consdata->linvardecrcoef = coef;
1774 }
1775 }
1776
1777 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1778 {
1779 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1780 * if we have already one candidate, then take the one where the loss in the objective function is less
1781 */
1782 if( (consdata->linvarincr == NULL) ||
1783 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1784 {
1785 consdata->linvarincr = var;
1786 consdata->linvarincrcoef = coef;
1787 }
1788 }
1789 }
1790 }
1791
1792 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1793 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1794
1795 if( consdata->linvarincr != NULL )
1796 {
1797 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1798 }
1799 if( consdata->linvardecr != NULL )
1800 {
1801 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1802 }
1803}
1804
1805/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1806 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1807 *
1808 * The method assumes that this is always possible and that not all constraints are feasible already.
1809 */
1810static
1812 SCIP* scip, /**< SCIP data structure */
1813 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1814 SCIP_CONS** conss, /**< constraints to process */
1815 int nconss, /**< number of constraints */
1816 SCIP_SOL* sol, /**< solution to process */
1817 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1818 )
1819{
1820 SCIP_CONSHDLRDATA* conshdlrdata;
1821 SCIP_SOL* newsol;
1822 int c;
1823
1824 assert(scip != NULL);
1825 assert(conshdlr != NULL);
1826 assert(conss != NULL || nconss == 0);
1827 assert(success != NULL);
1828
1829 *success = FALSE;
1830
1831 /* don't propose new solutions if not in presolve or solving */
1833 return SCIP_OKAY;
1834
1835 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1836 assert(conshdlrdata != NULL);
1837
1838 if( sol != NULL )
1839 {
1840 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1841 }
1842 else
1843 {
1844 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1845 }
1846 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1847 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1848 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1849
1850 for( c = 0; c < nconss; ++c )
1851 {
1852 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1853 SCIP_Real viol = 0.0;
1854 SCIP_Real delta;
1855 SCIP_Real gap;
1856
1857 assert(consdata != NULL);
1858
1859 /* get absolute violation and sign */
1860 if( consdata->lhsviol > SCIPfeastol(scip) )
1861 viol = consdata->lhsviol; /* lhs - activity */
1862 else if( consdata->rhsviol > SCIPfeastol(scip) )
1863 viol = -consdata->rhsviol; /* rhs - activity */
1864 else
1865 continue; /* constraint is satisfied */
1866
1867 if( consdata->linvarincr != NULL &&
1868 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1869 {
1870 SCIP_VAR* var = consdata->linvarincr;
1871
1872 /* compute how much we would like to increase var */
1873 delta = viol / consdata->linvarincrcoef;
1874 assert(delta > 0.0);
1875
1876 /* if var has an upper bound, may need to reduce delta */
1878 {
1879 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1880 delta = MIN(MAX(0.0, gap), delta);
1881 }
1882 if( SCIPisPositive(scip, delta) )
1883 {
1884 /* if variable is integral, round delta up so that it will still have an integer value */
1885 if( SCIPvarIsIntegral(var) )
1886 delta = SCIPceil(scip, delta);
1887
1888 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1889 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1890 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1891
1892 /* adjust constraint violation, if satisfied go on to next constraint */
1893 viol -= consdata->linvarincrcoef * delta;
1894 if( SCIPisZero(scip, viol) )
1895 continue;
1896 }
1897 }
1898
1899 assert(viol != 0.0);
1900 if( consdata->linvardecr != NULL &&
1901 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1902 {
1903 SCIP_VAR* var = consdata->linvardecr;
1904
1905 /* compute how much we would like to decrease var */
1906 delta = viol / consdata->linvardecrcoef;
1907 assert(delta < 0.0);
1908
1909 /* if var has a lower bound, may need to reduce delta */
1911 {
1912 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1913 delta = MAX(MIN(0.0, gap), delta);
1914 }
1915 if( SCIPisNegative(scip, delta) )
1916 {
1917 /* if variable is integral, round delta down so that it will still have an integer value */
1918 if( SCIPvarIsIntegral(var) )
1919 delta = SCIPfloor(scip, delta);
1920 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1921 /*lint --e{613} */
1922 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1923 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1924
1925 /* adjust constraint violation, if satisfied go on to next constraint */
1926 viol -= consdata->linvardecrcoef * delta;
1927 if( SCIPisZero(scip, viol) )
1928 continue;
1929 }
1930 }
1931
1932 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1933 break;
1934 }
1935
1936 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1937 * then pass it to the trysol heuristic
1938 */
1940 {
1941 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1942
1943 assert(conshdlrdata->trysolheur != NULL);
1944 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1945
1946 *success = TRUE;
1947 }
1948
1949 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1950
1951 return SCIP_OKAY;
1952}
1953
1954/** notify nonlinear handlers to add linearization in new solution that has been found
1955 *
1956 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1957 *
1958 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1959 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1960 * cut that is valid and supporting in the given solution.
1961 * For example, for convex constraints, we achieve this by linearizing.
1962 * For SOC, we also linearize, but on a a convex reformulation.
1963 *
1964 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1965 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1966 */
1967static
1969 SCIP* scip, /**< SCIP data structure */
1970 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1971 SCIP_CONS** conss, /**< constraints */
1972 int nconss, /**< number of constraints */
1973 SCIP_SOL* sol, /**< reference point where to estimate */
1974 SCIP_Bool solisbest /**< whether solution is best */
1975 )
1976{
1977 SCIP_CONSDATA* consdata;
1978 SCIP_Longint soltag;
1979 SCIP_EXPRITER* it;
1980 SCIP_EXPR* expr;
1981 int c, e;
1982
1983 assert(scip != NULL);
1984 assert(conshdlr != NULL);
1985 assert(conss != NULL || nconss == 0);
1986
1987 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1988
1989 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1990 * would be nice to recognize this and skip reevaluating
1991 */
1992 soltag = SCIPgetExprNewSoltag(scip);
1993
1997
1998 for( c = 0; c < nconss; ++c )
1999 {
2000 /* skip constraints that are not enabled or deleted or have separation disabled */
2001 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2002 continue;
2003 assert(SCIPconsIsActive(conss[c]));
2004
2005 consdata = SCIPconsGetData(conss[c]);
2006 assert(consdata != NULL);
2007
2008 ENFOLOG(
2009 {
2010 int i;
2011 SCIPinfoMessage(scip, enfologfile, " constraint ");
2012 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2013 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2014 for( i = 0; i < consdata->nvarexprs; ++i )
2015 {
2016 SCIP_VAR* var;
2017 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2018 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2020 }
2021 })
2022
2023 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2024 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2025
2026 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2027 {
2028 SCIP_EXPR_OWNERDATA* ownerdata;
2029
2030 ownerdata = SCIPexprGetOwnerData(expr);
2031 assert(ownerdata != NULL);
2032
2033 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2034 assert(SCIPexprGetEvalTag(expr) == soltag);
2036 if( ownerdata->auxvar != NULL )
2037 {
2038 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2039 }
2040
2041 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2042 for( e = 0; e < ownerdata->nenfos; ++e )
2043 {
2044 /* call sollinearize callback, if implemented by nlhdlr */
2045 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2046 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2047 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2048 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2049 }
2050 }
2051 }
2052
2053 SCIPfreeExpriter(&it);
2054
2055 return SCIP_OKAY;
2056}
2057
2058/** processes the event that a new primal solution has been found */
2059static
2060SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2061{
2062 SCIP_CONSHDLR* conshdlr;
2063 SCIP_CONSHDLRDATA* conshdlrdata;
2064 SCIP_SOL* sol;
2065
2066 assert(scip != NULL);
2067 assert(event != NULL);
2068 assert(eventdata != NULL);
2069 assert(eventhdlr != NULL);
2071
2072 conshdlr = (SCIP_CONSHDLR*)eventdata;
2073
2074 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2075 return SCIP_OKAY;
2076
2077 sol = SCIPeventGetSol(event);
2078 assert(sol != NULL);
2079
2080 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2081 assert(conshdlrdata != NULL);
2082
2083 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2084 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2085 * from the tree, but postprocessed via proposeFeasibleSolution
2086 */
2087 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2088 return SCIP_OKAY;
2089
2090 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2091
2093
2094 return SCIP_OKAY;
2095}
2096
2097/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2098 *
2099 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2100 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2101 *
2102 * Nothing will happen if SCIP is not in presolve or solve.
2103 */
2104static
2106 SCIP* scip, /**< SCIP data structure */
2107 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2108 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2109 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2110 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2111 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2112 )
2113{
2114 SCIP_VAR* var;
2115 SCIP_Bool tightenedlb;
2116 SCIP_Bool tightenedub;
2117 SCIP_Bool force;
2118
2119 assert(scip != NULL);
2120 assert(conshdlr != NULL);
2121 assert(expr != NULL);
2122 assert(cutoff != NULL);
2123
2124 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2126
2127 *cutoff = FALSE;
2128
2130 if( var == NULL )
2131 return SCIP_OKAY;
2132
2133 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2134 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2135
2136 /* try to tighten lower bound of (auxiliary) variable */
2137 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2138 if( tightenedlb )
2139 {
2140 if( ntightenings != NULL )
2141 ++*ntightenings;
2142 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2143 }
2144 if( *cutoff )
2145 {
2146 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2147 return SCIP_OKAY;
2148 }
2149
2150 /* try to tighten upper bound of (auxiliary) variable */
2151 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2152 if( tightenedub )
2153 {
2154 if( ntightenings != NULL )
2155 ++*ntightenings;
2156 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2157 }
2158 if( *cutoff )
2159 {
2160 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2161 return SCIP_OKAY;
2162 }
2163
2164 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2165 * that seems unnecessary and we could easily undo this here, e.g.,
2166 * if( tightenedlb ) expr->activity.inf = bounds.inf
2167 */
2168
2169 return SCIP_OKAY;
2170}
2171
2172/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2173 * and tries to tighten the bounds of the auxiliary variables accordingly
2174 */
2175static
2177 SCIP* scip, /**< SCIP data structure */
2178 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2179 SCIP_EXPR* rootexpr, /**< expression */
2180 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2181 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2182 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2183 )
2184{
2185 SCIP_EXPRITER* it;
2186 SCIP_EXPR* expr;
2187 SCIP_EXPR_OWNERDATA* ownerdata;
2188 SCIP_CONSHDLRDATA* conshdlrdata;
2189
2190 assert(scip != NULL);
2191 assert(rootexpr != NULL);
2192
2193 if( infeasible != NULL )
2194 *infeasible = FALSE;
2195 if( ntightenings != NULL )
2196 *ntightenings = 0;
2197
2198 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2199 assert(conshdlrdata != NULL);
2200
2201 /* if value is valid and empty, then we cannot improve, so do nothing */
2202 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2203 {
2204 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2205
2206 if( infeasible != NULL )
2207 *infeasible = TRUE;
2208
2209 /* just update tag to curboundstag */
2210 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2211
2212 return SCIP_OKAY;
2213 }
2214
2215 /* if value is up-to-date, then nothing to do */
2216 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2217 {
2218 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2219
2220 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2221
2222 return SCIP_OKAY;
2223 }
2224
2225 ownerdata = SCIPexprGetOwnerData(rootexpr);
2226 assert(ownerdata != NULL);
2227
2228 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2229 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2230 * during detect, we are in some in-between state where we may want to eval activity
2231 * on exprs that we did not notify about their activity usage
2232 */
2233 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2234 {
2235#ifdef DEBUG_PROP
2236 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2237#endif
2238 SCIPABORT();
2239 return SCIP_OKAY;
2240 }
2241
2245
2246 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2247 {
2248 switch( SCIPexpriterGetStageDFS(it) )
2249 {
2251 {
2252 /* skip child if it has been evaluated already */
2253 SCIP_EXPR* child;
2254
2255 child = SCIPexpriterGetChildExprDFS(it);
2256 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2257 {
2259 *infeasible = TRUE;
2260
2261 expr = SCIPexpriterSkipDFS(it);
2262 continue;
2263 }
2264
2265 break;
2266 }
2267
2269 {
2270 SCIP_INTERVAL activity;
2271
2272 /* we should not have entered this expression if its activity was already up to date */
2273 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2274
2275 ownerdata = SCIPexprGetOwnerData(expr);
2276 assert(ownerdata != NULL);
2277
2278 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2279 * so we can assume that the activity is up to date for all these variables
2280 * UNLESS we changed the method used to evaluate activity of variable expressions
2281 * or we currently use global bounds (varevents are catched for local bound changes only)
2282 */
2283 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2284 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2285 {
2286#ifndef NDEBUG
2287 SCIP_INTERVAL exprhdlrinterval;
2288
2289 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2290 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2291 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2292#endif
2293#ifdef DEBUG_PROP
2294 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2295#endif
2296 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2297
2298 break;
2299 }
2300
2301 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2302 {
2303 /* start with entire activity if current one is invalid */
2305 }
2307 {
2308 /* If already empty, then don't try to compute even better activity.
2309 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2310 * so an assert(infeasible == NULL || *infeasible) should work here.
2311 * However, after reporting a cutoff due to expr->activity being empty,
2312 * SCIP may wander to a different node and call propagation again.
2313 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2314 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2315 * we will still have expr->activity being empty, but will have forgotten
2316 * that we found infeasibility here before (!2221#note_134120).
2317 * Therefore we just set *infeasibility=TRUE here and stop.
2318 */
2319 if( infeasible != NULL )
2320 *infeasible = TRUE;
2321 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2322 break;
2323 }
2324 else
2325 {
2326 /* start with current activity, since it is valid */
2327 activity = SCIPexprGetActivity(expr);
2328 }
2329
2330 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2331 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2332 {
2333#ifdef DEBUG_PROP
2334 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2335#endif
2336 break;
2337 }
2338
2339#ifdef DEBUG_PROP
2340 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2341 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2342 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2343#endif
2344
2345 /* run interval eval of nonlinear handlers or expression handler */
2346 if( ownerdata->nenfos > 0 )
2347 {
2348 SCIP_NLHDLR* nlhdlr;
2349 SCIP_INTERVAL nlhdlrinterval;
2350 int e;
2351
2352 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2353 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2354 {
2355 /* skip nlhdlr if it does not want to participate in activity computation */
2356 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2357 continue;
2358
2359 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2360 assert(nlhdlr != NULL);
2361
2362 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2363 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2364 continue;
2365
2366 /* let nlhdlr evaluate current expression */
2367 nlhdlrinterval = activity;
2368 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2369 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2370#ifdef DEBUG_PROP
2371 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2372#endif
2373
2374 /* update activity by intersecting with computed activity */
2375 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2376#ifdef DEBUG_PROP
2377 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2378#endif
2379 }
2380 }
2381 else
2382 {
2383 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2384 SCIP_INTERVAL exprhdlrinterval = activity;
2385 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2386#ifdef DEBUG_PROP
2387 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2388#endif
2389
2390 /* update expr->activity by intersecting with computed activity */
2391 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2392#ifdef DEBUG_PROP
2393 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2394#endif
2395 }
2396
2397 /* if expression is integral, then we try to tighten the interval bounds a bit
2398 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2399 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2400 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2401 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2402 * (constants should be ok, too)
2403 */
2404 if( SCIPexprIsIntegral(expr) &&
2405 conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2406 {
2407 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2408 activity.inf = SCIPceil(scip, activity.inf);
2409 if( activity.sup < SCIP_INTERVAL_INFINITY )
2410 activity.sup = SCIPfloor(scip, activity.sup);
2411#ifdef DEBUG_PROP
2412 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2413#endif
2414 }
2415
2416 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2417 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2418 */
2419 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2420 {
2421 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2422 SCIPintervalSetEmpty(&activity);
2423 }
2424
2425 /* now finally store activity in expr */
2426 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2427
2429 {
2430 if( infeasible != NULL )
2431 *infeasible = TRUE;
2432 }
2433 else if( tightenauxvars && ownerdata->auxvar != NULL )
2434 {
2435 SCIP_Bool tighteninfeasible;
2436
2437 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2438 if( tighteninfeasible )
2439 {
2440 if( infeasible != NULL )
2441 *infeasible = TRUE;
2442 SCIPintervalSetEmpty(&activity);
2443 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2444 }
2445 }
2446
2447 break;
2448 }
2449
2450 default:
2451 /* you should never be here */
2452 SCIPerrorMessage("unexpected iterator stage\n");
2453 SCIPABORT();
2454 break;
2455 }
2456
2457 expr = SCIPexpriterGetNext(it);
2458 }
2459
2460 SCIPfreeExpriter(&it);
2461
2462 return SCIP_OKAY;
2463}
2464
2465/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2466 *
2467 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2468 *
2469 * If `subsetsufficient` is FALSE, then we require
2470 * - a change from an unbounded interval to a bounded one, or
2471 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2472 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2473 */
2474static
2476 SCIP* scip, /**< SCIP data structure */
2477 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2478 SCIP_INTERVAL newinterval, /**< new interval */
2479 SCIP_INTERVAL oldinterval /**< old interval */
2480 )
2481{
2482 assert(scip != NULL);
2485
2486 if( subsetsufficient )
2487 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2488 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2489
2490 /* check whether lower bound of interval becomes finite */
2491 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2492 return TRUE;
2493
2494 /* check whether upper bound of interval becomes finite */
2495 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2496 return TRUE;
2497
2498 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2499 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2500 return TRUE;
2501
2502 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2503 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2504 return TRUE;
2505
2506 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2507 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2508 return TRUE;
2509
2510 return FALSE;
2511}
2512
2513/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2514 *
2515 * The expression will be traversed in breadth first search by using this queue.
2516 *
2517 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2518 * forwardPropExpr() before calling this function.
2519 *
2520 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2521 */
2522static
2524 SCIP* scip, /**< SCIP data structure */
2525 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2526 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2527 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2528 )
2529{
2530 SCIP_CONSHDLRDATA* conshdlrdata;
2531 SCIP_EXPR* expr;
2532 SCIP_EXPR_OWNERDATA* ownerdata;
2533
2534 assert(infeasible != NULL);
2535 assert(ntightenings != NULL);
2536
2537 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2538 assert(conshdlrdata != NULL);
2539
2540 *ntightenings = 0;
2541
2542 /* main loop that calls reverse propagation for expressions on the queue
2543 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2544 */
2545 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2546 {
2547 SCIP_INTERVAL propbounds;
2548 int e;
2549
2550 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2551 assert(expr != NULL);
2552
2553 ownerdata = SCIPexprGetOwnerData(expr);
2554 assert(ownerdata != NULL);
2555
2556 assert(ownerdata->inpropqueue);
2557 /* mark that the expression is not in the queue anymore */
2558 ownerdata->inpropqueue = FALSE;
2559
2560 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2561 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2562 */
2563 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2564 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2565 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2566
2567 /* this intersects propbounds with activity and auxvar bounds
2568 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2569 * auxvar bounds separately, so disabling this for now
2570 */
2571#ifdef SCIP_DISABLED_CODE
2572 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2574 {
2575 *infeasible = TRUE;
2576 break;
2577 }
2578#else
2579 propbounds = ownerdata->propbounds;
2580#endif
2581
2582 if( ownerdata->nenfos > 0 )
2583 {
2584 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2585 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2586 {
2587 SCIP_NLHDLR* nlhdlr;
2588 int nreds;
2589
2590 /* skip nlhdlr if it does not want to participate in activity computation */
2591 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2592 continue;
2593
2594 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2595 assert(nlhdlr != NULL);
2596
2597 /* call the reverseprop of the nlhdlr */
2598#ifdef SCIP_DEBUG
2599 SCIPdebugMsg(scip, "call reverse propagation for ");
2600 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2601 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2602#endif
2603
2604 nreds = 0;
2605 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2606 assert(nreds >= 0);
2607 *ntightenings += nreds;
2608 }
2609 }
2611 {
2612 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2613 SCIP_INTERVAL* childrenbounds;
2614 int c;
2615
2616#ifdef SCIP_DEBUG
2617 SCIPdebugMsg(scip, "call reverse propagation for ");
2618 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2619 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2620#endif
2621
2622 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2623 * been initialized in detectNlhdlr yet (nenfos < 0)
2624 */
2625 assert(ownerdata->nenfos < 0);
2626
2627 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2628 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2629 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2630
2631 /* call the reverseprop of the exprhdlr */
2632 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2633
2634 if( !*infeasible )
2635 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2636 {
2637 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2638 }
2639
2640 SCIPfreeBufferArray(scip, &childrenbounds);
2641 }
2642 }
2643
2644 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2645 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2646 {
2647 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2648 assert(expr != NULL);
2649
2650 ownerdata = SCIPexprGetOwnerData(expr);
2651 assert(ownerdata != NULL);
2652
2653 /* mark that the expression is not in the queue anymore */
2654 ownerdata->inpropqueue = FALSE;
2655 }
2656
2657 return SCIP_OKAY;
2658}
2659
2660/** calls domain propagation for a given set of constraints
2661 *
2662 * The algorithm alternates calls of forward and reverse propagation.
2663 * Forward propagation ensures that activity of expressions is up to date.
2664 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2665 * [lhs,rhs] interval as starting point.
2666 *
2667 * The propagation algorithm works as follows:
2668 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2669 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2670 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2671 * provide tighter bounds
2672 * 3. apply reverse propagation to all collected expressions; don't explore
2673 * sub-expressions which have not changed since the beginning of the propagation loop
2674 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2675 *
2676 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2677 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2678 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2679 *
2680 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2681 * e.g., try less to propagate on convex constraints?
2682 */
2683static
2685 SCIP* scip, /**< SCIP data structure */
2686 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2687 SCIP_CONS** conss, /**< constraints to propagate */
2688 int nconss, /**< total number of constraints */
2689 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2690 SCIP_RESULT* result, /**< pointer to store the result */
2691 int* nchgbds /**< buffer to add the number of changed bounds */
2692 )
2693{
2694 SCIP_CONSHDLRDATA* conshdlrdata;
2695 SCIP_CONSDATA* consdata;
2696 SCIP_EXPR_OWNERDATA* ownerdata;
2698 SCIP_INTERVAL conssides;
2699 int ntightenings;
2700 int roundnr;
2701 SCIP_EXPRITER* revpropcollectit = NULL;
2702 int i;
2703
2704 assert(scip != NULL);
2705 assert(conshdlr != NULL);
2706 assert(conss != NULL);
2707 assert(nconss >= 0);
2708 assert(result != NULL);
2709 assert(nchgbds != NULL);
2710 assert(*nchgbds >= 0);
2711
2712 /* no constraints to propagate */
2713 if( nconss == 0 )
2714 {
2716 return SCIP_OKAY;
2717 }
2718
2719 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2720 assert(conshdlrdata != NULL);
2721#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2722 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2723#endif
2724 assert(!conshdlrdata->globalbounds);
2725
2727 roundnr = 0;
2728
2729 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2730 conshdlrdata->forceboundtightening = force;
2731
2732 /* invalidate all propbounds (probably not needed) */
2733 ++conshdlrdata->curpropboundstag;
2734
2735 /* create iterator that we will use if we need to look at all auxvars */
2736 if( conshdlrdata->propauxvars )
2737 {
2738 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2739 }
2740
2741 /* main propagation loop */
2742 do
2743 {
2744 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2745
2746 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2747
2748 /* apply forward propagation (update expression activities)
2749 * and add promising root expressions into queue for reversepropagation
2750 */
2751 for( i = 0; i < nconss; ++i )
2752 {
2753 consdata = SCIPconsGetData(conss[i]);
2754 assert(consdata != NULL);
2755
2756 /* skip deleted, non-active, or propagation-disabled constraints */
2757 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2758 continue;
2759
2760 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2761 * activity didn't change
2762 */
2763 if( consdata->ispropagated )
2764 continue;
2765
2766 /* update activities in expression */
2767 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2768 SCIPdebugPrintCons(scip, conss[i], NULL);
2769
2770 ntightenings = 0;
2771 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2773
2774 if( cutoff )
2775 {
2776 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2778 break;
2779 }
2780
2781 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2782
2783 /* 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 */
2784 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2785 {
2786 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2787 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2788 * so taking auxvar bounds is enough)
2789 */
2790 if( ownerdata->auxvar == NULL )
2791 {
2792 /* relax sides by SCIPepsilon() and handle infinite sides */
2793 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2794 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2795 SCIPintervalSetBounds(&conssides, lhs, rhs);
2796 }
2797 else
2798 {
2799 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2800 }
2801 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2802 }
2803 else
2804 {
2805 /* check whether bounds of any auxvar used in constraint provides a tightening
2806 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2807 * but skip exprs that have an auxvar, but do not participate in propagation
2808 */
2809 SCIP_EXPR* expr;
2810
2811 assert(revpropcollectit != NULL);
2812 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2813 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2814 {
2815 ownerdata = SCIPexprGetOwnerData(expr);
2816 assert(ownerdata != NULL);
2817
2818 if( ownerdata->auxvar == NULL )
2819 continue;
2820
2821 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2822 continue;
2823
2824 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2825 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2826 }
2827 }
2828
2829 if( cutoff )
2830 {
2831 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2833 break;
2834 }
2835
2836 assert(ntightenings >= 0);
2837 if( ntightenings > 0 )
2838 {
2839 *nchgbds += ntightenings;
2841 }
2842
2843 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2844 consdata->ispropagated = TRUE;
2845 }
2846
2847 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2848 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2849 assert(ntightenings >= 0);
2850 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2851
2852 if( cutoff )
2853 {
2854 SCIPdebugMsg(scip, " -> cutoff\n");
2856 break;
2857 }
2858
2859 if( ntightenings > 0 )
2860 {
2861 *nchgbds += ntightenings;
2863 }
2864 }
2865 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2866
2867 if( conshdlrdata->propauxvars )
2868 {
2869 SCIPfreeExpriter(&revpropcollectit);
2870 }
2871
2872 conshdlrdata->forceboundtightening = FALSE;
2873
2874 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2875 ++conshdlrdata->curpropboundstag;
2876
2877 return SCIP_OKAY;
2878}
2879
2880/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2881 *
2882 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2883 *
2884 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2885 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2886 */
2887static
2889 SCIP* scip, /**< SCIP data structure */
2890 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2891 SCIP_CONS** conss, /**< constraints to propagate */
2892 int nconss, /**< total number of constraints */
2893 SCIP_RESULT* result, /**< pointer to store the result */
2894 int* nchgbds /**< buffer to add the number of changed bounds */
2895 )
2896{
2897 SCIP_CONSDATA* consdata;
2898 SCIP_EXPRITER* it;
2899 SCIP_EXPR* expr;
2900 SCIP_EXPR_OWNERDATA* ownerdata;
2902 int ntightenings;
2903 int c;
2904 int e;
2905
2906 assert(scip != NULL);
2907 assert(conshdlr != NULL);
2908 assert(conss != NULL);
2909 assert(nconss >= 0);
2910 assert(result != NULL);
2911 assert(nchgbds != NULL);
2912 assert(*nchgbds >= 0);
2913
2914#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2915 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2916#endif
2917 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2918 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2919
2921
2924
2925 for( c = 0; c < nconss && !cutoff; ++c )
2926 {
2927 /* skip deleted, non-active, or propagation-disabled constraints */
2928 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2929 continue;
2930
2931 consdata = SCIPconsGetData(conss[c]);
2932 assert(consdata != NULL);
2933
2934 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2935 {
2936 ownerdata = SCIPexprGetOwnerData(expr);
2937 assert(ownerdata != NULL);
2938
2939 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2940 * this will propagate the current activity
2941 */
2942 for( e = 0; e < ownerdata->nenfos; ++e )
2943 {
2944 SCIP_NLHDLR* nlhdlr;
2945 assert(ownerdata->enfos[e] != NULL);
2946
2947 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2948 assert(nlhdlr != NULL);
2949 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2950 continue;
2951
2952 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2953 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2954 ntightenings = 0;
2955 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2956 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2957
2958 if( cutoff )
2959 {
2960 /* stop everything if we detected infeasibility */
2961 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2963 break;
2964 }
2965
2966 assert(ntightenings >= 0);
2967 if( ntightenings > 0 )
2968 {
2969 *nchgbds += ntightenings;
2971 }
2972 }
2973 }
2974 }
2975
2976 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2977 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2978 assert(ntightenings >= 0);
2979
2980 if( cutoff )
2981 {
2982 SCIPdebugMsg(scip, " -> cutoff\n");
2984 }
2985 else if( ntightenings > 0 )
2986 {
2987 *nchgbds += ntightenings;
2989 }
2990
2991 SCIPfreeExpriter(&it);
2992
2993 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2994 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2995
2996 return SCIP_OKAY;
2997}
2998
2999/** propagates variable locks through expression and adds locks to variables */
3000static
3002 SCIP* scip, /**< SCIP data structure */
3003 SCIP_EXPR* expr, /**< expression */
3004 int nlockspos, /**< number of positive locks */
3005 int nlocksneg /**< number of negative locks */
3006 )
3007{
3008 SCIP_EXPR_OWNERDATA* ownerdata;
3009 SCIP_EXPRITER* it;
3010 SCIP_EXPRITER_USERDATA ituserdata;
3011
3012 assert(expr != NULL);
3013
3014 /* if no locks, then nothing to propagate */
3015 if( nlockspos == 0 && nlocksneg == 0 )
3016 return SCIP_OKAY;
3017
3021 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3022
3023 /* store locks in root node */
3024 ituserdata.intvals[0] = nlockspos;
3025 ituserdata.intvals[1] = nlocksneg;
3026 SCIPexpriterSetCurrentUserData(it, ituserdata);
3027
3028 while( !SCIPexpriterIsEnd(it) )
3029 {
3030 /* collect locks */
3031 ituserdata = SCIPexpriterGetCurrentUserData(it);
3032 nlockspos = ituserdata.intvals[0];
3033 nlocksneg = ituserdata.intvals[1];
3034
3035 ownerdata = SCIPexprGetOwnerData(expr);
3036
3037 switch( SCIPexpriterGetStageDFS(it) )
3038 {
3040 {
3041 if( SCIPisExprVar(scip, expr) )
3042 {
3043 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3044 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3045 }
3046
3047 /* add locks to expression */
3048 ownerdata->nlockspos += nlockspos;
3049 ownerdata->nlocksneg += nlocksneg;
3050
3051 /* add monotonicity information if expression has been locked for the first time */
3052 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3054 {
3055 int i;
3056
3057 assert(ownerdata->monotonicity == NULL);
3058 assert(ownerdata->monotonicitysize == 0);
3059
3060 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3061 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3062
3063 /* store the monotonicity for each child */
3064 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3065 {
3066 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3067 }
3068 }
3069 break;
3070 }
3071
3073 {
3074 /* remove monotonicity information if expression has been unlocked */
3075 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3076 {
3077 assert(ownerdata->monotonicitysize > 0);
3078 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3079 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3080
3081 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3082 ownerdata->monotonicitysize = 0;
3083 }
3084 break;
3085 }
3086
3088 {
3089 SCIP_MONOTONE monotonicity;
3090
3091 /* get monotonicity of child */
3092 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3093 * SCIPcallExprMonotonicity
3094 */
3095 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3096
3097 /* compute resulting locks of the child expression */
3098 switch( monotonicity )
3099 {
3100 case SCIP_MONOTONE_INC:
3101 ituserdata.intvals[0] = nlockspos;
3102 ituserdata.intvals[1] = nlocksneg;
3103 break;
3104 case SCIP_MONOTONE_DEC:
3105 ituserdata.intvals[0] = nlocksneg;
3106 ituserdata.intvals[1] = nlockspos;
3107 break;
3109 ituserdata.intvals[0] = nlockspos + nlocksneg;
3110 ituserdata.intvals[1] = nlockspos + nlocksneg;
3111 break;
3113 ituserdata.intvals[0] = 0;
3114 ituserdata.intvals[1] = 0;
3115 break;
3116 }
3117 /* set locks in child expression */
3118 SCIPexpriterSetChildUserData(it, ituserdata);
3119
3120 break;
3121 }
3122
3123 default :
3124 /* you should never be here */
3125 SCIPABORT();
3126 break;
3127 }
3128
3129 expr = SCIPexpriterGetNext(it);
3130 }
3131
3132 SCIPfreeExpriter(&it);
3133
3134 return SCIP_OKAY;
3135}
3136
3137/** main function for adding locks to expressions and variables
3138 *
3139 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3140 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3141 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3142 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3143 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3144 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3145 * which implies that updating the monotonicity information during the next locking of this expression does not
3146 * break existing locks.
3147 *
3148 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3149 * locks from an expression and repropagating them after the structural changes have been applied.
3150 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3151 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3152 */
3153static
3155 SCIP* scip, /**< SCIP data structure */
3156 SCIP_CONS* cons, /**< nonlinear constraint */
3157 int nlockspos, /**< number of positive rounding locks */
3158 int nlocksneg /**< number of negative rounding locks */
3159 )
3160{
3161 SCIP_CONSDATA* consdata;
3162
3163 assert(cons != NULL);
3164
3165 if( nlockspos == 0 && nlocksneg == 0 )
3166 return SCIP_OKAY;
3167
3168 consdata = SCIPconsGetData(cons);
3169 assert(consdata != NULL);
3170
3171 /* no constraint sides -> nothing to lock */
3172 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3173 return SCIP_OKAY;
3174
3175 /* remember locks */
3176 consdata->nlockspos += nlockspos;
3177 consdata->nlocksneg += nlocksneg;
3178
3179 assert(consdata->nlockspos >= 0);
3180 assert(consdata->nlocksneg >= 0);
3181
3182 /* compute locks for lock propagation */
3183 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3184 {
3185 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg) );
3186 }
3187 else if( !SCIPisInfinity(scip, consdata->rhs) )
3188 {
3189 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg) );
3190 }
3191 else
3192 {
3193 assert(!SCIPisInfinity(scip, -consdata->lhs));
3194 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos) );
3195 }
3196
3197 return SCIP_OKAY;
3198}
3199
3200/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3201static
3203 SCIP* scip, /**< SCIP data structure */
3204 SCIP_CONS* cons /**< nonlinear constraint */
3205 )
3206{
3207 SCIP_CONSDATA* consdata;
3208
3209 assert(scip != NULL);
3210 assert(cons != NULL);
3211
3212 consdata = SCIPconsGetData(cons);
3213 assert(consdata != NULL);
3214 assert(consdata->expr != NULL);
3215
3216 if( consdata->nlrow != NULL )
3217 {
3218 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3219 }
3220
3221 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3222 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3223 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3224
3225 if( SCIPisExprSum(scip, consdata->expr) )
3226 {
3227 /* if root is a sum, then split into linear and nonlinear terms */
3228 SCIP_EXPR* nonlinpart;
3229 SCIP_EXPR* child;
3230 SCIP_Real* coefs;
3231 int i;
3232
3233 coefs = SCIPgetCoefsExprSum(consdata->expr);
3234
3235 /* constant term of sum */
3236 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3237
3238 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3239 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3240
3241 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3242 {
3243 child = SCIPexprGetChildren(consdata->expr)[i];
3244 if( SCIPisExprVar(scip, child) )
3245 {
3246 /* linear term */
3247 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3248 }
3249 else
3250 {
3251 /* nonlinear term */
3252 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3253 }
3254 }
3255
3256 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3257 {
3258 /* add expression to nlrow (this will make a copy) */
3259 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3260 }
3261 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3262 }
3263 else
3264 {
3265 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3266 }
3267
3268 return SCIP_OKAY;
3269}
3270
3271/** compares enfodata by enforcement priority of nonlinear handler
3272 *
3273 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3274 */
3275static
3277{
3278 SCIP_NLHDLR* h1;
3279 SCIP_NLHDLR* h2;
3280
3281 assert(elem1 != NULL);
3282 assert(elem2 != NULL);
3283
3284 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3285 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3286
3287 assert(h1 != NULL);
3288 assert(h2 != NULL);
3289
3292
3295
3296 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3297}
3298
3299/** install nlhdlrs in one expression */
3300static
3302 SCIP* scip, /**< SCIP data structure */
3303 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3304 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3305 )
3306{
3307 SCIP_EXPR_OWNERDATA* ownerdata;
3308 SCIP_CONSHDLRDATA* conshdlrdata;
3309 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3310 SCIP_NLHDLR_METHOD enforcemethods;
3311 SCIP_NLHDLR_METHOD enforcemethodsnew;
3312 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3313 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3314 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3315 int enfossize; /* allocated length of expr->enfos array */
3316 int h;
3317
3318 assert(expr != NULL);
3319
3320 ownerdata = SCIPexprGetOwnerData(expr);
3321 assert(ownerdata != NULL);
3322
3323 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3324 assert(conshdlrdata != NULL);
3325 assert(conshdlrdata->auxvarid >= 0);
3326 assert(!conshdlrdata->indetect);
3327
3328 /* there should be no enforcer yet and detection should not even have considered expr yet */
3329 assert(ownerdata->nenfos < 0);
3330 assert(ownerdata->enfos == NULL);
3331
3332 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3333 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3334 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3335 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3336 * - if no one uses activity, then do not need activity methods
3337 */
3338 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3339 if( ownerdata->nauxvaruses == 0 )
3340 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3341 else
3342 {
3343 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3344 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3345 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3346 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3347 }
3348 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3349 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3350
3351 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3352 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3353
3354 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3355 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3356
3357 ownerdata->nenfos = 0;
3358 enfossize = 2;
3359 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3360 conshdlrdata->indetect = TRUE;
3361
3362 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3363 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3364 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3365 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3366 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3367
3368 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3369 {
3370 SCIP_NLHDLR* nlhdlr;
3371
3372 nlhdlr = conshdlrdata->nlhdlrs[h];
3373 assert(nlhdlr != NULL);
3374
3375 /* skip disabled nlhdlrs */
3376 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3377 continue;
3378
3379 /* call detect routine of nlhdlr */
3380 nlhdlrexprdata = NULL;
3381 enforcemethodsnew = enforcemethods;
3382 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3383 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3384 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3385 /* coverity[var_deref_model] */
3386 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3387
3388 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3389 nlhdlrparticipating &= enforcemethodsallowed;
3390
3391 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3392 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3393
3394 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3395 * They are also cleaned up here to ensure that only the needed methods are claimed.
3396 */
3397 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3398
3399 /* nlhdlr needs to participate for the methods it is enforcing */
3400 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3401
3402 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3403 {
3404 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3405 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3406
3407 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3408 if( nlhdlrexprdata != NULL )
3409 {
3410 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3411 }
3412 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3413 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3414
3415 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3416
3417 continue;
3418 }
3419
3420 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3421 SCIPnlhdlrGetName(nlhdlr),
3422 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3423 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3424 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3425
3426 /* store nlhdlr and its data */
3427 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3428 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3429 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3430 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3431 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3432 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3433 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3434 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3435 ownerdata->nenfos++;
3436
3437 /* update enforcement flags */
3438 enforcemethods = enforcemethodsnew;
3439 }
3440
3441 conshdlrdata->indetect = FALSE;
3442
3443 /* stop if an enforcement method is missing but we are already in solving stage
3444 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3445 */
3446 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3447 {
3448 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3449 return SCIP_ERROR;
3450 }
3451
3452 assert(ownerdata->nenfos > 0);
3453
3454 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3455 if( ownerdata->nenfos > 1 )
3456 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3457
3458 /* resize enfos array to be nenfos long */
3459 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3460
3461 return SCIP_OKAY;
3462}
3463
3464/** detect nlhdlrs that can handle the expressions */
3465static
3467 SCIP* scip, /**< SCIP data structure */
3468 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3469 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3470 int nconss /**< total number of constraints */
3471 )
3472{
3473 SCIP_CONSHDLRDATA* conshdlrdata;
3474 SCIP_CONSDATA* consdata;
3475 SCIP_EXPR* expr;
3476 SCIP_EXPR_OWNERDATA* ownerdata;
3477 SCIP_EXPRITER* it;
3478 int i;
3479
3480 assert(conss != NULL || nconss == 0);
3481 assert(nconss >= 0);
3482 assert(SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVING && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3483
3484 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3485 assert(conshdlrdata != NULL);
3486
3489
3491 {
3492 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3493 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3494 */
3496 conshdlrdata->globalbounds = TRUE;
3497 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3498 }
3499
3500 for( i = 0; i < nconss; ++i )
3501 {
3502 assert(conss != NULL && conss[i] != NULL);
3503
3504 consdata = SCIPconsGetData(conss[i]);
3505 assert(consdata != NULL);
3506 assert(consdata->expr != NULL);
3507
3508 /* if a constraint is separated, we currently need it to be initial, too
3509 * this is because INITLP will create the auxiliary variables that are used for any separation
3510 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3511 */
3512 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3513
3514 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3515 assert(ownerdata != NULL);
3516
3517 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3518 * then we would normally skip to run DETECT again
3519 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3520 * thus, if expr is the root expression, we rerun DETECT
3521 */
3522 if( ownerdata->nenfos > 0 )
3523 {
3524 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3525 assert(ownerdata->nenfos < 0);
3526 }
3527
3528 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3529 * this way we can treat the root expression like any other expression when enforcing via separation
3530 * if constraint will be propagated, then register activity usage of root expression
3531 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3532 */
3533 conshdlrdata->indetect = TRUE;
3536 SCIPconsIsPropagated(conss[i]),
3537 FALSE, FALSE) );
3538 conshdlrdata->indetect = FALSE;
3539
3540 /* 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
3541 * if this presolver may be run in the current presolve round (presoltiming=exhaustive could be added as additional criterion),
3542 * then we ensure that a routine will be present to compute this activity (SCIPregisterExprUsageNonlinear actually updates activity already)
3543 */
3544 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd'
3545 && (SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs)) && SCIPisExprSum(scip, consdata->expr) )
3546 {
3547 int c;
3548 for( c = 0; c < SCIPexprGetNChildren(consdata->expr); ++c )
3549 {
3550 expr = SCIPexprGetChildren(consdata->expr)[c];
3551 if( SCIPisExprProduct(scip, expr) )
3552 {
3554 }
3555 }
3556 }
3557
3558 /* compute integrality information for all subexpressions */
3559 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3560
3561 /* run detectNlhdlr on all expr where required */
3562 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3563 {
3564 ownerdata = SCIPexprGetOwnerData(expr);
3565 assert(ownerdata != NULL);
3566
3567 /* skip exprs that we already looked at */
3568 if( ownerdata->nenfos >= 0 )
3569 continue;
3570
3571 /* if there is use of the auxvar, then someone requires that
3572 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3573 * thus, we need to find nlhdlrs that separate or estimate
3574 * if there is use of the activity, then there is someone requiring that
3575 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3576 * thus, we need to find nlhdlrs that do interval-evaluation
3577 */
3578 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3579 {
3580 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3581
3582 assert(ownerdata->nenfos >= 0);
3583 }
3584 else
3585 {
3586 /* remember that we looked at this expression during detectNlhdlrs
3587 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3588 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3589 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3590 */
3591 ownerdata->nenfos = 0;
3592 }
3593 }
3594
3595 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3596 if( SCIPconsIsPropagated(conss[i]) )
3597 consdata->ispropagated = FALSE;
3598 }
3599
3601 {
3602 /* ensure that the local bounds are used again when reevaluating the expressions later;
3603 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3604 */
3606 conshdlrdata->globalbounds = FALSE;
3607 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3608 }
3609 else
3610 {
3611 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3613 }
3614
3615 SCIPfreeExpriter(&it);
3616
3617 return SCIP_OKAY;
3618}
3619
3620/** initializes (pre)solving data of constraints
3621 *
3622 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3623 * not be modified.
3624 * In particular, this function
3625 * - runs the detection method of nlhldrs
3626 * - looks for unlocked linear variables
3627 * - checks curvature (if not in presolve)
3628 * - creates and add row to NLP (if not in presolve)
3629 *
3630 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3631 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3632 */
3633static
3635 SCIP* scip, /**< SCIP data structure */
3636 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3637 SCIP_CONS** conss, /**< constraints */
3638 int nconss /**< number of constraints */
3639 )
3640{
3641 int c;
3642
3643 for( c = 0; c < nconss; ++c )
3644 {
3645 /* check for a linear variable that can be increase or decreased without harming feasibility */
3646 findUnlockedLinearVar(scip, conss[c]);
3647
3649 {
3650 SCIP_CONSDATA* consdata;
3651 SCIP_Bool success = FALSE;
3652
3653 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3654 assert(consdata != NULL);
3655 assert(consdata->expr != NULL);
3656
3657 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3658 {
3659 /* call the curvature detection algorithm of the convex nonlinear handler
3660 * Check only for those curvature that may result in a convex inequality, i.e.,
3661 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3662 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3663 */
3664 if( !SCIPisInfinity(scip, -consdata->lhs) )
3665 {
3666 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3667 if( success )
3668 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3669 }
3670 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3671 {
3672 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3673 if( success )
3674 consdata->curv = SCIP_EXPRCURV_CONVEX;
3675 }
3676 }
3677 else
3678 {
3679 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3680 {
3681 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3682 consdata->curv = SCIP_EXPRCURV_LINEAR;
3683 }
3684 else
3685 {
3686 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3687 }
3688 }
3689 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3690
3691 /* add nlrow representation to NLP, if NLP had been constructed */
3693 {
3694 if( consdata->nlrow == NULL )
3695 {
3696 SCIP_CALL( createNlRow(scip, conss[c]) );
3697 assert(consdata->nlrow != NULL);
3698 }
3699 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3700 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3701 }
3702 }
3703 }
3704
3705 /* register non linear handlers */
3706 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3707
3708 return SCIP_OKAY;
3709}
3710
3711/** deinitializes (pre)solving data of constraints
3712 *
3713 * This removes the initialization data created in initSolve().
3714 *
3715 * This function can be called in presolve and solve.
3716 *
3717 * TODO At the moment, it should not be called for a constraint if there are other constraints
3718 * that use the same expressions but still require their nlhdlr.
3719 * We should probably only decrement the auxvar and activity usage for the root expr and then
3720 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3721 */
3722static
3724 SCIP* scip, /**< SCIP data structure */
3725 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3726 SCIP_CONS** conss, /**< constraints */
3727 int nconss /**< number of constraints */
3728 )
3729{
3730 SCIP_EXPRITER* it;
3731 SCIP_EXPR* expr;
3732 SCIP_CONSDATA* consdata;
3733 SCIP_Bool rootactivityvalid;
3734 int c;
3735
3739
3740 /* call deinitialization callbacks of expression and nonlinear handlers
3741 * free nonlinear handlers information from expressions
3742 * remove auxiliary variables and nactivityuses counts from expressions
3743 */
3744 for( c = 0; c < nconss; ++c )
3745 {
3746 assert(conss != NULL);
3747 assert(conss[c] != NULL);
3748
3749 consdata = SCIPconsGetData(conss[c]);
3750 assert(consdata != NULL);
3751 assert(consdata->expr != NULL);
3752
3753 /* check and remember whether activity in root is valid */
3754 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3755
3756 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3757 {
3758 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3759
3760 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3761 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3762
3763 /* remove quadratic info */
3765
3766 if( rootactivityvalid )
3767 {
3768 /* ensure activity is valid if consdata->expr activity is valid
3769 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3770 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3771 * so this childs activity would be invalid, which can generate confusion
3772 */
3774 }
3775 }
3776
3777 if( consdata->nlrow != NULL )
3778 {
3779 /* remove row from NLP, if still in solving
3780 * if we are in exitsolve, the whole NLP will be freed anyway
3781 */
3783 {
3784 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3785 }
3786
3787 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3788 }
3789
3790 /* forget about linear variables that can be increased or decreased without harming feasibility */
3791 consdata->linvardecr = NULL;
3792 consdata->linvarincr = NULL;
3793
3794 /* forget about curvature */
3795 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3796 }
3797
3798 SCIPfreeExpriter(&it);
3799
3800 return SCIP_OKAY;
3801}
3802
3803/** helper method to decide whether a given expression is product of at least two binary variables */
3804static
3806 SCIP* scip, /**< SCIP data structure */
3807 SCIP_EXPR* expr /**< expression */
3808 )
3809{
3810 int i;
3811
3812 assert(expr != NULL);
3813
3814 /* check whether the expression is a product */
3815 if( !SCIPisExprProduct(scip, expr) )
3816 return FALSE;
3817
3818 /* don't consider products with a coefficient != 1 and products with a single child
3819 * simplification will take care of this expression later
3820 */
3821 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3822 return FALSE;
3823
3824 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3825 {
3826 SCIP_EXPR* child;
3827 SCIP_VAR* var;
3828
3829 child = SCIPexprGetChildren(expr)[i];
3830 assert(child != NULL);
3831
3832 if( !SCIPisExprVar(scip, child) )
3833 return FALSE;
3834
3835 var = SCIPgetVarExprVar(child);
3836
3837 /* check whether variable is binary, in any feasible solution
3838 * we need to forbid weakly implied binary variables because cons_and wouldn't ensure that the
3839 * product condition holds in any feasible solution (i.e., when vars may not be at bounds) in this case,
3840 * which would lead to accepting solutions that are not feasible in the original (non-reformulated) cons
3841 */
3843 return FALSE;
3844 }
3845
3846 return TRUE;
3847}
3848
3849/** helper method to collect all bilinear binary product terms */
3850static
3852 SCIP* scip, /**< SCIP data structure */
3853 SCIP_EXPR* sumexpr, /**< sum expression */
3854 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3855 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3856 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3857 int* nterms /**< pointer to store the total number of bilinear binary terms */
3858 )
3859{
3860 int i;
3861
3862 assert(sumexpr != NULL);
3863 assert(SCIPisExprSum(scip, sumexpr));
3864 assert(xs != NULL);
3865 assert(ys != NULL);
3866 assert(childidxs != NULL);
3867 assert(nterms != NULL);
3868
3869 *nterms = 0;
3870
3871 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3872 {
3873 SCIP_EXPR* child;
3874
3875 child = SCIPexprGetChildren(sumexpr)[i];
3876 assert(child != NULL);
3877
3878 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3879 {
3882
3883 assert(x != NULL);
3884 assert(y != NULL);
3885
3886 if( x != y )
3887 {
3888 xs[*nterms] = x;
3889 ys[*nterms] = y;
3890 childidxs[*nterms] = i;
3891 ++(*nterms);
3892 }
3893 }
3894 }
3895
3896 return SCIP_OKAY;
3897}
3898
3899/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3900static
3902 SCIP* scip, /**< SCIP data structure */
3903 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3904 SCIP_CONS* cons, /**< constraint */
3905 SCIP_VAR* facvar, /**< variable that has been factorized */
3906 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3907 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3908 int nvars, /**< total number of variables in sum_j c_ij x_j */
3909 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3910 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3911 )
3912{
3913 SCIP_VAR* auxvar;
3914 SCIP_CONS* newcons;
3915 SCIP_Real minact = 0.0;
3916 SCIP_Real maxact = 0.0;
3918 char name [SCIP_MAXSTRLEN];
3919 int i;
3920
3921 assert(facvar != NULL);
3922 assert(vars != NULL);
3923 assert(nvars > 1);
3924 assert(newexpr != NULL);
3925
3926 /* compute minimum and maximum activity of sum_j c_ij x_j */
3927 /* 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 */
3928 for( i = 0; i < nvars; ++i )
3929 {
3930 minact += MIN(coefs[i], 0.0);
3931 maxact += MAX(coefs[i], 0.0);
3934
3935 if( impltype != SCIP_IMPLINTTYPE_NONE && !SCIPisIntegral(scip, coefs[i]) )
3936 impltype = SCIP_IMPLINTTYPE_NONE;
3937 }
3938 assert(minact <= maxact);
3939
3940 /* create and add auxiliary variable */
3941 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3942 SCIP_CALL( SCIPcreateVarImpl(scip, &auxvar, name, minact, maxact, 0.0, SCIP_VARTYPE_CONTINUOUS, impltype,
3943 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
3944 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3945
3946#ifdef WITH_DEBUG_SOLUTION
3947 if( SCIPdebugIsMainscip(scip) )
3948 {
3949 SCIP_Real debugsolval; /* value of auxvar in debug solution */
3950 SCIP_Real val;
3951
3952 /* compute value of new variable in debug solution */
3953 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
3954 debugsolval = 0.0;
3955 for( i = 0; i < nvars; ++i )
3956 {
3958 debugsolval += coefs[i] * val;
3959 }
3960
3961 /* now multiply by x_i (facvar) */
3962 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
3963 debugsolval *= val;
3964
3965 /* store debug solution value of auxiliary variable */
3966 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
3967 }
3968#endif
3969
3970 /* create and add z - maxact x <= 0 */
3971 if( !SCIPisZero(scip, maxact) )
3972 {
3973 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3974 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3975 SCIP_CALL( SCIPaddCons(scip, newcons) );
3976 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3977 if( naddconss != NULL )
3978 ++(*naddconss);
3979 }
3980
3981 /* create and add 0 <= z - minact x */
3982 if( !SCIPisZero(scip, minact) )
3983 {
3984 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3985 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3986 SCIP_CALL( SCIPaddCons(scip, newcons) );
3987 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3988 if( naddconss != NULL )
3989 ++(*naddconss);
3990 }
3991
3992 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3993 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3994 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3995 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3996 if( !SCIPisZero(scip, minact) )
3997 {
3998 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3999 }
4000 SCIP_CALL( SCIPaddCons(scip, newcons) );
4001 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4002 if( naddconss != NULL )
4003 ++(*naddconss);
4004
4005 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4006 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4007 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4008 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4009 if( !SCIPisZero(scip, maxact) )
4010 {
4011 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4012 }
4013 SCIP_CALL( SCIPaddCons(scip, newcons) );
4014 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4015 if( naddconss != NULL )
4016 ++(*naddconss);
4017
4018 /* create variable expression */
4019 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4020
4021 /* release auxvar */
4022 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4023
4024 return SCIP_OKAY;
4025}
4026
4027/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4028static
4030 SCIP* scip, /**< SCIP data structure */
4031 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4032 SCIP_CONS* cons, /**< constraint */
4033 SCIP_EXPR* sumexpr, /**< expression */
4034 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4035 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4036 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4037 )
4038{
4039 SCIP_EXPR** exprs = NULL;
4040 SCIP_VAR** tmpvars = NULL;
4041 SCIP_VAR** vars = NULL;
4042 SCIP_VAR** xs = NULL;
4043 SCIP_VAR** ys = NULL;
4044 SCIP_Real* exprcoefs = NULL;
4045 SCIP_Real* tmpcoefs = NULL;
4046 SCIP_Real* sumcoefs;
4047 SCIP_Bool* isused = NULL;
4048 int* childidxs = NULL;
4049 int* count = NULL;
4050 int nchildren;
4051 int nexprs = 0;
4052 int nterms;
4053 int nvars;
4054 int ntotalvars;
4055 int i;
4056
4057 assert(sumexpr != NULL);
4058 assert(minterms > 1);
4059 assert(newexpr != NULL);
4060
4061 *newexpr = NULL;
4062
4063 /* check whether sumexpr is indeed a sum */
4064 if( !SCIPisExprSum(scip, sumexpr) )
4065 return SCIP_OKAY;
4066
4067 nchildren = SCIPexprGetNChildren(sumexpr);
4068 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4070 ntotalvars = SCIPgetNTotalVars(scip);
4071
4072 /* check whether there are enough terms available */
4073 if( nchildren < minterms )
4074 return SCIP_OKAY;
4075
4076 /* allocate memory */
4077 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4078 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4079 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4080
4081 /* collect all bilinear binary product terms */
4082 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4083
4084 /* check whether there are enough terms available */
4085 if( nterms < minterms )
4086 goto TERMINATE;
4087
4088 /* store how often each variable appears in a bilinear binary product */
4090 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4091 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4092
4093 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4094 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4097
4098 for( i = 0; i < nterms; ++i )
4099 {
4100 int xidx;
4101 int yidx;
4102
4103 assert(xs[i] != NULL);
4104 assert(ys[i] != NULL);
4105
4106 xidx = SCIPvarGetIndex(xs[i]);
4107 assert(xidx < ntotalvars);
4108 yidx = SCIPvarGetIndex(ys[i]);
4109 assert(yidx < ntotalvars);
4110
4111 ++count[xidx];
4112 ++count[yidx];
4113
4114 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4115 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4116 }
4117
4118 /* sort variables; don't change order of count array because it depends on problem indices */
4119 {
4120 int* tmpcount;
4121
4122 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4123 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4124 SCIPfreeBufferArray(scip, &tmpcount);
4125 }
4126
4127 for( i = 0; i < nvars; ++i )
4128 {
4129 SCIP_VAR* facvar = vars[i];
4130 int ntmpvars = 0;
4131 int j;
4132
4133 /* skip candidate if there are not enough terms left */
4134 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4135 continue;
4136
4137 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4138
4139 /* collect variables for x_i * sum_j c_ij x_j */
4140 for( j = 0; j < nterms; ++j )
4141 {
4142 int childidx = childidxs[j];
4143 assert(childidx >= 0 && childidx < nchildren);
4144
4145 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4146 {
4147 SCIP_Real coef;
4148 int xidx;
4149 int yidx;
4150
4151 coef = sumcoefs[childidx];
4152 assert(coef != 0.0);
4153
4154 /* collect corresponding variable */
4155 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4156 tmpcoefs[ntmpvars] = coef;
4157 ++ntmpvars;
4158
4159 /* update counters */
4160 xidx = SCIPvarGetIndex(xs[j]);
4161 assert(xidx < ntotalvars);
4162 yidx = SCIPvarGetIndex(ys[j]);
4163 assert(yidx < ntotalvars);
4164 --count[xidx];
4165 --count[yidx];
4166 assert(count[xidx] >= 0);
4167 assert(count[yidx] >= 0);
4168
4169 /* mark term to be used */
4170 isused[childidx] = TRUE;
4171 }
4172 }
4173 assert(ntmpvars >= minterms);
4174 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4175 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4176
4177 /* create required constraints and store the generated expression */
4178 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4179 exprcoefs[nexprs] = 1.0;
4180 ++nexprs;
4181 }
4182
4183 /* factorization was only successful if at least one expression has been generated */
4184 if( nexprs > 0 )
4185 {
4186 int nexprsold = nexprs;
4187
4188 /* add all children of the sum that have not been used */
4189 for( i = 0; i < nchildren; ++i )
4190 {
4191 if( !isused[i] )
4192 {
4193 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4194 exprcoefs[nexprs] = sumcoefs[i];
4195 ++nexprs;
4196 }
4197 }
4198
4199 /* create a new sum expression */
4200 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4201
4202 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4203 for( i = 0; i < nexprsold; ++i )
4204 {
4205 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4206 }
4207 }
4208
4209TERMINATE:
4210 /* free memory */
4211 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4212 SCIPfreeBufferArrayNull(scip, &tmpvars);
4213 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4216 SCIPfreeBufferArrayNull(scip, &isused);
4218 SCIPfreeBufferArray(scip, &childidxs);
4221
4222 return SCIP_OKAY;
4223}
4224
4225/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4226static
4228 SCIP* scip, /**< SCIP data structure */
4229 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4230 SCIP_EXPR* prodexpr, /**< product expression */
4231 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4232 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4233 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4234 )
4235{
4236 SCIP_VAR** vars;
4237 SCIP_CONS* cons;
4238 SCIP_Real* coefs;
4239 SCIP_VAR* w;
4240 char* name;
4241 int nchildren;
4242 int i;
4243
4244 assert(conshdlr != NULL);
4245 assert(prodexpr != NULL);
4246 assert(SCIPisExprProduct(scip, prodexpr));
4247 assert(newexpr != NULL);
4248
4249 nchildren = SCIPexprGetNChildren(prodexpr);
4250 assert(nchildren >= 2);
4251
4252 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4253 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4254 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4255 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4256
4257 /* prepare the names of the variable and the constraints */
4258 /* coverity[secure_coding] */
4259 strcpy(name, "binreform");
4260 for( i = 0; i < nchildren; ++i )
4261 {
4263 coefs[i] = 1.0;
4264 assert(vars[i] != NULL);
4265 (void) strcat(name, "_");
4266 (void) strcat(name, SCIPvarGetName(vars[i]));
4267
4269 }
4270
4271 /* create and add variable */
4272 SCIP_CALL( SCIPcreateVarImpl(scip, &w, name, 0.0, 1.0, 0.0,
4274 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
4276 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4277
4278#ifdef WITH_DEBUG_SOLUTION
4279 if( SCIPdebugIsMainscip(scip) )
4280 {
4281 SCIP_Real debugsolval; /* value of auxvar in debug solution */
4282 SCIP_Real val;
4283
4284 /* compute value of new variable in debug solution (\prod_i vars[i]) */
4285 debugsolval = 1.0;
4286 for( i = 0; i < nchildren; ++i )
4287 {
4289 debugsolval *= val;
4290 }
4291
4292 /* store debug solution value of auxiliary variable */
4293 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
4294 }
4295#endif
4296
4297 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4298 if( nchildren == 2 && !empathy4and )
4299 {
4300 SCIP_VAR* x = vars[0];
4301 SCIP_VAR* y = vars[1];
4302
4303 assert(x != NULL);
4304 assert(y != NULL);
4305 assert(x != y);
4306
4307 /* create and add x - w >= 0 */
4308 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4309 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4310 SCIP_CALL( SCIPaddCons(scip, cons) );
4311 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4312
4313 /* create and add y - w >= 0 */
4314 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4315 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4316 SCIP_CALL( SCIPaddCons(scip, cons) );
4317 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4318
4319 /* create and add x + y - w <= 1 */
4320 vars[2] = w;
4321 coefs[2] = -1.0;
4322 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4323 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4324 SCIP_CALL( SCIPaddCons(scip, cons) );
4325 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4326
4327 /* update number of added constraints */
4328 if( naddconss != NULL )
4329 *naddconss += 3;
4330 }
4331 else
4332 {
4333 /* create, add, and release AND constraint */
4334 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4335 SCIP_CALL( SCIPaddCons(scip, cons) );
4336 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4337 SCIPdebugMsg(scip, " create AND constraint\n");
4338
4339 /* update number of added constraints */
4340 if( naddconss != NULL )
4341 *naddconss += 1;
4342 }
4343
4344 /* create variable expression */
4345 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4346
4347 /* release created variable */
4349
4350 /* free memory */
4351 SCIPfreeBufferArray(scip, &name);
4352 SCIPfreeBufferArray(scip, &coefs);
4354
4355 return SCIP_OKAY;
4356}
4357
4358/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4359static
4361 SCIP* scip, /**< SCIP data structure */
4362 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4363 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4364 SCIP_EXPR* prodexpr, /**< product expression */
4365 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4366 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4367 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4368 )
4369{
4370 SCIP_CONSHDLRDATA* conshdlrdata;
4371 int nchildren;
4372
4373 assert(prodexpr != NULL);
4374 assert(newexpr != NULL);
4375
4376 *newexpr = NULL;
4377
4378 /* only consider products of binary variables */
4379 if( !isBinaryProduct(scip, prodexpr) )
4380 return SCIP_OKAY;
4381
4382 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4383 assert(conshdlrdata != NULL);
4384 nchildren = SCIPexprGetNChildren(prodexpr);
4385 assert(nchildren >= 2);
4386
4387 /* check whether there is already an expression that represents the product */
4388 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4389 {
4390 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4391 assert(*newexpr != NULL);
4392
4393 /* capture expression */
4394 SCIPcaptureExpr(*newexpr);
4395 }
4396 else
4397 {
4398 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4399
4400 if( nchildren == 2 )
4401 {
4402 SCIP_CLIQUE** xcliques;
4403 SCIP_CONS* clqcons;
4404 SCIP_VAR* clqvars[2];
4405 SCIP_VAR* x;
4406 SCIP_VAR* y;
4407 SCIP_Bool found_clique = FALSE;
4408 char clqname[SCIP_MAXSTRLEN];
4409 int c;
4410
4411 /* get variables from the product expression */
4412 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4413 assert(x != NULL);
4414 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4415 assert(y != NULL);
4416 assert(x != y);
4417
4418 /* first try to find a clique containing both variables */
4419 xcliques = SCIPvarGetCliques(x, TRUE);
4420
4421 /* look in cliques containing x */
4422 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4423 {
4424 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4425 {
4426 /* add clique as explicit set packing constraint to preserve model completeness */
4427 clqvars[0] = x;
4428 clqvars[1] = y;
4429 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
4430 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
4431 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
4432 SCIP_CALL( SCIPaddCons(scip, clqcons) );
4433 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
4434
4435 /* create zero value expression */
4436 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4437
4438 if( naddconss != NULL )
4439 *naddconss += 1;
4440 if( nchgcoefs != NULL )
4441 *nchgcoefs += 1;
4442
4443 found_clique = TRUE;
4444 break;
4445 }
4446
4447 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4448 {
4449 /* add clique as explicit set packing constraint: x + (1-y) <= 1 */
4450 clqvars[0] = x;
4451 SCIP_CALL( SCIPgetNegatedVar(scip, y, &clqvars[1]) );
4452 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
4453 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
4454 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
4455 SCIP_CALL( SCIPaddCons(scip, clqcons) );
4456 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
4457
4458 /* create variable expression for x */
4459 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4460
4461 if( naddconss != NULL )
4462 *naddconss += 1;
4463 if( nchgcoefs != NULL )
4464 *nchgcoefs += 2;
4465
4466 found_clique = TRUE;
4467 break;
4468 }
4469 }
4470
4471 if( !found_clique )
4472 {
4473 xcliques = SCIPvarGetCliques(x, FALSE);
4474
4475 /* look in cliques containing complement of x */
4476 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4477 {
4478 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4479 {
4480 /* add clique as explicit set packing constraint: (1-x) + y <= 1 */
4481 SCIP_CALL( SCIPgetNegatedVar(scip, x, &clqvars[0]) );
4482 clqvars[1] = y;
4483 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
4484 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
4485 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
4486 SCIP_CALL( SCIPaddCons(scip, clqcons) );
4487 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
4488
4489 /* create variable expression for y */
4490 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4491
4492 if( naddconss != NULL )
4493 *naddconss += 1;
4494 if( nchgcoefs != NULL )
4495 *nchgcoefs += 1;
4496
4497 found_clique = TRUE;
4498 break;
4499 }
4500
4501 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4502 {
4503 /* add clique as explicit set covering constraint: x + y >= 1 */
4504 clqvars[0] = x;
4505 clqvars[1] = y;
4506 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
4507 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
4508 SCIP_CALL( SCIPcreateConsBasicSetcover(scip, &clqcons, clqname, 2, clqvars) );
4509 SCIP_CALL( SCIPaddCons(scip, clqcons) );
4510 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
4511
4512 /* create sum expression */
4513 SCIP_EXPR* sum_children[2];
4514 SCIP_Real sum_coefs[2];
4515 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4516 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4517 sum_coefs[0] = 1.0;
4518 sum_coefs[1] = 1.0;
4519 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4520
4521 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4522 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4523
4524 if( naddconss != NULL )
4525 *naddconss += 1;
4526 if( nchgcoefs != NULL )
4527 *nchgcoefs += 3;
4528
4529 found_clique = TRUE;
4530 break;
4531 }
4532 }
4533 }
4534
4535 /* if the variables are not in a clique, do standard linearization */
4536 if( !found_clique )
4537 {
4538 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4539 }
4540 }
4541 else
4542 {
4543 /* linearize binary product using an AND constraint because nchildren > 2 */
4544 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4545 }
4546
4547 /* hash variable expression */
4548 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4549 }
4550
4551 return SCIP_OKAY;
4552}
4553
4554/** helper function to replace binary products in a given constraint */
4555static
4557 SCIP* scip, /**< SCIP data structure */
4558 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4559 SCIP_CONS* cons, /**< constraint */
4560 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4561 SCIP_EXPRITER* it, /**< expression iterator */
4562 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4563 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4564 )
4565{
4566 SCIP_CONSHDLRDATA* conshdlrdata;
4567 SCIP_CONSDATA* consdata;
4568 SCIP_EXPR* expr;
4569
4570 assert(conshdlr != NULL);
4571 assert(cons != NULL);
4572 assert(exprmap != NULL);
4573 assert(it != NULL);
4574
4575 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4576 assert(conshdlrdata != NULL);
4577
4578 consdata = SCIPconsGetData(cons);
4579 assert(consdata != NULL);
4580 assert(consdata->expr != NULL);
4581
4582 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4583
4584 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4585 {
4586 SCIP_EXPR* newexpr = NULL;
4587 SCIP_EXPR* childexpr;
4588 int childexpridx;
4589
4590 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4591 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4592 childexpr = SCIPexpriterGetChildExprDFS(it);
4593 assert(childexpr != NULL);
4594
4595 /* try to factorize variables in a sum expression that contains several products of binary variables */
4596 if( conshdlrdata->reformbinprodsfac > 1 )
4597 {
4598 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4599 }
4600
4601 /* try to create an expression that represents a product of binary variables */
4602 if( newexpr == NULL )
4603 {
4604 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4605 }
4606
4607 if( newexpr != NULL )
4608 {
4609 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4610
4611 /* replace product expression */
4612 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4613
4614 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4615 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4616
4617 /* mark the constraint to not be simplified anymore */
4618 consdata->issimplified = FALSE;
4619 }
4620 }
4621
4622 return SCIP_OKAY;
4623}
4624
4625/** reformulates products of binary variables during presolving in the following way:
4626 *
4627 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4628 * 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}:
4629 * \f[
4630 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4631 * \f]
4632 *
4633 * 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
4634 * \f$x_j\f$. These cliques allow for a better reformulation. There are four cases:
4635 *
4636 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4637 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4638 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4639 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4640 *
4641 * When a clique is used, the corresponding inequality is added as an explicit set packing or covering
4642 * constraint to preserve model completeness, since the clique may have been derived from a constraint containing
4643 * \f$x_i x_j\f$. For example, when \f$x_i x_j \leq 0\f$ provides the clique \f$(x_i, x_j)\f$, then the binary
4644 * reformulation replaces \f$x_i x_j\f$ by 0 (case 1), but now \f$0 \leq 0\f$ no longer enforces \f$x_i = 0 \vee x_j = 0\f$.
4645 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4646 *
4647 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4648 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4649 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4650 * Such a lower sum is reformulated with only one extra variable w_i:
4651 * \f{align}{
4652 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4653 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4654 * \text{minact}\, x_i & \leq w_i, \\
4655 * w_i &\leq \text{maxact}\, x_i, \\
4656 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4657 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4658 * \f}
4659 * 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
4660 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4661 * of terms are prioritized.
4662 */
4663static
4665 SCIP* scip, /**< SCIP data structure */
4666 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4667 SCIP_CONS** conss, /**< constraints */
4668 int nconss, /**< total number of constraints */
4669 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4670 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4671 )
4672{
4673 SCIP_CONSHDLRDATA* conshdlrdata;
4674 SCIP_HASHMAP* exprmap;
4675 SCIP_EXPRITER* it;
4676 int c;
4677
4678 assert(conshdlr != NULL);
4679
4680 /* no nonlinear constraints or binary variables -> skip */
4681 if( nconss == 0 || SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip) == 0 )
4682 return SCIP_OKAY;
4683 assert(conss != NULL);
4684
4685 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4686 assert(conshdlrdata != NULL);
4687
4688 /* create expression hash map */
4690
4691 /* create expression iterator */
4695
4696 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4697
4698 for( c = 0; c < nconss; ++c )
4699 {
4700 SCIP_CONSDATA* consdata;
4701 SCIP_EXPR* newexpr = NULL;
4702
4703 assert(conss[c] != NULL);
4704
4705 consdata = SCIPconsGetData(conss[c]);
4706 assert(consdata != NULL);
4707
4708 /* try to reformulate the root expression */
4709 if( conshdlrdata->reformbinprodsfac > 1 )
4710 {
4711 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4712 }
4713
4714 /* release the root node if another expression has been found */
4715 if( newexpr != NULL )
4716 {
4717 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4718 consdata->expr = newexpr;
4719
4720 /* mark constraint to be not simplified anymore */
4721 consdata->issimplified = FALSE;
4722 }
4723
4724 /* replace each product of binary variables separately */
4725 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4726 }
4727
4728 /* free memory */
4729 SCIPhashmapFree(&exprmap);
4730 SCIPfreeExpriter(&it);
4731
4732 return SCIP_OKAY;
4733}
4734
4735/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4736 *
4737 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4738 * Then scale by -1 if
4739 * - \f$n_+ < n_-\f$, or
4740 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4741 */
4742static
4744 SCIP* scip, /**< SCIP data structure */
4745 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4746 SCIP_CONS* cons, /**< nonlinear constraint */
4747 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4748 )
4749{
4750 SCIP_CONSDATA* consdata;
4751 int i;
4752
4753 assert(cons != NULL);
4754
4755 consdata = SCIPconsGetData(cons);
4756 assert(consdata != NULL);
4757
4758 if( SCIPisExprSum(scip, consdata->expr) )
4759 {
4760 SCIP_Real* coefs;
4761 SCIP_Real constant;
4762 int nchildren;
4763 int counter = 0;
4764
4765 coefs = SCIPgetCoefsExprSum(consdata->expr);
4766 constant = SCIPgetConstantExprSum(consdata->expr);
4767 nchildren = SCIPexprGetNChildren(consdata->expr);
4768
4769 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4770 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4771 {
4772 SCIP_EXPR* expr;
4773 expr = consdata->expr;
4774
4775 consdata->expr = SCIPexprGetChildren(expr)[0];
4776 assert(!SCIPisExprSum(scip, consdata->expr));
4777
4778 SCIPcaptureExpr(consdata->expr);
4779
4780 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4781 consdata->lhs = -consdata->lhs;
4782 consdata->rhs = -consdata->rhs;
4783
4784 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4785 *changed = TRUE;
4786 return SCIP_OKAY;
4787 }
4788
4789 /* compute n_+ - n_i */
4790 for( i = 0; i < nchildren; ++i )
4791 counter += coefs[i] > 0 ? 1 : -1;
4792
4793 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4794 {
4795 SCIP_EXPR* expr;
4796 SCIP_Real* newcoefs;
4797
4798 /* allocate memory */
4799 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4800
4801 for( i = 0; i < nchildren; ++i )
4802 newcoefs[i] = -coefs[i];
4803
4804 /* create a new sum expression */
4805 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4806
4807 /* replace expression in constraint data and scale sides */
4808 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4809 consdata->expr = expr;
4810 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4811 consdata->lhs = -consdata->lhs;
4812 consdata->rhs = -consdata->rhs;
4813
4814 /* free memory */
4815 SCIPfreeBufferArray(scip, &newcoefs);
4816
4817 *changed = TRUE;
4818 }
4819 }
4820
4821 return SCIP_OKAY;
4822}
4823
4824/** forbid multiaggrations of variables that appear nonlinear in constraints */
4825static
4827 SCIP* scip, /**< SCIP data structure */
4828 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4829 SCIP_CONS** conss, /**< constraints */
4830 int nconss /**< number of constraints */
4831 )
4832{
4833 SCIP_EXPRITER* it;
4834 SCIP_CONSDATA* consdata;
4835 SCIP_EXPR* expr;
4836 int c;
4837
4838 assert(scip != NULL);
4839 assert(conshdlr != NULL);
4840
4841 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4842 return SCIP_OKAY;
4843
4846
4847 for( c = 0; c < nconss; ++c )
4848 {
4849 consdata = SCIPconsGetData(conss[c]);
4850 assert(consdata != NULL);
4851
4852 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4853 * i.e., skip children of sum that are variables
4854 */
4855 if( SCIPisExprSum(scip, consdata->expr) )
4856 {
4857 int i;
4858 SCIP_EXPR* child;
4859 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4860 {
4861 child = SCIPexprGetChildren(consdata->expr)[i];
4862
4863 /* skip variable expression, as they correspond to a linear term */
4864 if( SCIPisExprVar(scip, child) )
4865 continue;
4866
4867 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4868 if( SCIPisExprVar(scip, expr) )
4869 {
4871 }
4872 }
4873 }
4874 else
4875 {
4876 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4877 if( SCIPisExprVar(scip, expr) )
4878 {
4880 }
4881 }
4882 }
4883
4884 SCIPfreeExpriter(&it);
4885
4886 return SCIP_OKAY;
4887}
4888
4889/** simplifies expressions and replaces common subexpressions for a set of constraints
4890 * @todo put the constant to the constraint sides
4891 */
4892static
4894 SCIP* scip, /**< SCIP data structure */
4895 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4896 SCIP_CONS** conss, /**< constraints */
4897 int nconss, /**< total number of constraints */
4898 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4899 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4900 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4901 int* naddconss, /**< counter to add number of added constraints, or NULL */
4902 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4903 )
4904{
4905 SCIP_CONSHDLRDATA* conshdlrdata;
4906 SCIP_CONSDATA* consdata;
4907 int* nlockspos;
4908 int* nlocksneg;
4909 SCIP_Bool havechange;
4910 int i;
4911
4912 assert(scip != NULL);
4913 assert(conshdlr != NULL);
4914 assert(conss != NULL);
4915 assert(nconss > 0);
4916 assert(infeasible != NULL);
4917
4918 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4919 assert(conshdlrdata != NULL);
4920
4921 /* update number of canonicalize calls */
4922 ++(conshdlrdata->ncanonicalizecalls);
4923
4924 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4925
4926 *infeasible = FALSE;
4927
4928 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4929 havechange = conshdlrdata->ncanonicalizecalls == 1;
4930
4931 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4932 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4933
4934 /* allocate memory for storing locks of each constraint */
4935 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4936 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4937
4938 /* unlock all constraints */
4939 for( i = 0; i < nconss; ++i )
4940 {
4941 assert(conss[i] != NULL);
4942
4943 consdata = SCIPconsGetData(conss[i]);
4944 assert(consdata != NULL);
4945
4946 /* remember locks */
4947 nlockspos[i] = consdata->nlockspos;
4948 nlocksneg[i] = consdata->nlocksneg;
4949
4950 /* remove locks */
4951 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4952 assert(consdata->nlockspos == 0);
4953 assert(consdata->nlocksneg == 0);
4954 }
4955
4956#ifndef NDEBUG
4957 /* check whether all locks of each expression have been removed */
4958 for( i = 0; i < nconss; ++i )
4959 {
4960 SCIP_EXPR* expr;
4961 SCIP_EXPRITER* it;
4962
4964
4965 consdata = SCIPconsGetData(conss[i]);
4966 assert(consdata != NULL);
4967
4969 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4970 {
4971 assert(expr != NULL);
4972 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4973 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4974 }
4975 SCIPfreeExpriter(&it);
4976 }
4977#endif
4978
4979 /* reformulate products of binary variables */
4980 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4981 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4982 {
4983 int tmpnaddconss = 0;
4984 int tmpnchgcoefs = 0;
4985
4986 /* call this function before simplification because expressions might not be simplified after reformulating
4987 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4988 */
4989 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4990
4991 /* update counters */
4992 if( naddconss != NULL )
4993 *naddconss += tmpnaddconss;
4994 if( nchgcoefs != NULL )
4995 *nchgcoefs += tmpnchgcoefs;
4996
4997 /* check whether at least one expression has changed */
4998 if( tmpnaddconss + tmpnchgcoefs > 0 )
4999 havechange = TRUE;
5000 }
5001
5002 for( i = 0; i < nconss; ++i )
5003 {
5004 consdata = SCIPconsGetData(conss[i]);
5005 assert(consdata != NULL);
5006
5007 /* call simplify for each expression */
5008 if( !consdata->issimplified && consdata->expr != NULL )
5009 {
5010 SCIP_EXPR* simplified;
5011 SCIP_Bool changed;
5012
5013 changed = FALSE;
5014 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
5015 consdata->issimplified = TRUE;
5016
5017 if( changed )
5018 havechange = TRUE;
5019
5020 /* 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").
5021 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
5022 */
5023 if( simplified != consdata->expr )
5024 {
5025 assert(changed);
5026
5027 /* release old expression */
5028 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5029
5030 /* store simplified expression */
5031 consdata->expr = simplified;
5032 }
5033 else
5034 {
5035 /* The simplify captures simplified in any case, also if nothing has changed.
5036 * Therefore, we have to release it here.
5037 */
5038 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5039 }
5040
5041 if( *infeasible )
5042 break;
5043
5044 /* scale constraint sides */
5045 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5046
5047 if( changed )
5048 havechange = TRUE;
5049
5050 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5051 if( SCIPisExprValue(scip, consdata->expr) )
5052 {
5053 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5054 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5055 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5056 {
5057 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5058 SCIPdebugPrintCons(scip, conss[i], NULL);
5059 *infeasible = TRUE;
5060 break;
5061 }
5062 else
5063 {
5064 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5065 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5066 if( ndelconss != NULL )
5067 ++*ndelconss;
5068 havechange = TRUE;
5069 }
5070 }
5071 }
5072 }
5073
5074 /* replace common subexpressions */
5075 if( havechange && !*infeasible )
5076 {
5077 SCIP_CONS** consssorted;
5078 SCIP_EXPR** rootexprs;
5079 SCIP_Bool replacedroot;
5080
5081 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5082 for( i = 0; i < nconss; ++i )
5083 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5084
5085 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5086
5087 /* update pointer to root expr in constraints, if any has changed
5088 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5089 */
5090 if( replacedroot )
5091 for( i = 0; i < nconss; ++i )
5092 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5093
5094 SCIPfreeBufferArray(scip, &rootexprs);
5095
5096 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5097 * been changed after simplification; now we completely recollect all variable expression and variable events
5098 */
5099
5100 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5101 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5102 */
5103 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5104 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5105
5106 for( i = nconss-1; i >= 0; --i )
5107 {
5108 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5109 if( SCIPconsIsDeleted(consssorted[i]) )
5110 continue;
5111
5112 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5113 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5114 }
5115 for( i = 0; i < nconss; ++i )
5116 {
5117 if( SCIPconsIsDeleted(consssorted[i]) )
5118 continue;
5119
5120 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5121 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5122 }
5123
5124 SCIPfreeBufferArray(scip, &consssorted);
5125
5126 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5127 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5128 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5129 */
5130 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5131 }
5132
5133 /* restore locks */
5134 for( i = 0; i < nconss; ++i )
5135 {
5136 if( SCIPconsIsDeleted(conss[i]) )
5137 continue;
5138
5139 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5140 }
5141
5142 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5143 * TODO can we skip this in presoltiming fast?
5144 */
5145 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5146 {
5147 /* reset one of the number of detections counter to count only current presolving round */
5148 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5149 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5150
5151 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5152 }
5153
5154 /* free allocated memory */
5155 SCIPfreeBufferArray(scip, &nlocksneg);
5156 SCIPfreeBufferArray(scip, &nlockspos);
5157
5158 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5159
5160 return SCIP_OKAY;
5161}
5162
5163/** merges constraints that have the same root expression */
5164static
5166 SCIP* scip, /**< SCIP data structure */
5167 SCIP_CONS** conss, /**< constraints to process */
5168 int nconss, /**< number of constraints */
5169 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5170 )
5171{
5172 SCIP_HASHMAP* expr2cons;
5173 SCIP_Bool* updatelocks;
5174 int* nlockspos;
5175 int* nlocksneg;
5176 int c;
5177
5178 assert(success != NULL);
5179
5180 *success = FALSE;
5181
5182 /* not enough constraints available */
5183 if( nconss <= 1 )
5184 return SCIP_OKAY;
5185
5186 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5187 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5188 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5189 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5190
5191 for( c = 0; c < nconss; ++c )
5192 {
5193 SCIP_CONSDATA* consdata;
5194
5195 /* ignore deleted constraints */
5196 if( SCIPconsIsDeleted(conss[c]) )
5197 continue;
5198
5199 consdata = SCIPconsGetData(conss[c]);
5200 assert(consdata != NULL);
5201
5202 /* add expression to the hash map if not seen so far */
5203 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5204 {
5205 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5206 }
5207 else
5208 {
5209 SCIP_CONSDATA* imgconsdata;
5210 int idx;
5211
5212 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5213 assert(idx >= 0 && idx < nconss);
5214
5215 imgconsdata = SCIPconsGetData(conss[idx]);
5216 assert(imgconsdata != NULL);
5217 assert(imgconsdata->expr == consdata->expr);
5218
5219 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5220 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5221
5222 /* check whether locks need to be updated */
5223 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5224 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5225 {
5226 nlockspos[idx] = imgconsdata->nlockspos;
5227 nlocksneg[idx] = imgconsdata->nlocksneg;
5228 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5229 updatelocks[idx] = TRUE;
5230 }
5231
5232 /* update constraint sides */
5233 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5234 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5235
5236 /* delete constraint */
5237 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5238 *success = TRUE;
5239 }
5240 }
5241
5242 /* restore locks of updated constraints */
5243 if( *success )
5244 {
5245 for( c = 0; c < nconss; ++c )
5246 {
5247 if( updatelocks[c] )
5248 {
5249 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5250 }
5251 }
5252 }
5253
5254 /* free memory */
5255 SCIPfreeBufferArray(scip, &nlocksneg);
5256 SCIPfreeBufferArray(scip, &nlockspos);
5257 SCIPfreeBufferArray(scip, &updatelocks);
5258 SCIPhashmapFree(&expr2cons);
5259
5260 return SCIP_OKAY;
5261}
5262
5263/** interval evaluation of variables as used in redundancy check
5264 *
5265 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5266 */
5267static
5268SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5269{ /*lint --e{715}*/
5270 SCIP_CONSHDLRDATA* conshdlrdata;
5271 SCIP_INTERVAL interval;
5272 SCIP_Real lb;
5273 SCIP_Real ub;
5274
5275 assert(scip != NULL);
5276 assert(var != NULL);
5277
5278 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5279 assert(conshdlrdata != NULL);
5280
5281 if( conshdlrdata->globalbounds )
5282 {
5283 lb = SCIPvarGetLbGlobal(var);
5284 ub = SCIPvarGetUbGlobal(var);
5285 }
5286 else
5287 {
5288 lb = SCIPvarGetLbLocal(var);
5289 ub = SCIPvarGetUbLocal(var);
5290 }
5291 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5292
5293 /* relax variable bounds, if there are bounds and variable is not fixed
5294 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5295 */
5296 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5297 {
5298 if( !SCIPisInfinity(scip, -lb) )
5299 lb -= SCIPfeastol(scip);
5300
5301 if( !SCIPisInfinity(scip, ub) )
5302 ub += SCIPfeastol(scip);
5303 }
5304
5305 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5308 assert(lb <= ub);
5309
5310 SCIPintervalSetBounds(&interval, lb, ub);
5311
5312 return interval;
5313}
5314
5315/** removes constraints that are always feasible or very simple
5316 *
5317 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5318 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5319 * might violate variable bounds by up to feastol, too.
5320 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5321 *
5322 * Also removes constraints of the form lhs &le; variable &le; rhs.
5323 *
5324 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5325 *
5326 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5327 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5328 * would appear as if the constraint is redundant.
5329 */
5330static
5332 SCIP* scip, /**< SCIP data structure */
5333 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5334 SCIP_CONS** conss, /**< constraints to propagate */
5335 int nconss, /**< total number of constraints */
5336 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5337 int* ndelconss, /**< buffer to add the number of deleted constraints */
5338 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5339 )
5340{
5341 SCIP_CONSHDLRDATA* conshdlrdata;
5342 SCIP_CONSDATA* consdata;
5343 SCIP_INTERVAL activity;
5344 SCIP_INTERVAL sides;
5345 int i;
5346
5347 assert(scip != NULL);
5348 assert(conshdlr != NULL);
5349 assert(conss != NULL);
5350 assert(nconss >= 0);
5351 assert(cutoff != NULL);
5352 assert(ndelconss != NULL);
5353 assert(nchgbds != NULL);
5354
5355 /* no constraints to check */
5356 if( nconss == 0 )
5357 return SCIP_OKAY;
5358
5359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5360 assert(conshdlrdata != NULL);
5361
5362 /* increase curboundstag and set lastvaractivitymethodchange
5363 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5364 * for the redundancy check differently than for domain propagation
5365 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5366 */
5367 ++conshdlrdata->curboundstag;
5368 assert(conshdlrdata->curboundstag > 0);
5369 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5370 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5371 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5372
5373 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5374
5375 *cutoff = FALSE;
5376 for( i = 0; i < nconss; ++i )
5377 {
5378 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5379 continue;
5380
5381 consdata = SCIPconsGetData(conss[i]);
5382 assert(consdata != NULL);
5383
5384 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5385 if( SCIPisExprValue(scip, consdata->expr) )
5386 {
5387 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5388
5389 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5390 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5391 {
5392 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5393 *cutoff = TRUE;
5394
5395 goto TERMINATE;
5396 }
5397
5398 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5399
5400 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5401 ++*ndelconss;
5402
5403 continue;
5404 }
5405
5406 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5407 if( SCIPisExprVar(scip, consdata->expr) )
5408 {
5409 SCIP_VAR* var;
5410 SCIP_Bool tightened;
5411
5412 var = SCIPgetVarExprVar(consdata->expr);
5413 assert(var != NULL);
5414
5415 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);
5416
5417 /* ensure that variable bounds are within constraint sides */
5418 if( !SCIPisInfinity(scip, -consdata->lhs) )
5419 {
5420 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5421
5422 if( tightened )
5423 ++*nchgbds;
5424
5425 if( *cutoff )
5426 goto TERMINATE;
5427 }
5428
5429 if( !SCIPisInfinity(scip, consdata->rhs) )
5430 {
5431 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5432
5433 if( tightened )
5434 ++*nchgbds;
5435
5436 if( *cutoff )
5437 goto TERMINATE;
5438 }
5439
5440 /* delete the (now) redundant constraint locally */
5441 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5442 ++*ndelconss;
5443
5444 continue;
5445 }
5446
5447 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5448 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5449 * variable bounds by up to feastol
5450 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5451 */
5452 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5453 SCIPdebugPrintCons(scip, conss[i], NULL);
5454
5455 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5457
5458 /* it is unlikely that we detect infeasibility by doing forward propagation */
5459 if( *cutoff )
5460 {
5461 SCIPdebugMsg(scip, " -> cutoff\n");
5462 goto TERMINATE;
5463 }
5464
5465 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5466 activity = SCIPexprGetActivity(consdata->expr);
5467
5468 /* relax sides by feastol
5469 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5470 */
5471 SCIPintervalSetBounds(&sides,
5472 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5473 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5474
5475 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5476 {
5477 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5478
5479 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5480 ++*ndelconss;
5481
5482 continue;
5483 }
5484
5485 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5486 }
5487
5488TERMINATE:
5489 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5490 ++conshdlrdata->curboundstag;
5491 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5492 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5493 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5494
5495 return SCIP_OKAY;
5496}
5497
5498/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5499static
5501 SCIP* scip, /**< SCIP data structure */
5502 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5503 SCIP_CONS* cons, /**< source constraint to try to convert */
5504 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5505 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5506 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5507 )
5508{
5509 SCIP_CONSHDLRDATA* conshdlrdata;
5510 SCIP_CONSDATA* consdata;
5511 SCIP_CONS** upgdconss;
5512 int upgdconsssize;
5513 int nupgdconss_;
5514 int i;
5515
5516 assert(scip != NULL);
5517 assert(conshdlr != NULL);
5518 assert(cons != NULL);
5520 assert(upgraded != NULL);
5521 assert(nupgdconss != NULL);
5522 assert(naddconss != NULL);
5523
5524 *upgraded = FALSE;
5525
5526 nupgdconss_ = 0;
5527
5528 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5529 assert(conshdlrdata != NULL);
5530
5531 /* if there are no upgrade methods, we can stop */
5532 if( conshdlrdata->nconsupgrades == 0 )
5533 return SCIP_OKAY;
5534
5535 upgdconsssize = 2;
5536 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5537
5538 /* call the upgrading methods */
5539 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5541
5542 consdata = SCIPconsGetData(cons);
5543 assert(consdata != NULL);
5544
5545 /* try all upgrading methods in priority order in case the upgrading step is enabled */
5546 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5547 {
5548 if( !conshdlrdata->consupgrades[i]->active )
5549 continue;
5550
5551 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5552
5553 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5554
5555 while( nupgdconss_ < 0 )
5556 {
5557 /* upgrade function requires more memory: resize upgdconss and call again */
5558 assert(-nupgdconss_ > upgdconsssize);
5559 upgdconsssize = -nupgdconss_;
5560 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5561
5562 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5563
5564 assert(nupgdconss_ != 0);
5565 }
5566
5567 if( nupgdconss_ > 0 )
5568 {
5569 /* got upgrade */
5570 int j;
5571
5572 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5573
5574 /* add the upgraded constraints to the problem and forget them */
5575 for( j = 0; j < nupgdconss_; ++j )
5576 {
5577 SCIPdebugMsgPrint(scip, "\t");
5578 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5579
5580 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5581 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5582 }
5583
5584 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5585 *nupgdconss += 1;
5586 *naddconss += nupgdconss_ - 1;
5587 *upgraded = TRUE;
5588
5589 /* delete upgraded constraint */
5590 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5591 SCIP_CALL( SCIPdelCons(scip, cons) );
5592
5593 break;
5594 }
5595 }
5596
5597 SCIPfreeBufferArray(scip, &upgdconss);
5598
5599 return SCIP_OKAY;
5600}
5601
5602/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5603 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5604 * variable bounds, and is not binary
5605 */
5606static
5608 SCIP* scip, /**< SCIP data structure */
5609 SCIP_EXPR* expr /**< variable expression */
5610 )
5611{
5612 SCIP_VAR* var;
5613 SCIP_EXPR_OWNERDATA* ownerdata;
5614
5615 assert(SCIPisExprVar(scip, expr));
5616
5617 var = SCIPgetVarExprVar(expr);
5618 assert(var != NULL);
5619
5620 ownerdata = SCIPexprGetOwnerData(expr);
5621 assert(ownerdata != NULL);
5622
5623 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5624 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5625 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5629}
5630
5631/** removes all variable expressions that are contained in a given expression from a hash map */
5632static
5634 SCIP* scip, /**< SCIP data structure */
5635 SCIP_EXPR* expr, /**< expression */
5636 SCIP_EXPRITER* it, /**< expression iterator */
5637 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5638 )
5639{
5640 SCIP_EXPR* e;
5641
5642 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5643 {
5644 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5645 {
5646 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5647 }
5648 }
5649
5650 return SCIP_OKAY;
5651}
5652
5653/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5654 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5655 *
5656 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5657 * Otherwise, a bound disjunction constraint is added.
5658 *
5659 * @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?)
5660 */
5661static
5663 SCIP* scip, /**< SCIP data structure */
5664 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5665 SCIP_CONS* cons, /**< nonlinear constraint */
5666 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5667 int* naddconss, /**< pointer to store the total number of added constraints */
5668 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5669 )
5670{
5671 SCIP_CONSHDLRDATA* conshdlrdata;
5672 SCIP_CONSDATA* consdata;
5673 SCIP_EXPR** singlelocked;
5674 SCIP_HASHMAP* exprcands;
5675 SCIP_Bool hasbounddisj;
5676 SCIP_Bool haslhs;
5677 SCIP_Bool hasrhs;
5678 int nsinglelocked = 0;
5679 int i;
5680
5681 assert(conshdlr != NULL);
5682 assert(cons != NULL);
5683 assert(nchgvartypes != NULL);
5684 assert(naddconss != NULL);
5685 assert(infeasible != NULL);
5686
5687 *nchgvartypes = 0;
5688 *naddconss = 0;
5689 *infeasible = FALSE;
5690
5691 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5692 assert(conshdlrdata != NULL);
5693 consdata = SCIPconsGetData(cons);
5694 assert(consdata != NULL);
5695
5696 /* only consider constraints with one finite side */
5697 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5698 return SCIP_OKAY;
5699
5700 /* only consider sum expressions */
5701 if( !SCIPisExprSum(scip, consdata->expr) )
5702 return SCIP_OKAY;
5703
5704 /* remember which side is finite */
5705 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5706 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5707
5708 /* allocate memory */
5709 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5710 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5711
5712 /* check all variable expressions for single locked variables */
5713 for( i = 0; i < consdata->nvarexprs; ++i )
5714 {
5715 assert(consdata->varexprs[i] != NULL);
5716
5717 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5718 {
5719 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5720 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5721 }
5722 }
5723 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5724
5725 if( nsinglelocked > 0 )
5726 {
5727 SCIP_EXPR** children;
5728 SCIP_EXPRITER* it;
5729 int nchildren;
5730
5731 children = SCIPexprGetChildren(consdata->expr);
5732 nchildren = SCIPexprGetNChildren(consdata->expr);
5733
5734 /* create iterator */
5738
5739 for( i = 0; i < nchildren; ++i )
5740 {
5741 SCIP_EXPR* child;
5742 SCIP_Real coef;
5743
5744 child = children[i];
5745 assert(child != NULL);
5746 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5747
5748 /* ignore linear terms */
5749 if( SCIPisExprVar(scip, child) )
5750 continue;
5751
5752 /* consider products coef * prod_j f_j(x)
5753 * - if f_j(x) is a single variable, ignore it
5754 * - if f_j(x) = x^(2k), then keep it if product is concave when fixing all other factor;
5755 * 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
5756 * - remove all other variable expressions from exprcand
5757 */
5758 if( SCIPisExprProduct(scip, child) )
5759 {
5760 int j;
5761 SCIP_INTERVAL productactivity;
5762 SCIP_Bool keepevenpower;
5763
5764 /* activity has been ensured to be uptodate (or at least still valid) by
5765 * call to SCIPregisterExprUsageNonlinear() in detectNlhdlrs() in canonicalize
5766 */
5767 productactivity = SCIPexprGetActivity(child);
5768
5769 /* check whether variables in even-powered factor terms can be restricted to bounds (as in SCIPisExprPower() below) */
5770 keepevenpower = (haslhs && productactivity.inf >= 0.0) || (hasrhs && productactivity.sup <= 0.0);
5771
5772 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5773 {
5774 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5775 assert(grandchild != NULL);
5776
5777 /* if grandchild is x^(2k), then do not remove x from exprcands */
5778 if( keepevenpower && SCIPisExprPower(scip, grandchild) && SCIPisExprVar(scip, SCIPexprGetChildren(grandchild)[0]) )
5779 {
5780 SCIP_Real exponent = SCIPgetExponentExprPow(grandchild);
5781
5782 if( exponent > 1.0 && fmod(exponent, 2.0) == 0.0 )
5783 continue;
5784 }
5785
5786 if( !SCIPisExprVar(scip, grandchild) )
5787 {
5788 /* mark all variable expressions that are contained in the expression */
5789 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5790 }
5791 }
5792 }
5793 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5794 * for an integer k >= 1
5795 */
5796 else if( SCIPisExprPower(scip, child) )
5797 {
5798 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5799 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5801
5802 /* check for even integral exponent */
5803 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5804
5805 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5806 {
5807 /* mark all variable expressions that are contained in the expression */
5808 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5809 }
5810 }
5811 /* all other cases cannot be handled */
5812 else
5813 {
5814 /* mark all variable expressions that are contained in the expression */
5815 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5816 }
5817 }
5818
5819 /* free expression iterator */
5820 SCIPfreeExpriter(&it);
5821 }
5822
5823 /* check whether the bound disjunction constraint handler is available */
5824 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5825
5826 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5827 for( i = 0; i < nsinglelocked; ++i )
5828 {
5829 /* only consider expressions that are still contained in the exprcands map */
5830 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5831 {
5832 SCIP_CONS* newcons;
5833 SCIP_VAR* vars[2];
5834 SCIP_BOUNDTYPE boundtypes[2];
5835 SCIP_Real bounds[2];
5836 char name[SCIP_MAXSTRLEN];
5837 SCIP_VAR* var;
5838
5839 var = SCIPgetVarExprVar(singlelocked[i]);
5840 assert(var != NULL);
5841 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5843
5844 /* try to change the variable type to binary */
5845 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5846 {
5849 ++(*nchgvartypes);
5850
5851 if( *infeasible )
5852 {
5853 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5854 break;
5855 }
5856 }
5857 /* add bound disjunction constraint if bounds of the variable are finite */
5858 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5859 {
5860 vars[0] = var;
5861 vars[1] = var;
5862 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5863 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5864 bounds[0] = SCIPvarGetUbGlobal(var);
5865 bounds[1] = SCIPvarGetLbGlobal(var);
5866
5867 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5868
5869 /* create, add, and release bound disjunction constraint */
5870 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5871 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5873 SCIP_CALL( SCIPaddCons(scip, newcons) );
5874 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5875 ++(*naddconss);
5876 }
5877 }
5878 }
5879
5880 /* free memory */
5881 SCIPfreeBufferArray(scip, &singlelocked);
5882 SCIPhashmapFree(&exprcands);
5883
5884 return SCIP_OKAY;
5885}
5886
5887/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5888static
5890 SCIP* scip, /**< SCIP data structure */
5891 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5892 SCIP_CONS** conss, /**< nonlinear constraints */
5893 int nconss, /**< total number of nonlinear constraints */
5894 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5895 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5896 )
5897{
5898 int c;
5899
5900 assert(scip != NULL);
5901 assert(conshdlr != NULL);
5902 assert(conss != NULL || nconss == 0);
5903 assert(nchgvartypes != NULL);
5904 assert(infeasible != NULL);
5905
5906 *infeasible = FALSE;
5907
5908 /* nothing can be done on purley continuous problem */
5910 return SCIP_OKAY;
5911
5912 /* no continuous var can be made implicit-integer if there are no continuous variables */
5913 if( SCIPgetNContVars(scip) == 0 )
5914 return SCIP_OKAY;
5915
5916 for( c = 0; c < nconss; ++c )
5917 {
5918 SCIP_CONSDATA* consdata;
5919 SCIP_EXPR** children;
5920 int nchildren;
5921 SCIP_Real* coefs;
5922 SCIP_EXPR* cand = NULL;
5923 SCIP_Real candcoef = 0.0;
5924 int i;
5925 SCIP_IMPLINTTYPE impltype;
5926
5927 assert(conss != NULL && conss[c] != NULL);
5928
5929 consdata = SCIPconsGetData(conss[c]);
5930 assert(consdata != NULL);
5931
5932 /* the constraint must be an equality constraint */
5933 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5934 continue;
5935
5936 /* the root expression needs to be a sum expression */
5937 if( !SCIPisExprSum(scip, consdata->expr) )
5938 continue;
5939
5940 children = SCIPexprGetChildren(consdata->expr);
5941 nchildren = SCIPexprGetNChildren(consdata->expr);
5942
5943 /* the sum expression must have at least two children
5944 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5945 */
5946 if( nchildren <= 1 )
5947 continue;
5948
5949 coefs = SCIPgetCoefsExprSum(consdata->expr);
5950
5951 /* find first continuous variable and get value of its coefficient */
5952 for( i = 0; i < nchildren; ++i )
5953 {
5954 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5955 continue;
5956
5957 candcoef = coefs[i];
5958 assert(candcoef != 0.0);
5959
5960 /* lhs/rhs - constant divided by candcoef must be integral
5961 * if not, break with cand == NULL, so give up
5962 */
5963 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5964 cand = children[i];
5965
5966 break;
5967 }
5968
5969 /* no suitable continuous variable found */
5970 if( cand == NULL )
5971 continue;
5972
5973 impltype = SCIP_IMPLINTTYPE_STRONG;
5974
5975 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5976 for( i = 0; i < nchildren; ++i )
5977 {
5978 if( children[i] == cand )
5979 continue;
5980
5981 impltype = MIN(impltype, SCIPexprGetIntegrality(children[i]));
5982 /* child i must be integral */
5983 if( impltype == SCIP_IMPLINTTYPE_NONE )
5984 {
5985 cand = NULL;
5986 break;
5987 }
5988
5989 /* coefficient of child i must be integral if diving by candcoef */
5990 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5991 {
5992 cand = NULL;
5993 break;
5994 }
5995 }
5996
5997 if( cand == NULL )
5998 continue;
5999
6000 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
6002
6003 /* change variable type */
6004 assert(impltype != SCIP_IMPLINTTYPE_NONE);
6005
6006 SCIP_CALL( SCIPchgVarImplType(scip, SCIPgetVarExprVar(cand), impltype, infeasible) );
6007 ++(*nchgvartypes);
6008
6009 if( *infeasible )
6010 return SCIP_OKAY;
6011
6012 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
6013 SCIPexprSetIntegrality(cand, impltype);
6014 }
6015
6016 return SCIP_OKAY;
6017}
6018
6019/** creates auxiliary variable for a given expression
6020 *
6021 * @note for a variable expression it does nothing
6022 * @note this function can only be called in stage SCIP_STAGE_SOLVING
6023 */
6024static
6026 SCIP* scip, /**< SCIP data structure */
6027 SCIP_EXPR* expr /**< expression */
6028 )
6029{
6030 SCIP_EXPR_OWNERDATA* ownerdata;
6031 SCIP_CONSHDLRDATA* conshdlrdata;
6032 SCIP_IMPLINTTYPE impltype;
6033 SCIP_INTERVAL activity;
6034 char name[SCIP_MAXSTRLEN];
6035
6036 assert(scip != NULL);
6037 assert(expr != NULL);
6038
6039 ownerdata = SCIPexprGetOwnerData(expr);
6040 assert(ownerdata != NULL);
6041 assert(ownerdata->nauxvaruses > 0);
6042
6043 /* if we already have auxvar, then do nothing */
6044 if( ownerdata->auxvar != NULL )
6045 return SCIP_OKAY;
6046
6047 /* if expression is a variable-expression, then do nothing */
6048 if( SCIPisExprVar(scip, expr) )
6049 return SCIP_OKAY;
6050
6052 {
6053 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6054 return SCIP_INVALIDCALL;
6055 }
6056
6057 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6058 assert(conshdlrdata != NULL);
6059 assert(conshdlrdata->auxvarid >= 0);
6060
6061 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6062 * but it usually indicates a missing simplify
6063 * if we find situations where we need to have an auxvar for a constant, then remove this assert
6064 */
6065 assert(!SCIPisExprValue(scip, expr));
6066
6067 /* create and capture auxiliary variable */
6068 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6069 ++conshdlrdata->auxvarid;
6070
6071 /* type of auxiliary variable depends on integrality information of the expression */
6072 impltype = SCIPexprGetIntegrality(expr);
6073
6074 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6075 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6076 {
6077 activity = SCIPexprGetActivity(expr);
6078 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6079 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6080 * and abort in debug mode only
6081 */
6083 {
6084 SCIPABORT();
6086 }
6087 }
6088 else
6090
6091 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6092 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6093 */
6094 if( SCIPgetDepth(scip) == 0 )
6095 {
6096 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name,
6097 MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0,
6098 SCIP_VARTYPE_CONTINUOUS, impltype,
6099 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6100 }
6101 else
6102 {
6103 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
6104 SCIP_VARTYPE_CONTINUOUS, impltype,
6105 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6106 }
6107
6108 /* mark the auxiliary variable to be added for the relaxation only
6109 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6110 * or to copy the variable to a subscip
6111 */
6112 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6113
6114 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6115
6116 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6117
6118 /* add variable locks in both directions
6119 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6120 * but then we need to also update the auxvars locks when the expr locks change
6121 */
6122 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6123
6124#ifdef WITH_DEBUG_SOLUTION
6125 if( SCIPdebugIsMainscip(scip) )
6126 {
6127 /* store debug solution value of auxiliary variable
6128 * assumes that expression has been evaluated in debug solution before
6129 */
6130 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6131 }
6132#endif
6133
6134 if( SCIPgetDepth(scip) > 0 )
6135 {
6136 /* initialize local bounds to (locally valid) activity */
6138 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6139 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6140 }
6141
6142 return SCIP_OKAY;
6143}
6144
6145/** initializes separation for constraint
6146 *
6147 * - ensures that activities are up to date in all expressions
6148 * - creates auxiliary variables where required
6149 * - calls propExprDomains() to possibly tighten auxvar bounds
6150 * - calls separation initialization callback of nlhdlrs
6151 */
6152static
6154 SCIP* scip, /**< SCIP data structure */
6155 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6156 SCIP_CONS** conss, /**< constraints */
6157 int nconss, /**< number of constraints */
6158 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6159 )
6160{
6161 SCIP_CONSDATA* consdata;
6162 SCIP_CONSHDLRDATA* conshdlrdata;
6163 SCIP_EXPRITER* it;
6164 SCIP_EXPR* expr;
6166 SCIP_VAR* auxvar;
6167 int nreductions = 0;
6168 int c, e;
6169
6170 assert(scip != NULL);
6171 assert(conshdlr != NULL);
6172 assert(conss != NULL || nconss == 0);
6173 assert(nconss >= 0);
6174 assert(infeasible != NULL);
6175
6176 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6177 assert(conshdlrdata != NULL);
6178
6179 /* start with new propbounds (just to be sure, should not be needed) */
6180 ++conshdlrdata->curpropboundstag;
6181
6184
6185 /* first ensure activities are up to date and create auxvars */
6186 *infeasible = FALSE;
6187 for( c = 0; c < nconss; ++c )
6188 {
6189 assert(conss != NULL);
6190 assert(conss[c] != NULL);
6191
6192 consdata = SCIPconsGetData(conss[c]);
6193 assert(consdata != NULL);
6194 assert(consdata->expr != NULL);
6195
6196#ifdef WITH_DEBUG_SOLUTION
6197 if( SCIPdebugIsMainscip(scip) )
6198 {
6199 SCIP_SOL* debugsol;
6200
6201 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6202
6203 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6204 {
6205 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6206 * in createAuxVar()
6207 */
6208 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6209 }
6210 }
6211#endif
6212
6213 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6214 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6215
6216 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6217 {
6218 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6219 {
6220 SCIP_CALL( createAuxVar(scip, expr) );
6221 }
6222 }
6223
6224 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6225 if( auxvar != NULL )
6226 {
6227 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6228 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6229 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6230 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6231 if( *infeasible )
6232 {
6233 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6234 break;
6235 }
6236
6237 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6238 if( *infeasible )
6239 {
6240 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6241 break;
6242 }
6243 }
6244 }
6245
6246 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6247 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6248 * (e.g., log(x*y), which becomes log(w), w=x*y
6249 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6250 */
6251 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6252 if( result == SCIP_CUTOFF )
6253 *infeasible = TRUE;
6254
6255 /* now call initsepa of nlhdlrs
6256 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6257 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6258 */
6260 for( c = 0; c < nconss && !*infeasible; ++c )
6261 {
6262 assert(conss != NULL);
6263 assert(conss[c] != NULL);
6264
6265 consdata = SCIPconsGetData(conss[c]);
6266 assert(consdata != NULL);
6267 assert(consdata->expr != NULL);
6268
6269 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6270 {
6271 SCIP_EXPR_OWNERDATA* ownerdata;
6272
6273 ownerdata = SCIPexprGetOwnerData(expr);
6274 assert(ownerdata != NULL);
6275
6276 if( ownerdata->nauxvaruses == 0 )
6277 continue;
6278
6279 for( e = 0; e < ownerdata->nenfos; ++e )
6280 {
6281 SCIP_NLHDLR* nlhdlr;
6282 SCIP_Bool underestimate;
6283 SCIP_Bool overestimate;
6284 assert(ownerdata->enfos[e] != NULL);
6285
6286 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6287 * which participated in a previous initSepa() call
6288 */
6289 if( ownerdata->enfos[e]->issepainit )
6290 continue;
6291
6292 /* only call initsepa if it will actually separate */
6293 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6294 continue;
6295
6296 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6297 assert(nlhdlr != NULL);
6298
6299 /* only init sepa if there is an initsepa callback */
6300 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6301 continue;
6302
6303 /* check whether expression needs to be under- or overestimated */
6304 overestimate = ownerdata->nlocksneg > 0;
6305 underestimate = ownerdata->nlockspos > 0;
6306 assert(underestimate || overestimate);
6307
6308 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6309
6310 /* call the separation initialization callback of the nonlinear handler */
6311 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6312 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6313 ownerdata->enfos[e]->issepainit = TRUE;
6314
6315 if( *infeasible )
6316 {
6317 /* stop everything if we detected infeasibility */
6318 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6319 break;
6320 }
6321 }
6322 }
6323 }
6324
6325 SCIPfreeExpriter(&it);
6326
6327 return SCIP_OKAY;
6328}
6329
6330/** returns whether we are ok to branch on auxiliary variables
6331 *
6332 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6333 */
6334static
6336 SCIP* scip, /**< SCIP data structure */
6337 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6338 )
6339{
6340 SCIP_CONSHDLRDATA* conshdlrdata;
6341
6342 assert(conshdlr != NULL);
6343
6344 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6345 assert(conshdlrdata != NULL);
6346
6347 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6348}
6349
6350/** gets weight of variable when splitting violation score onto several variables in an expression */
6351static
6353 SCIP* scip, /**< SCIP data structure */
6354 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6355 SCIP_VAR* var, /**< variable */
6356 SCIP_SOL* sol /**< current solution */
6357 )
6358{
6359 SCIP_CONSHDLRDATA* conshdlrdata;
6360
6361 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6362 assert(conshdlrdata != NULL);
6363
6364 switch( conshdlrdata->branchviolsplit )
6365 {
6366 case 'u' : /* uniform: everyone gets the same score */
6367 return 1.0;
6368
6369 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6370 {
6371 SCIP_Real weight;
6373 return MAX(0.05, weight);
6374 }
6375
6376 case 'd' : /* domain width */
6378
6379 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6380 {
6382 assert(width > 0.0);
6383 if( width > 10.0 )
6384 return 10.0*log10(width);
6385 if( width < 0.1 )
6386 return 0.1/(-log10(width));
6387 return width;
6388 }
6389
6390 default :
6391 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6392 SCIPABORT();
6393 return SCIP_INVALID;
6394 }
6395}
6396
6397/** adds violation-branching score to a set of expressions, thereby distributing the score
6398 *
6399 * Each expression must either be a variable expression or have an aux-variable.
6400 *
6401 * If unbounded variables are present, each unbounded var gets an even score.
6402 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6403 */
6404static
6406 SCIP* scip, /**< SCIP data structure */
6407 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6408 int nexprs, /**< number of expressions */
6409 SCIP_Real violscore, /**< violation-branching score to add to expression */
6410 SCIP_SOL* sol, /**< current solution */
6411 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6412 )
6413{
6414 SCIP_CONSHDLR* conshdlr;
6415 SCIP_VAR* var;
6416 SCIP_Real weight;
6417 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6418 int nunbounded = 0; /* number of candidates with unbounded domain */
6419 int i;
6420
6421 assert(exprs != NULL);
6422 assert(nexprs >= 0);
6423 assert(success != NULL);
6424
6425 if( nexprs == 1 )
6426 {
6427 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6428 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6430 *success = TRUE;
6431 return;
6432 }
6433
6434 if( nexprs == 0 )
6435 {
6436 *success = FALSE;
6437 return;
6438 }
6439
6440 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6441
6442 for( i = 0; i < nexprs; ++i )
6443 {
6445 assert(var != NULL);
6446
6448 ++nunbounded;
6450 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6451 }
6452
6453 *success = FALSE;
6454 for( i = 0; i < nexprs; ++i )
6455 {
6457 assert(var != NULL);
6458
6459 if( nunbounded > 0 )
6460 {
6462 {
6463 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6464 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6465 100.0/nunbounded, violscore,
6467 *success = TRUE;
6468 }
6469 }
6471 {
6472 assert(weightsum > 0.0);
6473
6474 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6475 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6476 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6477 100*weight / weightsum, violscore,
6479 *success = TRUE;
6480 }
6481 else
6482 {
6483 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6485 }
6486 }
6487}
6488
6489/** adds violation-branching score to children of expression for given auxiliary variables
6490 *
6491 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6492 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6493 *
6494 * @note This method may modify the given auxvars array by means of sorting.
6495 */
6496static
6498 SCIP* scip, /**< SCIP data structure */
6499 SCIP_EXPR* expr, /**< expression where to start searching */
6500 SCIP_Real violscore, /**< violation score to add to expression */
6501 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6502 int nauxvars, /**< number of auxiliary variables */
6503 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6504 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6505 )
6506{
6507 SCIP_EXPRITER* it;
6508 SCIP_VAR* auxvar;
6509 SCIP_EXPR** exprs;
6510 int nexprs;
6511 int pos;
6512
6513 assert(scip != NULL);
6514 assert(expr != NULL);
6515 assert(auxvars != NULL);
6516 assert(success != NULL);
6517
6518 /* sort variables to make lookup below faster */
6519 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6520
6523
6524 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6525 nexprs = 0;
6526
6527 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6528 {
6529 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6530 if( auxvar == NULL )
6531 continue;
6532
6533 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6534 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6535 {
6536 assert(auxvars[pos] == auxvar);
6537
6538 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6539 exprs[nexprs++] = expr;
6540
6541 if( nexprs == nauxvars )
6542 break;
6543 }
6544 }
6545
6546 SCIPfreeExpriter(&it);
6547
6548 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6549
6550 SCIPfreeBufferArray(scip, &exprs);
6551
6552 return SCIP_OKAY;
6553}
6554
6555/** registers all unfixed variables in violated constraints as branching candidates */
6556static
6558 SCIP* scip, /**< SCIP data structure */
6559 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6560 SCIP_CONS** conss, /**< constraints */
6561 int nconss, /**< number of constraints */
6562 int* nnotify /**< counter for number of notifications performed */
6563 )
6564{
6565 SCIP_CONSDATA* consdata;
6566 SCIP_VAR* var;
6567 int c;
6568 int i;
6569
6570 assert(conshdlr != NULL);
6571 assert(conss != NULL || nconss == 0);
6572 assert(nnotify != NULL);
6573
6574 *nnotify = 0;
6575
6576 for( c = 0; c < nconss; ++c )
6577 {
6578 assert(conss != NULL && conss[c] != NULL);
6579
6580 consdata = SCIPconsGetData(conss[c]);
6581 assert(consdata != NULL);
6582
6583 /* consider only violated constraints */
6584 if( !isConsViolated(scip, conss[c]) )
6585 continue;
6586
6587 /* register all variables that have not been fixed yet */
6588 assert(consdata->varexprs != NULL);
6589 for( i = 0; i < consdata->nvarexprs; ++i )
6590 {
6591 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6592 assert(var != NULL);
6593
6595 {
6597 ++(*nnotify);
6598 }
6599 }
6600 }
6601
6602 return SCIP_OKAY;
6603}
6604
6605/** registers all variables in violated constraints with branching scores as external branching candidates */
6606static
6608 SCIP* scip, /**< SCIP data structure */
6609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6610 SCIP_CONS** conss, /**< constraints */
6611 int nconss, /**< number of constraints */
6612 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6613 )
6614{
6615 SCIP_CONSDATA* consdata;
6616 SCIP_EXPRITER* it = NULL;
6617 int c;
6618
6619 assert(conshdlr != NULL);
6620 assert(success != NULL);
6621
6622 *success = FALSE;
6623
6624 if( branchAuxNonlinear(scip, conshdlr) )
6625 {
6628 }
6629
6630 /* register external branching candidates */
6631 for( c = 0; c < nconss; ++c )
6632 {
6633 assert(conss != NULL && conss[c] != NULL);
6634
6635 consdata = SCIPconsGetData(conss[c]);
6636 assert(consdata != NULL);
6637 assert(consdata->varexprs != NULL);
6638
6639 /* consider only violated constraints */
6640 if( !isConsViolated(scip, conss[c]) )
6641 continue;
6642
6643 if( !branchAuxNonlinear(scip, conshdlr) )
6644 {
6645 int i;
6646
6647 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6648 * only, so we can loop over variable expressions
6649 */
6650 for( i = 0; i < consdata->nvarexprs; ++i )
6651 {
6652 SCIP_Real violscore;
6653 SCIP_Real lb;
6654 SCIP_Real ub;
6655 SCIP_VAR* var;
6656
6657 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6658
6659 /* skip variable expressions that do not have a violation score */
6660 if( violscore == 0.0 )
6661 continue;
6662
6663 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6664 assert(var != NULL);
6665
6666 lb = SCIPvarGetLbLocal(var);
6667 ub = SCIPvarGetUbLocal(var);
6668
6669 /* consider variable for branching if it has not been fixed yet */
6670 if( !SCIPisEQ(scip, lb, ub) )
6671 {
6672 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6674 *success = TRUE;
6675 }
6676 else
6677 {
6678 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6679 }
6680
6681 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6682 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6683 */
6684 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6685 }
6686 }
6687 else
6688 {
6689 SCIP_EXPR* expr;
6690 SCIP_VAR* var;
6691 SCIP_Real lb;
6692 SCIP_Real ub;
6693 SCIP_Real violscore;
6694
6695 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6696 {
6697 violscore = SCIPgetExprViolScoreNonlinear(expr);
6698 if( violscore == 0.0 )
6699 continue;
6700
6701 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6702 * variable, so this expression should either be an original variable or have an auxiliary variable
6703 */
6705 assert(var != NULL);
6706
6707 lb = SCIPvarGetLbLocal(var);
6708 ub = SCIPvarGetUbLocal(var);
6709
6710 /* consider variable for branching if it has not been fixed yet */
6711 if( !SCIPisEQ(scip, lb, ub) )
6712 {
6713 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6714
6716 *success = TRUE;
6717 }
6718 else
6719 {
6720 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6721 }
6722 }
6723 }
6724 }
6725
6726 if( it != NULL )
6727 SCIPfreeExpriter(&it);
6728
6729 return SCIP_OKAY;
6730}
6731
6732/** collect branching candidates from violated constraints
6733 *
6734 * Fills array with expressions that serve as branching candidates.
6735 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6736 * branching candidate.
6737 *
6738 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6739 * through variable-expressions only.
6740 */
6741static
6743 SCIP* scip, /**< SCIP data structure */
6744 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6745 SCIP_CONS** conss, /**< constraints to process */
6746 int nconss, /**< number of constraints */
6747 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6748 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6749 SCIP_Longint soltag, /**< tag of solution */
6750 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6751 int* ncands /**< number of candidates found */
6752 )
6753{
6754 SCIP_CONSHDLRDATA* conshdlrdata;
6755 SCIP_CONSDATA* consdata;
6756 SCIP_EXPRITER* it = NULL;
6757 int c;
6758 int attempt;
6759 SCIP_VAR* var;
6760
6761 assert(scip != NULL);
6762 assert(conshdlr != NULL);
6763 assert(cands != NULL);
6764 assert(ncands != NULL);
6765
6766 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6767 assert(conshdlrdata != NULL);
6768
6769 if( branchAuxNonlinear(scip, conshdlr) )
6770 {
6773 }
6774
6775 *ncands = 0;
6776 for( attempt = 0; attempt < 2; ++attempt )
6777 {
6778 /* collect branching candidates from violated constraints
6779 * in the first attempt, consider only constraints with large violation
6780 * in the second attempt, consider all remaining violated constraints
6781 */
6782 for( c = 0; c < nconss; ++c )
6783 {
6784 SCIP_Real consviol;
6785
6786 assert(conss != NULL && conss[c] != NULL);
6787
6788 /* consider only violated constraints */
6789 if( !isConsViolated(scip, conss[c]) )
6790 continue;
6791
6792 consdata = SCIPconsGetData(conss[c]);
6793 assert(consdata != NULL);
6794 assert(consdata->varexprs != NULL);
6795
6796 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6797
6798 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6799 continue;
6800 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6801 continue;
6802
6803 if( !branchAuxNonlinear(scip, conshdlr) )
6804 {
6805 int i;
6806
6807 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6808 * only, so we can loop over variable expressions
6809 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6810 * variable, therefore we invalidate the score of a variable after processing it.
6811 */
6812 for( i = 0; i < consdata->nvarexprs; ++i )
6813 {
6814 SCIP_Real lb;
6815 SCIP_Real ub;
6816
6817 /* skip variable expressions that do not have a valid violation score */
6818 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6819 continue;
6820
6821 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6822 assert(var != NULL);
6823
6824 lb = SCIPvarGetLbLocal(var);
6825 ub = SCIPvarGetUbLocal(var);
6826
6827 /* skip already fixed variable */
6828 if( SCIPisEQ(scip, lb, ub) )
6829 {
6830 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6831 continue;
6832 }
6833
6834 assert(*ncands + 1 < SCIPgetNVars(scip));
6835 cands[*ncands].expr = consdata->varexprs[i];
6836 cands[*ncands].var = var;
6837 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6838 cands[*ncands].fractionality = 0.0;
6839 ++(*ncands);
6840
6841 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6842 * several times as external branching candidate */
6843 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6844 }
6845 }
6846 else
6847 {
6848 SCIP_EXPR* expr;
6849 SCIP_Real lb;
6850 SCIP_Real ub;
6851
6852 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6853 {
6854 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6855 continue;
6856
6857 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6858 * variables, so this expression should either be an original variable or have an auxiliary variable
6859 */
6861 assert(var != NULL);
6862
6863 lb = SCIPvarGetLbLocal(var);
6864 ub = SCIPvarGetUbLocal(var);
6865
6866 /* skip already fixed variable */
6867 if( SCIPisEQ(scip, lb, ub) )
6868 {
6869 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6870 continue;
6871 }
6872
6873 assert(*ncands + 1 < SCIPgetNVars(scip));
6874 cands[*ncands].expr = expr;
6875 cands[*ncands].var = var;
6876 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6877 cands[*ncands].fractionality = 0.0;
6878 ++(*ncands);
6879 }
6880 }
6881 }
6882
6883 /* if we have branching candidates, then we don't need another attempt */
6884 if( *ncands > 0 )
6885 break;
6886 }
6887
6888 if( it != NULL )
6889 SCIPfreeExpriter(&it);
6890
6891 return SCIP_OKAY;
6892}
6893
6894/** computes a branching score for a variable that reflects how important branching on this variable would be for
6895 * improving the dual bound from the LP relaxation
6896 *
6897 * Assume the Lagrangian for the current LP is something of the form
6898 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6899 * where x are the original variables, z the auxiliary variables,
6900 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6901 *
6902 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6903 * If we could have used not only an estimator, but the actual function f(x), then this would
6904 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6905 * Using a lot of handwaving, we claim that
6906 * lambda_i * (f(x) - a_i'x + b_i)
6907 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6908 * If an estimator depended on local bounds, then it could be improved by branching.
6909 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6910 *
6911 * 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.
6912 * To scale, we divide by the LP objective value (if >1).
6913 *
6914 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6915 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6916 *
6917 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6918 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6919 * would also be branching candidates
6920 */
6921static
6923 SCIP* scip, /**< SCIP data structure */
6924 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6925 SCIP_VAR* var /**< variable */
6926 )
6927{
6928 SCIP_COL* col;
6929 SCIP_ROW** rows;
6930 int nrows;
6931 int r;
6932 SCIP_Real dualscore;
6933
6934 assert(scip != NULL);
6935 assert(conshdlr != NULL);
6936 assert(var != NULL);
6937
6938 /* if LP not solved, then the dual branching score is not available */
6940 return 0.0;
6941
6942 /* if var is not in the LP, then the dual branching score is not available */
6944 return 0.0;
6945
6946 col = SCIPvarGetCol(var);
6947 assert(col != NULL);
6948
6949 if( !SCIPcolIsInLP(col) )
6950 return 0.0;
6951
6952 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6953 rows = SCIPcolGetRows(col);
6954
6955 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6956
6957 /* aggregate duals from all rows from consexpr with non-zero dual
6958 * TODO: this is a quick-and-dirty implementation, and not used by default
6959 * in the long run, this should be either removed or replaced by a proper implementation
6960 */
6961 dualscore = 0.0;
6962 for( r = 0; r < nrows; ++r )
6963 {
6964 SCIP_Real estimategap;
6965 const char* estimategapstr;
6966
6967 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6968 * these would typically be local, unless they are created at the root node
6969 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6970 if( !SCIProwIsLocal(rows[r]) )
6971 continue;
6972 */
6973 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6974 continue;
6975 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6976 continue;
6977
6978 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6979 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6980 continue;
6981 estimategap = atof(estimategapstr + 13);
6982 assert(estimategap >= 0.0);
6983 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6984 estimategap = SCIPgetHugeValue(scip);
6985
6986 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6987 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6988
6989 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6990 }
6991
6992 /* divide by optimal value of LP for scaling */
6993 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6994
6995 return dualscore;
6996}
6997
6998/** computes branching scores (including weighted score) for a set of candidates
6999 *
7000 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
7001 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
7002 *
7003 * For each score, compute the maximum over all candidates.
7004 *
7005 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
7006 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
7007 * score of all candidates.
7008 * Further divide by the sum of all weights where a score was available (even if the score was 0).
7009 *
7010 * For example:
7011 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
7012 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
7013 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
7014 * - 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.
7015 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
7016 */
7017static
7019 SCIP* scip, /**< SCIP data structure */
7020 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7021 BRANCHCAND* cands, /**< branching candidates */
7022 int ncands, /**< number of candidates */
7023 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7024 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
7025 )
7026{
7027 SCIP_CONSHDLRDATA* conshdlrdata;
7028 BRANCHCAND maxscore;
7029 int c;
7030
7031 assert(scip != NULL);
7032 assert(conshdlr != NULL);
7033 assert(cands != NULL);
7034 assert(ncands > 0);
7035
7036 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7037 assert(conshdlrdata != NULL);
7038
7039 /* initialize counts to 0 */
7040 memset(&maxscore, 0, sizeof(BRANCHCAND));
7041
7042 for( c = 0; c < ncands; ++c )
7043 {
7044 if( conshdlrdata->branchviolweight > 0.0 )
7045 {
7046 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
7047 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
7048 }
7049
7050 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarIsNonimpliedIntegral(cands[c].var) )
7051 {
7052 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
7053 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
7054 */
7055 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
7056
7057 if( considerfracnl && cands[c].fractionality == 0.0 )
7058 {
7059 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
7060 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
7061 */
7062 SCIP_Real solval;
7063 SCIP_Real rounded;
7064
7065 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7066 rounded = SCIPround(scip, solval);
7067
7068 cands[c].fractionality = REALABS(solval - rounded);
7069 }
7070
7071 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
7072 }
7073 else
7074 cands[c].fractionality = 0.0;
7075
7076 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
7077 {
7078 SCIP_Real domainwidth;
7079 SCIP_VAR* var;
7080
7081 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7082 assert(var != NULL);
7083
7084 /* get domain width, taking infinity at 1e20 on purpose */
7085 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
7086
7087 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7088 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7089 * the idea is to penalize very large and very small domains
7090 */
7091 if( domainwidth >= 1.0 )
7092 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7093 else
7094 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7095
7096 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7097 }
7098 else
7099 cands[c].domain = 0.0;
7100
7101 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
7102 {
7103 SCIP_VAR* var;
7104
7105 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7106 assert(var != NULL);
7107
7108 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7109 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7110 }
7111 else
7112 cands[c].dual = 0.0;
7113
7114 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7115 {
7116 SCIP_VAR* var;
7117
7118 var = cands[c].var;
7119 assert(var != NULL);
7120
7121 if( cands[c].expr != NULL )
7122 {
7124 cands[c].pscost = SCIP_INVALID;
7125 else
7126 {
7127 SCIP_Real brpoint;
7128 SCIP_Real pscostdown;
7129 SCIP_Real pscostup;
7130 char strategy;
7131
7132 /* decide how to compute pseudo-cost scores
7133 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7134 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7135 */
7136 if( !SCIPvarIsIntegral(var) )
7137 strategy = conshdlrdata->branchpscostupdatestrategy;
7138 else
7139 strategy = 'l';
7140
7142
7143 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7144 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7145 * For here, I use a simple #counts >= branchpscostreliable.
7146 * TODO use SCIPgetVarPseudocostCount() instead?
7147 */
7148 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7149 {
7150 switch( strategy )
7151 {
7152 case 's' :
7154 break;
7155 case 'd' :
7157 break;
7158 case 'l' :
7160 pscostdown = SCIP_INVALID;
7161 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7162 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7163 else
7165 break;
7166 default :
7167 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7168 pscostdown = SCIP_INVALID;
7169 }
7170 }
7171 else
7172 pscostdown = SCIP_INVALID;
7173
7174 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7175 {
7176 switch( strategy )
7177 {
7178 case 's' :
7180 break;
7181 case 'd' :
7183 break;
7184 case 'l' :
7186 pscostup = SCIP_INVALID;
7187 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7188 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7189 else
7191 break;
7192 default :
7193 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7194 pscostup = SCIP_INVALID;
7195 }
7196 }
7197 else
7198 pscostup = SCIP_INVALID;
7199
7200 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7201 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7202 */
7203 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7204 cands[c].pscost = SCIP_INVALID;
7205 else if( pscostdown == SCIP_INVALID )
7206 cands[c].pscost = pscostup;
7207 else if( pscostup == SCIP_INVALID )
7208 cands[c].pscost = pscostdown;
7209 else
7210 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7211 }
7212 }
7213 else
7214 {
7215 SCIP_Real pscostdown;
7216 SCIP_Real pscostup;
7217 SCIP_Real solval;
7218
7219 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7220
7221 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7222 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7223 * and different between variable value and rounded up value for pscostup
7224 */
7225 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7226 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7227 else
7228 pscostdown = SCIP_INVALID;
7229
7230 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7231 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7232 else
7233 pscostup = SCIP_INVALID;
7234
7235 /* TODO see above for nonlinear variable case */
7236 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7237 cands[c].pscost = SCIP_INVALID;
7238 else if( pscostdown == SCIP_INVALID )
7239 cands[c].pscost = pscostup;
7240 else if( pscostup == SCIP_INVALID )
7241 cands[c].pscost = pscostdown;
7242 else
7243 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7244 }
7245
7246 if( cands[c].pscost != SCIP_INVALID )
7247 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7248 }
7249 else
7250 cands[c].pscost = SCIP_INVALID;
7251
7252 if( conshdlrdata->branchvartypeweight > 0.0 )
7253 {
7254 switch( SCIPvarGetType(cands[c].var) )
7255 {
7257 cands[c].vartype = 1.0;
7258 break;
7260 cands[c].vartype = 0.1;
7261 break;
7263 if( SCIPvarIsImpliedIntegral(cands[c].var) )
7264 cands[c].vartype = 0.01;
7265 else
7266 cands[c].vartype = 0.0;
7267 break;
7268 default:
7269 SCIPerrorMessage("invalid variable type\n");
7270 SCIPABORT();
7271 return; /*lint !e527*/
7272 } /*lint !e788*/
7273
7274 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7275 }
7276 }
7277
7278 /* now compute a weighted score for each candidate from the single scores
7279 * the single scores are scaled to be in [0,1] for this
7280 */
7281 for( c = 0; c < ncands; ++c )
7282 {
7283 SCIP_Real weightsum;
7284
7285 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7286
7287 cands[c].weighted = 0.0;
7288 weightsum = 0.0;
7289
7290 if( maxscore.auxviol > 0.0 )
7291 {
7292 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7293 weightsum += conshdlrdata->branchviolweight;
7294
7295 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7296 }
7297
7298 if( maxscore.fractionality > 0.0 )
7299 {
7300 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7301 weightsum += conshdlrdata->branchfracweight;
7302
7303 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7304 }
7305
7306 if( maxscore.domain > 0.0 )
7307 {
7308 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7309 weightsum += conshdlrdata->branchdomainweight;
7310
7311 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7312 }
7313
7314 if( maxscore.dual > 0.0 )
7315 {
7316 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7317 weightsum += conshdlrdata->branchdualweight;
7318
7319 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7320 }
7321
7322 if( maxscore.pscost > 0.0 )
7323 {
7324 /* use pseudo-costs only if available */
7325 if( cands[c].pscost != SCIP_INVALID )
7326 {
7327 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7328 weightsum += conshdlrdata->branchpscostweight;
7329
7330 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7331 }
7332 else
7333 {
7334 /* do not add pscostscore, if not available, also do not add into weightsum */
7335 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7336 }
7337 }
7338
7339 if( maxscore.vartype > 0.0 )
7340 {
7341 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7342 weightsum += conshdlrdata->branchvartypeweight;
7343
7344 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7345 }
7346
7347 assert(weightsum > 0.0); /* we should have got at least one valid score */
7348 cands[c].weighted /= weightsum;
7349
7350 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7351 }
7352}
7353
7354/** compare two branching candidates by their weighted score
7355 *
7356 * if weighted score is equal, use variable index of (aux)var
7357 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7358 */
7359static
7360SCIP_DECL_SORTINDCOMP(branchcandCompare)
7361{
7362 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7363
7364 if( cands[ind1].weighted != cands[ind2].weighted )
7365 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7366
7367 if( cands[ind1].var != cands[ind2].var )
7368 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7369
7370 return cands[ind1].expr != NULL ? 1 : -1;
7371}
7372
7373/** picks a candidate from array of branching candidates */
7374static
7376 SCIP* scip, /**< SCIP data structure */
7377 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7378 BRANCHCAND* cands, /**< branching candidates */
7379 int ncands, /**< number of candidates */
7380 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7381 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
7382 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7383 )
7384{
7385 SCIP_CONSHDLRDATA* conshdlrdata;
7386 int* perm;
7387 int c;
7388 int left;
7389 int right;
7390 SCIP_Real threshold;
7391
7392 assert(cands != NULL);
7393 assert(ncands >= 1);
7394 assert(selected != NULL);
7395
7396 if( ncands == 1 )
7397 {
7398 *selected = cands;
7399 return SCIP_OKAY;
7400 }
7401
7402 /* if there are more than one candidate, then compute scores and select */
7403
7404 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7405 assert(conshdlrdata != NULL);
7406
7407 /* compute additional scores on branching candidates and weighted score */
7408 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
7409
7410 /* sort candidates by weighted score */
7411 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7412 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7413
7414 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7415 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7416 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7417
7418 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7419 left = 0;
7420 right = ncands - 1;
7421 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7422 while( left < right )
7423 {
7424 int mid = (left + right) / 2;
7425 if( cands[perm[mid]].weighted >= threshold )
7426 left = mid + 1;
7427 else
7428 right = mid;
7429 }
7430 assert(left <= ncands);
7431
7432 if( left < ncands )
7433 {
7434 if( cands[perm[left]].weighted >= threshold )
7435 {
7436 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7437 ncands = left + 1;
7438 }
7439 else
7440 {
7441 assert(cands[perm[left]].weighted < threshold);
7442 ncands = left;
7443 }
7444 }
7445 assert(ncands > 0);
7446
7447 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7448 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7449 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7450
7451 if( ncands > 1 )
7452 {
7453 /* choose at random from candidates 0..ncands-1 */
7454 if( conshdlrdata->branchrandnumgen == NULL )
7455 {
7456 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7457 }
7458 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7459 *selected = &cands[perm[c]];
7460 }
7461 else
7462 *selected = &cands[perm[0]];
7463
7464 SCIPfreeBufferArray(scip, &perm);
7465
7466 return SCIP_OKAY;
7467}
7468
7469/** do spatial branching or register branching candidates */
7470static
7472 SCIP* scip, /**< SCIP data structure */
7473 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7474 SCIP_CONS** conss, /**< constraints to process */
7475 int nconss, /**< number of constraints */
7476 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7477 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7478 SCIP_Longint soltag, /**< tag of solution */
7479 SCIP_RESULT* result /**< pointer to store the result of branching */
7480 )
7481{
7482 SCIP_CONSHDLRDATA* conshdlrdata;
7483 BRANCHCAND* cands;
7484 int ncands;
7485 BRANCHCAND* selected = NULL;
7486 SCIP_NODE* downchild;
7487 SCIP_NODE* eqchild;
7488 SCIP_NODE* upchild;
7489
7490 assert(conshdlr != NULL);
7491 assert(result != NULL);
7492
7494
7495 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7496 assert(conshdlrdata != NULL);
7497
7498 if( conshdlrdata->branchexternal )
7499 {
7500 /* just register branching candidates as external */
7501 SCIP_Bool success;
7502
7503 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7504 if( success )
7506
7507 return SCIP_OKAY;
7508 }
7509
7510 /* collect branching candidates and their auxviol-score */
7512 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7513
7514 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7515 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7516 */
7517 if( ncands == 0 )
7518 goto TERMINATE;
7519
7520 /* here we include fractionality of integer variables into the branching score
7521 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7522 */
7523 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
7524 assert(selected != NULL);
7525 assert(selected->expr != NULL);
7526
7527 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7528 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7529
7530 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7531 &upchild) );
7532 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7534 else
7535 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7537
7538 TERMINATE:
7539 SCIPfreeBufferArray(scip, &cands);
7540
7541 return SCIP_OKAY;
7542}
7543
7544/** call enforcement or estimate callback of nonlinear handler
7545 *
7546 * Calls the enforcement callback, if available.
7547 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7548 *
7549 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7550 */
7551static
7553 SCIP* scip, /**< SCIP main data structure */
7554 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7555 SCIP_CONS* cons, /**< nonlinear constraint */
7556 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7557 SCIP_EXPR* expr, /**< expression */
7558 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7559 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7560 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7561 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7562 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7563 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7564 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7565 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7566 SCIP_RESULT* result /**< pointer to store the result */
7567 )
7568{
7569 assert(result != NULL);
7570
7571 /* call enforcement callback of the nlhdlr */
7572 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7573 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7574
7575 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7577 {
7578 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7579 SCIPnlhdlrGetName(nlhdlr), *result); )
7580 return SCIP_OKAY;
7581 }
7582 else
7583 {
7584 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7585 }
7586
7588
7589 /* now call the estimator callback of the nlhdlr */
7590 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7591 {
7592 SCIP_VAR* auxvar;
7593 SCIP_Bool sepasuccess = FALSE;
7594 SCIP_Bool branchscoresuccess = FALSE;
7595 SCIP_PTRARRAY* rowpreps;
7596 int minidx;
7597 int maxidx;
7598 int r;
7599 SCIP_ROWPREP* rowprep;
7600
7601 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7602
7603 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7604 assert(auxvar != NULL);
7605
7606 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7607 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7608
7609 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7610 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7611
7612 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7613
7614 if( !sepasuccess )
7615 {
7616 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7617 SCIPnlhdlrGetName(nlhdlr)); )
7618 }
7619
7620 for( r = minidx; r <= maxidx; ++r )
7621 {
7622 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7623
7624 assert(rowprep != NULL);
7626
7627 if( !branchcandonly )
7628 {
7629 /* complete estimator to cut */
7630 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7631
7632 /* add the cut and/or branching scores
7633 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7634 */
7635 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7636 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7637 }
7638
7639 SCIPfreeRowprep(scip, &rowprep);
7640 }
7641
7642 if( branchcandonly && branchscoresuccess )
7643 {
7644 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7646 }
7647
7648 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7649 }
7650
7651 return SCIP_OKAY;
7652}
7653
7654/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7655 *
7656 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7657 */
7658static
7660 SCIP* scip, /**< SCIP data structure */
7661 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7662 SCIP_CONS* cons, /**< nonlinear constraint */
7663 SCIP_EXPR* expr, /**< expression */
7664 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7665 SCIP_Longint soltag, /**< tag of solution */
7666 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7667 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7668 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7669 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7670 )
7671{
7672 SCIP_CONSHDLRDATA* conshdlrdata;
7673 SCIP_EXPR_OWNERDATA* ownerdata;
7674 SCIP_Real origviol;
7675 SCIP_Bool underestimate;
7676 SCIP_Bool overestimate;
7677 SCIP_Real auxviol;
7678 SCIP_Bool auxunderestimate;
7679 SCIP_Bool auxoverestimate;
7680 SCIP_RESULT hdlrresult;
7681 int e;
7682
7683 assert(scip != NULL);
7684 assert(expr != NULL);
7685 assert(result != NULL);
7686
7687 ownerdata = SCIPexprGetOwnerData(expr);
7688 assert(ownerdata != NULL);
7689 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7690
7692
7693 /* make sure that this expression has been evaluated */
7694 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7695
7696 /* decide whether under- or overestimate is required and get amount of violation */
7697 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7698
7699 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7700 assert(conshdlrdata != NULL);
7701
7702 /* no sufficient violation w.r.t. the original variables -> skip expression */
7703 if( !overestimate && !underestimate )
7704 {
7705 return SCIP_OKAY;
7706 }
7707
7708 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7709 for( e = 0; e < ownerdata->nenfos; ++e )
7710 {
7711 SCIP_NLHDLR* nlhdlr;
7712
7713 /* skip nlhdlr that do not want to participate in any separation */
7714 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7715 continue;
7716
7717 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7718 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7719 continue;
7720
7721 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7722 assert(nlhdlr != NULL);
7723
7724 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7725 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7726 ENFOLOG(
7727 SCIPinfoMessage(scip, enfologfile, " expr ");
7728 SCIPprintExpr(scip, expr, enfologfile);
7729 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7730 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7731 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7732 )
7733
7734 /* TODO if expr is root of constraint (consdata->expr == expr),
7735 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7736 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7737 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7738 * so we should enforce in these auxiliaries first
7739 * if changing this here, we must also adapt analyzeViolation()
7740 */
7741
7742 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7743 assert(auxviol >= 0.0);
7744
7745 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7746 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7747 {
7748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7749 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7750 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7751
7752 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7753 continue;
7754 }
7755
7756 /* 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 */
7757 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7758 {
7759 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7760 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7761 underestimate, overestimate); )
7762
7763 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7764 continue;
7765 }
7766
7767 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7768 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7769 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7770
7771 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7772 * wants to be called for separation on this side, then call separation of nlhdlr
7773 */
7774 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7775 {
7776 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7777 hdlrresult = SCIP_DIDNOTFIND;
7778 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7779 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7780
7781 if( hdlrresult == SCIP_CUTOFF )
7782 {
7783 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7785 ownerdata->lastenforced = conshdlrdata->enforound;
7786 break;
7787 }
7788
7789 if( hdlrresult == SCIP_SEPARATED )
7790 {
7791 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7793 ownerdata->lastenforced = conshdlrdata->enforound;
7794 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7795 break;
7796 }
7797
7798 if( hdlrresult == SCIP_REDUCEDDOM )
7799 {
7800 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7802 ownerdata->lastenforced = conshdlrdata->enforound;
7803 /* TODO or should we always just stop here? */
7804 }
7805
7806 if( hdlrresult == SCIP_BRANCHED )
7807 {
7808 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7809 assert(inenforcement);
7810
7811 /* separation and domain reduction takes precedence over branching */
7813 if( *result == SCIP_DIDNOTFIND )
7815 ownerdata->lastenforced = conshdlrdata->enforound;
7816 }
7817 }
7818
7819 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7820 * wants to be called for separation on this side, then call separation of nlhdlr
7821 */
7822 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7823 {
7824 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7825 hdlrresult = SCIP_DIDNOTFIND;
7826 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7827 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7828
7829 if( hdlrresult == SCIP_CUTOFF )
7830 {
7831 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7833 ownerdata->lastenforced = conshdlrdata->enforound;
7834 break;
7835 }
7836
7837 if( hdlrresult == SCIP_SEPARATED )
7838 {
7839 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7841 ownerdata->lastenforced = conshdlrdata->enforound;
7842 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7843 break;
7844 }
7845
7846 if( hdlrresult == SCIP_REDUCEDDOM )
7847 {
7848 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7850 ownerdata->lastenforced = conshdlrdata->enforound;
7851 /* TODO or should we always just stop here? */
7852 }
7853
7854 if( hdlrresult == SCIP_BRANCHED )
7855 {
7856 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7857 assert(inenforcement);
7858
7859 /* separation takes precedence over branching */
7861 if( *result == SCIP_DIDNOTFIND )
7863 ownerdata->lastenforced = conshdlrdata->enforound;
7864 }
7865 }
7866 }
7867
7868 return SCIP_OKAY;
7869}
7870
7871/** helper function to enforce a single constraint */
7872static
7874 SCIP* scip, /**< SCIP data structure */
7875 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7876 SCIP_CONS* cons, /**< constraint to process */
7877 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7878 SCIP_Longint soltag, /**< tag of solution */
7879 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7880 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7881 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7882 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7883 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7884 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7885 )
7886{
7887 SCIP_CONSDATA* consdata;
7888 SCIP_CONSHDLRDATA* conshdlrdata;
7889 SCIP_EXPR* expr;
7890
7891 assert(conshdlr != NULL);
7892 assert(cons != NULL);
7893 assert(it != NULL);
7894 assert(result != NULL);
7895 assert(success != NULL);
7896
7897 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7898 assert(conshdlrdata != NULL);
7899
7900 consdata = SCIPconsGetData(cons);
7901 assert(consdata != NULL);
7902 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7903
7904 *success = FALSE;
7905
7906 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7907 {
7908 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7909 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7910 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7911 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7912 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7913 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7914 * confuse the stalling check for how long to do separation).
7915 */
7916 SCIP_Bool infeasible;
7917 int ntightenings;
7918
7919 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7920 if( infeasible )
7921 {
7923 return SCIP_OKAY;
7924 }
7925 /* if we tightened an auxvar bound, we better communicate that */
7926 if( ntightenings > 0 )
7928 }
7929
7930 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7931 {
7932 SCIP_EXPR_OWNERDATA* ownerdata;
7933 SCIP_RESULT resultexpr;
7934
7935 ownerdata = SCIPexprGetOwnerData(expr);
7936 assert(ownerdata != NULL);
7937
7938 /* we can only enforce if there is an auxvar to compare with */
7939 if( ownerdata->auxvar == NULL )
7940 continue;
7941
7942 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7943 if( ownerdata->lastenforced == conshdlrdata->enforound )
7944 {
7945 ENFOLOG(
7946 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7947 SCIPprintExpr(scip, expr, enfologfile);
7948 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7949 )
7950 *success = TRUE;
7951 continue;
7952 }
7953
7954 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7955
7956 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7957 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7958 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
7959 *success = TRUE;
7960
7961 if( resultexpr == SCIP_CUTOFF )
7962 {
7964 break;
7965 }
7966
7967 if( resultexpr == SCIP_SEPARATED )
7969
7970 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7972
7973 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7975 }
7976
7977 return SCIP_OKAY;
7978}
7979
7980/** try to separate violated constraints and, if in enforcement, register branching scores
7981 *
7982 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7983 *
7984 * Sets result to
7985 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7986 * - SCIP_CUTOFF, if node can be cutoff,
7987 * - SCIP_SEPARATED, if a cut has been added,
7988 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7989 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7990 * - SCIP_INFEASIBLE, if external branching candidates were registered
7991 */
7992static
7994 SCIP* scip, /**< SCIP data structure */
7995 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7996 SCIP_CONS** conss, /**< constraints to process */
7997 int nconss, /**< number of constraints */
7998 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7999 SCIP_Longint soltag, /**< tag of solution */
8000 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
8001 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
8002 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
8003 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8004 )
8005{
8006 SCIP_CONSHDLRDATA* conshdlrdata;
8007 SCIP_EXPRITER* it;
8008 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
8009 int c;
8010
8011 assert(conshdlr != NULL);
8012 assert(conss != NULL || nconss == 0);
8013 assert(result != NULL);
8014
8015 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8016 assert(conshdlrdata != NULL);
8017
8018 /* increase tag to tell whether branching scores in expression belong to this sweep
8019 * and which expressions have already been enforced in this sweep
8020 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
8021 */
8022 ++(conshdlrdata->enforound);
8023
8025
8028
8029 for( c = 0; c < nconss; ++c )
8030 {
8031 assert(conss != NULL && conss[c] != NULL);
8032
8033 /* skip constraints that are not enabled or deleted */
8034 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
8035 continue;
8036 assert(SCIPconsIsActive(conss[c]));
8037
8038 /* skip constraints that have separation disabled if we are only in separation */
8039 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
8040 continue;
8041
8042 /* skip non-violated constraints */
8043 if( !isConsViolated(scip, conss[c]) )
8044 continue;
8045
8046 ENFOLOG(
8047 {
8048 SCIP_CONSDATA* consdata;
8049 int i;
8050 consdata = SCIPconsGetData(conss[c]);
8051 assert(consdata != NULL);
8052 SCIPinfoMessage(scip, enfologfile, " constraint ");
8053 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
8054 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
8055 for( i = 0; i < consdata->nvarexprs; ++i )
8056 {
8057 SCIP_VAR* var;
8058 var = SCIPgetVarExprVar(consdata->varexprs[i]);
8059 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
8061 }
8062 })
8063
8064 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
8065
8066 if( *result == SCIP_CUTOFF )
8067 break;
8068
8069 if( !consenforced && inenforcement && !branchcandonly )
8070 {
8071 SCIP_Real viol;
8072
8073 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
8074 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
8075 {
8076 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
8077 "cuts allowed\n", SCIPconsGetName(conss[c])); )
8078
8079 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
8080
8081 if( consenforced )
8082 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
8083
8084 if( *result == SCIP_CUTOFF )
8085 break;
8086 }
8087 }
8088 }
8089
8090 SCIPfreeExpriter(&it);
8091
8092 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8093
8094 if( *result == SCIP_BRANCHED && !branchcandonly )
8095 {
8096 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
8097 * branching
8098 */
8099 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
8100
8101 /* branching should either have branched: result == SCIP_BRANCHED,
8102 * or fixed a variable: result == SCIP_REDUCEDDOM,
8103 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
8104 * or have not done anything: result == SCIP_DIDNOTFIND
8105 */
8107 }
8108
8109 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8110
8111 return SCIP_OKAY;
8112}
8113
8114/** decide whether to branch on fractional integer or nonlinear variable
8115 *
8116 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
8117 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
8118 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
8119 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
8120 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
8121 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
8122 */
8123static
8125 SCIP* scip, /**< SCIP data structure */
8126 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8127 SCIP_CONS** conss, /**< constraints to process */
8128 int nconss, /**< number of constraints */
8129 SCIP_Longint soltag, /**< tag of LP solution */
8130 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
8131 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
8132 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
8133 )
8134{
8136 int nlpcands;
8137 SCIP_VAR** lpcands; /* fractional integer variables */
8138 SCIP_Real* lpcandsfrac; /* fractionalities */
8139 BRANCHCAND* cands;
8140 BRANCHCAND* selected;
8141 int ncands;
8142 int c;
8143
8144 assert(scip != NULL);
8145 assert(conshdlr != NULL);
8146 assert(conss != NULL);
8147 assert(nconss > 0);
8148 assert(branchintegral != NULL);
8149 assert(cutoff != NULL);
8150
8151 *branchintegral = FALSE;
8152 *cutoff = FALSE;
8153
8155 return SCIP_OKAY;
8156
8157 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
8158 switch( result )
8159 {
8160 case SCIP_DIDNOTFIND:
8161 /* no branching candidates found could mean that the LP solution is in a convex region */
8162 *branchintegral = TRUE;
8163 return SCIP_OKAY;
8164
8165 case SCIP_CUTOFF:
8166 /* probably cannot happen, but easy to handle */
8167 *cutoff = TRUE;
8168 return SCIP_OKAY;
8169
8170 case SCIP_SEPARATED:
8171 case SCIP_REDUCEDDOM:
8172 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8173 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8174 return SCIP_ERROR;
8175
8176 case SCIP_BRANCHED:
8177 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8178 break;
8179
8180 case SCIP_INFEASIBLE:
8181 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8182 * but this was disabled by branchcandonly = TRUE)
8183 */
8184 default:
8185 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8186 return SCIP_ERROR;
8187 } /*lint !e788*/
8188
8189 /* collect spatial branching candidates and their auxviol-score */
8191 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8192
8193 /* add fractional integer variables to branching candidates */
8195
8196 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8197
8198 for( c = 0; c < nlpcands; ++c )
8199 {
8202 cands[ncands].expr = NULL;
8203 cands[ncands].var = lpcands[c];
8204 cands[ncands].auxviol = 0.0;
8205 cands[ncands].fractionality = lpcandsfrac[c];
8206 ++ncands;
8207 }
8208
8209 /* select a variable for branching
8210 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8211 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
8212 */
8213 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
8214 assert(selected != NULL);
8215
8216 if( selected->expr == NULL )
8217 {
8218 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8219
8220 *branchintegral = TRUE;
8221 }
8222
8223 SCIPfreeBufferArray(scip, &cands);
8224
8225 return SCIP_OKAY;
8226}
8227
8228/** decide whether to consider spatial branching before integrality has been enforced
8229 *
8230 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8231 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8232 *
8233 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8234 */
8235static
8237 SCIP* scip, /**< SCIP data structure */
8238 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8239 SCIP_SOL* sol /**< solution to be enforced */
8240 )
8241{
8242 SCIP_CONSHDLRDATA* conshdlrdata;
8243
8244 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8245 assert(conshdlrdata != NULL);
8246
8247 /* if LP still unbounded, then work on nonlinear constraints first */
8249 return FALSE;
8250
8251 /* no branching in cons_integral if no integer variables */
8253 return FALSE;
8254
8255 /* no branching in cons_integral if LP solution not fractional */
8256 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
8257 return FALSE;
8258
8259 /* no branching in cons_integral if relax solution not fractional */
8260 if( sol != NULL )
8261 {
8262 SCIP_Bool isfractional = FALSE;
8263 SCIP_VAR** vars;
8264 int nbinvars;
8265 int nintvars;
8266 int i;
8267
8269 nbinvars = SCIPgetNBinVars(scip);
8270 nintvars = SCIPgetNIntVars(scip);
8271
8272 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
8273 {
8274 assert(vars[i] != NULL);
8276
8278 isfractional = TRUE;
8279 }
8280
8281 if( !isfractional )
8282 return FALSE;
8283 }
8284
8285 /* branchmixfractional being infinity means that integral should always go first */
8286 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8287 return TRUE;
8288
8289 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8290 if( conshdlrdata->branchmixfractional == 0.0 )
8291 return FALSE;
8292
8293 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8294 * @todo this gives the total pseudocost count divided by the number of discrete variables
8295 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8296 */
8297 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8298 return TRUE;
8299 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8300 return TRUE;
8301
8302 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8303 return FALSE;
8304}
8305
8306/** collect (and print (if debugging enfo)) information on violation in expressions
8307 *
8308 * assumes that constraint violations have been computed
8309 */
8310static
8312 SCIP* scip, /**< SCIP data structure */
8313 SCIP_CONS** conss, /**< constraints */
8314 int nconss, /**< number of constraints */
8315 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8316 SCIP_Longint soltag, /**< tag of solution */
8317 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8318 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8319 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8320 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8321 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8322 )
8323{
8324 SCIP_CONSDATA* consdata;
8325 SCIP_EXPRITER* it;
8326 SCIP_EXPR* expr;
8327 SCIP_Real v;
8328 int c;
8329
8330 assert(conss != NULL || nconss == 0);
8331 assert(maxabsconsviol != NULL);
8332 assert(maxrelconsviol != NULL);
8333 assert(maxauxviol != NULL);
8334 assert(maxvarboundviol != NULL);
8335
8338
8339 *maxabsconsviol = 0.0;
8340 *maxrelconsviol = 0.0;
8341 *minauxviol = SCIPinfinity(scip);
8342 *maxauxviol = 0.0;
8343 *maxvarboundviol = 0.0;
8344
8345 for( c = 0; c < nconss; ++c )
8346 {
8347 assert(conss != NULL && conss[c] != NULL);
8348
8349 consdata = SCIPconsGetData(conss[c]);
8350 assert(consdata != NULL);
8351
8352 /* skip constraints that are not enabled, deleted, or have separation disabled */
8353 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8354 continue;
8355 assert(SCIPconsIsActive(conss[c]));
8356
8357 v = getConsAbsViolation(conss[c]);
8358 *maxabsconsviol = MAX(*maxabsconsviol, v);
8359
8360 /* skip non-violated constraints */
8361 if( !isConsViolated(scip, conss[c]) )
8362 continue;
8363
8364 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8365 *maxrelconsviol = MAX(*maxrelconsviol, v);
8366
8367 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8368 {
8369 SCIP_EXPR_OWNERDATA* ownerdata;
8370 SCIP_Real auxvarvalue;
8371 SCIP_Real auxvarlb;
8372 SCIP_Real auxvarub;
8373 SCIP_Bool violunder;
8374 SCIP_Bool violover;
8375 SCIP_Real origviol;
8376 SCIP_Real auxviol;
8377 int e;
8378
8379 ownerdata = SCIPexprGetOwnerData(expr);
8380 assert(ownerdata != NULL);
8381
8382 if( ownerdata->auxvar == NULL )
8383 {
8384 /* check violation of variable bounds of original variable */
8385 if( SCIPisExprVar(scip, expr) )
8386 {
8387 SCIP_VAR* var;
8388 var = SCIPgetVarExprVar(expr);
8389 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8390 auxvarlb = SCIPvarGetLbLocal(var);
8391 auxvarub = SCIPvarGetUbLocal(var);
8392
8393 origviol = 0.0;
8394 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8395 origviol = auxvarlb - auxvarvalue;
8396 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8397 origviol = auxvarvalue - auxvarub;
8398 if( origviol <= 0.0 )
8399 continue;
8400
8401 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8402
8403 ENFOLOG(
8404 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8405 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8406 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8407 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8408 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8409 SCIPinfoMessage(scip, enfologfile, "\n");
8410 )
8411 }
8412
8413 continue;
8414 }
8415
8416 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8417 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8418 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8419
8420 /* check violation of variable bounds of auxiliary variable */
8421 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8422 *maxvarboundviol = auxvarlb - auxvarvalue;
8423 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8424 *maxvarboundviol = auxvarvalue - auxvarub;
8425
8426 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8427
8428 ENFOLOG(
8429 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8430 {
8431 SCIPinfoMessage(scip, enfologfile, "expr ");
8432 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8433 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8434
8435 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8436 if( origviol > 0.0 )
8437 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8438 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8439 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8440 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8441 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8442 SCIPinfoMessage(scip, enfologfile, "\n");
8443 }
8444 )
8445
8446 /* no violation w.r.t. the original variables -> skip expression */
8447 if( origviol == 0.0 )
8448 continue;
8449
8450 /* compute aux-violation for each nonlinear handlers */
8451 for( e = 0; e < ownerdata->nenfos; ++e )
8452 {
8453 SCIP_NLHDLR* nlhdlr;
8454
8455 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8456 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8457 continue;
8458
8459 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8460 assert(nlhdlr != NULL);
8461
8462 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8463 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8464
8465 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8466
8467 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8468
8469 if( auxviol > 0.0 )
8470 {
8471 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8472 *maxauxviol = MAX(*maxauxviol, auxviol);
8473 *minauxviol = MIN(*minauxviol, auxviol);
8474 }
8475 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8476 }
8477 }
8478 }
8479
8480 SCIPfreeExpriter(&it);
8481
8482 return SCIP_OKAY;
8483} /*lint !e715*/
8484
8485/** enforcement of constraints called by enfolp and enforelax */
8486static
8488 SCIP* scip, /**< SCIP data structure */
8489 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8490 SCIP_CONS** conss, /**< constraints to process */
8491 int nconss, /**< number of constraints */
8492 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8493 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8494 )
8495{
8496 SCIP_CONSHDLRDATA* conshdlrdata;
8497 SCIP_Real maxabsconsviol;
8498 SCIP_Real maxrelconsviol;
8499 SCIP_Real minauxviol;
8500 SCIP_Real maxauxviol;
8501 SCIP_Real maxvarboundviol;
8502 SCIP_Longint soltag;
8503 SCIP_Bool branchintegral;
8504 int nnotify;
8505 int c;
8506
8507 if( branchingIntegralFirst(scip, conshdlr, sol) )
8508 {
8509 /* let cons_integral handle enforcement */
8511 return SCIP_OKAY;
8512 }
8513
8514 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8515 assert(conshdlr != NULL);
8516
8517 soltag = SCIPgetExprNewSoltag(scip);
8518
8520 for( c = 0; c < nconss; ++c )
8521 {
8522 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8523
8524 if( isConsViolated(scip, conss[c]) )
8526 }
8527
8528 if( *result == SCIP_FEASIBLE )
8529 {
8530 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8532 return SCIP_OKAY;
8533 }
8534
8535 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8536 &minauxviol, &maxauxviol, &maxvarboundviol) );
8537
8538 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8539 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8540 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8541 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8542
8543 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8544
8545 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8546 if( sol == NULL )
8547 {
8549
8550 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8551 if( cutoff )
8552 {
8554 return SCIP_OKAY;
8555 }
8556 if( branchintegral )
8557 {
8558 /* let cons_integral handle enforcement */
8560 return SCIP_OKAY;
8561 }
8562 }
8563
8564 /* try to propagate */
8565 if( conshdlrdata->propinenforce )
8566 {
8567 SCIP_RESULT propresult;
8568 int nchgbds = 0;
8569
8570 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8571
8572 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8573 {
8574 *result = propresult;
8575 return SCIP_OKAY;
8576 }
8577 }
8578
8579 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8580 * all violated expr/auxvar in violated constraints)
8581 */
8582 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8583 sol == NULL )
8584 {
8585 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8586 ++conshdlrdata->ntightenlp;
8587
8589
8590 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8591 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8592
8593 return SCIP_OKAY;
8594 }
8595
8596 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8597 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8598 */
8599 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8600 {
8601 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8602 ++conshdlrdata->ntightenlp;
8603
8605
8606 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8607
8608 return SCIP_OKAY;
8609 }
8610
8611 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8612
8615 return SCIP_OKAY;
8616
8618
8619 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8620 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8621
8622 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8623 {
8624 /* if there are still fractional integer variables, then let cons_integral go first */
8626 return SCIP_OKAY;
8627 }
8628
8629 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8630 {
8631 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8632 ++conshdlrdata->ntightenlp;
8633
8635
8636 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8637 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8638
8639 return SCIP_OKAY;
8640 }
8641
8642 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8643 SCIPgetLPFeastol(scip)) && sol == NULL )
8644 {
8645 /* try whether tighten the LP feasibility tolerance could help
8646 * maybe it is just some cut that hasn't been taken into account sufficiently
8647 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8648 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8649 * until the LP feastol reaches epsilon
8650 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8651 * when maxauxviol is above LP feastol)
8652 */
8653 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8654 ++conshdlrdata->ndesperatetightenlp;
8655
8657
8658 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8659
8660 return SCIP_OKAY;
8661 }
8662
8663 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8664 if( !conshdlrdata->propinenforce )
8665 {
8666 SCIP_RESULT propresult;
8667 int nchgbds = 0;
8668
8669 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8670
8671 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8672 {
8673 *result = propresult;
8674 return SCIP_OKAY;
8675 }
8676 }
8677
8678 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8679 * now look if we find any unfixed variable that we could still branch on
8680 */
8681 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8682
8683 if( nnotify > 0 )
8684 {
8685 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8686 ++conshdlrdata->ndesperatebranch;
8687
8688 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8689
8690 return SCIP_OKAY;
8691 }
8692
8693 /* if everything is fixed in violated constraints, then let's cut off the node
8694 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8695 * result may not be conclusive (when constraint violations are small)
8696 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8697 * sufficiently (see st_e40)
8698 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8699 * not "desperate", but a pretty obvious thing to do
8700 */
8701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8703
8704 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8705 if( !SCIPisZero(scip, maxvarboundviol) )
8706 ++conshdlrdata->ndesperatecutoff;
8707
8708 return SCIP_OKAY;
8709}
8710
8711/** separation for all violated constraints to be used by SEPA callbacks */
8712static
8714 SCIP* scip, /**< SCIP data structure */
8715 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8716 SCIP_CONS** conss, /**< constraints to process */
8717 int nconss, /**< number of constraints */
8718 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8719 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8720 )
8721{
8722 SCIP_Longint soltag;
8723 SCIP_Bool haveviol = FALSE;
8724 int c;
8725
8727
8728 soltag = SCIPgetExprNewSoltag(scip);
8729
8730 /* compute violations */
8731 for( c = 0; c < nconss; ++c )
8732 {
8733 assert(conss[c] != NULL);
8734
8735 /* skip constraints that are not enabled, deleted, or have separation disabled */
8736 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8737 continue;
8738 assert(SCIPconsIsActive(conss[c]));
8739
8740 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8741
8742 if( isConsViolated(scip, conss[c]) )
8743 haveviol = TRUE;
8744 }
8745
8746 /* if none of our constraints are violated, don't attempt separation */
8747 if( !haveviol )
8748 {
8749 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8750 return SCIP_OKAY;
8751 }
8752
8753 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8754
8755 /* call separation */
8756 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8757
8758 return SCIP_OKAY;
8759}
8760
8761/** hash key retrieval function for bilinear term entries */
8762static
8763SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8764{ /*lint --e{715}*/
8765 SCIP_CONSHDLRDATA* conshdlrdata;
8766 int idx;
8767
8768 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8769 assert(conshdlrdata != NULL);
8770
8771 idx = ((int)(size_t)elem) - 1;
8772 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8773
8774 return (void*)&conshdlrdata->bilinterms[idx];
8775}
8776
8777/** returns TRUE iff the bilinear term entries are equal */
8778static
8779SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8780{ /*lint --e{715}*/
8783
8784 /* get corresponding entries */
8785 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8786 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8787 assert(entry1->x != NULL && entry1->y != NULL);
8788 assert(entry2->x != NULL && entry2->y != NULL);
8789 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8790 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8791
8792 return entry1->x == entry2->x && entry1->y == entry2->y;
8793}
8794
8795/** returns the hash value of the key */
8796static
8797SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8798{ /*lint --e{715}*/
8800
8801 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8802 assert(entry->x != NULL && entry->y != NULL);
8803 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8804
8805 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8806}
8807
8808/** compare two auxiliary expressions
8809 *
8810 * Compares auxiliary variables, followed by coefficients, and then constants.
8811 */
8812static
8814{
8817 int compvars;
8818 int i;
8819
8820 /* compare the auxiliary variables */
8821 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8822
8823 if( compvars != 0 )
8824 return compvars;
8825
8826 /* compare the coefficients and constants */
8827 for( i = 0; i < 3; ++i )
8828 {
8829 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8830 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8831 }
8832
8833 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8834}
8835
8836/* add an auxiliary expression to a bilinear term */
8837static
8839 SCIP* scip, /**< SCIP data structure */
8840 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8841 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8842 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8843 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8844 )
8845{
8846 SCIP_Bool found;
8847 int pos;
8848 int i;
8849
8850 *added = FALSE;
8851
8852 /* check if auxexpr has already been added to term */
8853 if( term->nauxexprs == 0 )
8854 {
8855 found = FALSE;
8856 pos = 0;
8857 }
8858 else
8859 {
8860 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8861 }
8862
8863 if( !found )
8864 {
8865 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8866 return SCIP_OKAY;
8867
8869 assert(term->auxexprssize >= term->nauxexprs + 1);
8870
8871 /* insert expression at the correct position */
8872 for( i = term->nauxexprs; i > pos; --i )
8873 {
8874 term->aux.exprs[i] = term->aux.exprs[i-1];
8875 }
8876 term->aux.exprs[pos] = auxexpr;
8877 ++(term->nauxexprs);
8878 *added = TRUE;
8879 }
8880 else
8881 {
8882 assert(term->aux.exprs != NULL);
8883 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8884 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8885 }
8886
8887 return SCIP_OKAY;
8888}
8889
8890/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8891static
8893 SCIP* scip, /**< SCIP data structure */
8894 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8895 SCIP_CONS** conss, /**< nonlinear constraints */
8896 int nconss /**< total number of nonlinear constraints */
8897 )
8898{
8899 SCIP_CONSHDLRDATA* conshdlrdata;
8900 SCIP_EXPRITER* it;
8901 int c;
8902
8903 assert(conss != NULL || nconss == 0);
8904
8905 if( nconss == 0 )
8906 return SCIP_OKAY;
8907
8908 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8909 assert(conshdlrdata != NULL);
8910
8911 /* check whether the bilinear terms have been stored already */
8912 if( conshdlrdata->bilinterms != NULL )
8913 return SCIP_OKAY;
8914
8915 /* create and initialize iterator */
8919
8920 /* iterate through all constraints */
8921 for( c = 0; c < nconss; ++c )
8922 {
8923 SCIP_CONSDATA* consdata;
8924 SCIP_EXPR* expr;
8925
8926 assert(conss != NULL && conss[c] != NULL);
8927 consdata = SCIPconsGetData(conss[c]);
8928 assert(consdata != NULL);
8929
8930 /* iterate through all expressions */
8931 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8932 {
8933 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8934 SCIP_VAR* x = NULL;
8935 SCIP_VAR* y = NULL;
8936
8937 /* check whether the expression is of the form f(..)^2 */
8938 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8939 {
8940 x = SCIPgetExprAuxVarNonlinear(children[0]);
8941 y = x;
8942 }
8943 /* check whether the expression is of the form f(..) * g(..) */
8944 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8945 {
8946 x = SCIPgetExprAuxVarNonlinear(children[0]);
8947 y = SCIPgetExprAuxVarNonlinear(children[1]);
8948 }
8949
8950 /* add variables to the hash table */
8951 if( x != NULL && y != NULL )
8952 {
8955 }
8956 }
8957 }
8958
8959 /* release iterator */
8960 SCIPfreeExpriter(&it);
8961
8962 return SCIP_OKAY;
8963}
8964
8965/** store x, y and the locks in a new bilinear term */
8966static
8968 SCIP* scip, /**< SCIP data structure */
8969 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8970 SCIP_VAR* x, /**< the first variable */
8971 SCIP_VAR* y, /**< the second variable */
8972 int nlockspos, /**< number of positive locks of the bilinear term */
8973 int nlocksneg, /**< number of negative locks of the bilinear term */
8974 int* idx, /**< pointer to store the position of the term in bilinterms array */
8975 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8976 )
8977{
8978 SCIP_CONSHDLRDATA* conshdlrdata;
8980
8981 assert(conshdlr != NULL);
8982 assert(x != NULL);
8983 assert(y != NULL);
8984 assert(nlockspos >= 0);
8985 assert(nlocksneg >= 0);
8986
8987 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8988 assert(conshdlrdata != NULL);
8989
8990 /* ensure that x.index <= y.index */
8991 if( SCIPvarCompare(x, y) == 1 )
8992 {
8993 SCIPswapPointers((void**)&x, (void**)&y);
8994 }
8995 assert(SCIPvarCompare(x, y) < 1);
8996
8997 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8998
8999 /* update or create the term */
9000 if( *idx >= 0 )
9001 { /* the term has already been added */
9002 assert(conshdlrdata->bilinterms[*idx].x == x);
9003 assert(conshdlrdata->bilinterms[*idx].y == y);
9004
9005 /* get term and add locks */
9006 term = &conshdlrdata->bilinterms[*idx];
9007 assert(existing <= term->existing); /* implicit terms are added after existing ones */
9008 term->nlockspos += nlockspos;
9009 term->nlocksneg += nlocksneg;
9010 }
9011 else
9012 { /* this is the first time we encounter this product */
9013 /* ensure size of bilinterms array */
9014 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
9015
9016 *idx = conshdlrdata->nbilinterms;
9017
9018 /* get term and set values in the created bilinear term */
9019 term = &conshdlrdata->bilinterms[*idx];
9020 assert(term != NULL);
9021 term->x = x;
9022 term->y = y;
9023 term->nauxexprs = 0;
9024 term->auxexprssize = 0;
9025 term->nlockspos = nlockspos;
9026 term->nlocksneg = nlocksneg;
9027 term->existing = existing;
9028 if( existing )
9029 term->aux.var = NULL;
9030 else
9031 term->aux.exprs = NULL;
9032
9033 /* increase the total number of bilinear terms */
9034 ++(conshdlrdata->nbilinterms);
9035
9036 /* save to the hashtable */
9037 if( conshdlrdata->bilinhashtable == NULL )
9038 {
9039 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
9040 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
9041 (void*)conshdlrdata) );
9042 }
9043 assert(conshdlrdata->bilinhashtable != NULL);
9044
9045 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
9046 * because zero can not be inserted into hash table
9047 */
9048 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
9049
9050 /* capture product variables */
9053 }
9054
9055 return SCIP_OKAY;
9056}
9057
9058/** frees array of bilinear terms and hash table */
9059static
9061 SCIP* scip, /**< SCIP data structure */
9062 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
9063 )
9064{
9065 int i;
9066 int j;
9067
9068 assert(conshdlrdata != NULL);
9069
9070 /* check whether bilinear terms have been stored */
9071 if( conshdlrdata->bilinterms == NULL )
9072 {
9073 assert(conshdlrdata->bilinterms == NULL);
9074 assert(conshdlrdata->nbilinterms == 0);
9075 assert(conshdlrdata->bilintermssize == 0);
9076
9077 return SCIP_OKAY;
9078 }
9079
9080 /* release variables */
9081 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
9082 {
9083 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
9084 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
9085
9086 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
9087 {
9088 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
9089 {
9090 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
9091 }
9092 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
9093 }
9094
9095 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
9096 {
9097 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
9098 continue;
9099 }
9100
9101 /* the rest is for simple terms with a single auxvar */
9102
9103 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
9104 if( conshdlrdata->bilinterms[i].aux.var != NULL )
9105 {
9106 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
9107 }
9108 }
9109
9110 /* free hash table */
9111 if( conshdlrdata->bilinhashtable != NULL )
9112 {
9113 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
9114 }
9115
9116 /* free bilinterms array; reset counters */
9117 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
9118 conshdlrdata->nbilinterms = 0;
9119 conshdlrdata->bilintermssize = 0;
9120
9121 return SCIP_OKAY;
9122}
9123
9124/*
9125 * vertex polyhedral separation
9126 */
9127
9128/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
9129static
9131 SCIP* scip, /**< SCIP data structure */
9132 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
9133 SCIP_LPI** lp /**< pointer to store created LP */
9134 )
9135{
9136 SCIP_Real* obj;
9137 SCIP_Real* lb;
9138 SCIP_Real* ub;
9139 SCIP_Real* val;
9140 int* beg;
9141 int* ind;
9142 unsigned int nnonz;
9143 unsigned int ncols;
9144 unsigned int nrows;
9145 unsigned int i;
9146 unsigned int k;
9147
9148 assert(scip != NULL);
9149 assert(lp != NULL);
9150 assert(nvars > 0);
9152
9153 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
9154
9155 /* create lpi to store the LP */
9157
9158 nrows = (unsigned int)nvars + 1;
9159 ncols = POWEROFTWO((unsigned int)nvars);
9160 nnonz = (ncols * (nrows + 1)) / 2;
9161
9162 /* allocate necessary memory; set obj, lb, and ub to zero */
9165 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
9166 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
9167 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
9168 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
9169
9170 /* calculate nonzero entries in the LP */
9171 for( i = 0, k = 0; i < ncols; ++i )
9172 {
9173 int row;
9174 unsigned int a;
9175
9176 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
9177 ub[i] = SCIPlpiInfinity(*lp);
9178
9179 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
9180 beg[i] = (int)k;
9181 row = 0;
9182
9183 /* iterate through the bit representation of i */
9184 a = 1;
9185 while( a <= i )
9186 {
9187 if( (a & i) != 0 )
9188 {
9189 val[k] = 1.0;
9190 ind[k] = row;
9191
9192 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
9193
9194 ++k;
9195 }
9196
9197 a <<= 1;
9198 ++row;
9199 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
9200 assert(POWEROFTWO(row) == a);
9201 }
9202
9203 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
9204 val[k] = 1.0;
9205 ind[k] = (int)nrows - 1;
9206 ++k;
9207 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9208 }
9209 assert(k == nnonz);
9210
9211 /* load all data into LP interface
9212 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9213 */
9214 assert(nrows <= ncols);
9216 (int)ncols, obj, lb, ub, NULL,
9217 (int)nrows, lb, lb, NULL,
9218 (int)nnonz, beg, ind, val) );
9219
9220 /* for the last row, we can set the rhs to 1.0 already */
9221 ind[0] = (int)nrows - 1;
9222 val[0] = 1.0;
9223 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9224
9225 /* free allocated memory */
9232
9233 return SCIP_OKAY;
9234}
9235
9236/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9237 * \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
9238 * set of vertices of the domain
9239 */
9240static
9242 SCIP* scip, /**< SCIP data structure */
9243 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9244 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9245 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9246 int nallvars, /**< number of all variables */
9247 int nvars, /**< number of unfixed variables */
9248 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9249 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9250 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9251 )
9252{
9253 SCIP_Real maxerror;
9254 SCIP_Real facetval;
9255 SCIP_Real funval;
9256 SCIP_Real error;
9257 unsigned int i;
9258 unsigned int ncorners;
9259 unsigned int prev;
9260
9261 assert(scip != NULL);
9262 assert(funvals != NULL);
9263 assert(box != NULL);
9264 assert(nonfixedpos != NULL);
9265 assert(facetcoefs != NULL);
9266
9267 ncorners = POWEROFTWO(nvars);
9268 maxerror = 0.0;
9269
9270 /* check the origin (all variables at lower bound) */
9271 facetval = facetconstant;
9272 for( i = 0; i < (unsigned int) nallvars; ++i )
9273 facetval += facetcoefs[i] * box[2*i];
9274
9275 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9276 funval = funvals[0];
9277 if( overestimate )
9278 error = funval - facetval;
9279 else
9280 error = facetval - funval;
9281
9282 /* update maximum error */
9283 maxerror = MAX(error, maxerror);
9284
9285 prev = 0;
9286 for( i = 1; i < ncorners; ++i )
9287 {
9288 unsigned int gray;
9289 unsigned int diff;
9290 unsigned int pos;
9291 int origpos;
9292
9293 gray = i ^ (i >> 1);
9294 diff = gray ^ prev;
9295
9296 /* compute position of unique 1 of diff */
9297 pos = 0;
9298 while( (diff >>= 1) != 0 )
9299 ++pos;
9300 assert(pos < (unsigned int)nvars);
9301
9302 origpos = nonfixedpos[pos];
9303
9304 if( gray > prev )
9305 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9306 else
9307 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9308
9309 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9310 funval = funvals[gray];
9311 if( overestimate )
9312 error = funval - facetval;
9313 else
9314 error = facetval - funval;
9315
9316 /* update maximum error */
9317 maxerror = MAX(error, maxerror);
9318
9319 prev = gray;
9320 }
9321
9322 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9323
9324 return maxerror;
9325}
9326
9327/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9328static
9330 SCIP* scip, /**< SCIP data structure */
9331 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9332 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9333 SCIP_Real* xstar, /**< point to be separated */
9334 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9335 int nallvars, /**< half of the length of box */
9336 int* nonfixedpos, /**< indices of nonfixed variables */
9337 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9338 int nvars, /**< number of nonfixed variables */
9339 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9340 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9341 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9342 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9343 )
9344{ /*lint --e{715}*/
9345 SCIP_CONSHDLRDATA* conshdlrdata;
9346 SCIP_LPI* lp;
9347 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9348 int* inds;
9349 int ncols;
9350 int nrows;
9351 int i;
9352 SCIP_Real facetvalue;
9353 SCIP_Real mindomwidth;
9354 SCIP_RETCODE lpsolveretcode;
9355
9356 assert(scip != NULL);
9357 assert(conshdlr != NULL);
9358 assert(xstar != NULL);
9359 assert(box != NULL);
9360 assert(nonfixedpos != NULL);
9361 assert(funvals != NULL);
9362 assert(nvars >= 0);
9364 assert(success != NULL);
9365 assert(facetcoefs != NULL);
9366 assert(facetconstant != NULL);
9367
9368 *success = FALSE;
9369
9370 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9371 assert(conshdlrdata != NULL);
9372
9373 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9374 {
9375 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9376 }
9377
9378 /* construct an LP for this size, if not having one already */
9379 if( conshdlrdata->vp_lp[nvars] == NULL )
9380 {
9381 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9382 }
9383 lp = conshdlrdata->vp_lp[nvars];
9384 assert(lp != NULL);
9385
9386 /* get number of cols and rows of separation lp */
9387 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9388 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9389
9390 /* number of columns should equal the number of corners = 2^nvars */
9391 assert(ncols == (int)POWEROFTWO(nvars));
9392
9393 /* allocate necessary memory */
9394 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9395 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9396
9397 /*
9398 * set up the described LP on the transformed space
9399 */
9400
9401 for( i = 0; i < ncols; ++i )
9402 inds[i] = i;
9403
9404 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9405 mindomwidth = 2*SCIPinfinity(scip);
9406 for( i = 0; i < nrows-1; ++i )
9407 {
9408 SCIP_Real solval;
9409 SCIP_Real lb;
9410 SCIP_Real ub;
9411 int varpos;
9412
9413 assert(i < nvars);
9414
9415 varpos = nonfixedpos[i];
9416 lb = box[2 * varpos];
9417 ub = box[2 * varpos + 1];
9418 solval = xstar[varpos];
9419
9420 if( ub - lb < mindomwidth )
9421 mindomwidth = ub - lb;
9422
9423 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9424 if( solval <= lb )
9425 aux[i] = 0.0;
9426 else if( solval >= ub )
9427 aux[i] = 1.0;
9428 else
9429 aux[i] = (solval - lb) / (ub - lb);
9430
9431 /* perturb point to hopefully obtain a facet of the convex envelope */
9432 if( conshdlrdata->vp_maxperturb > 0.0 )
9433 {
9434 assert(conshdlrdata->vp_randnumgen != NULL);
9435
9436 if( aux[i] == 1.0 )
9437 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9438 else if( aux[i] == 0.0 )
9439 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9440 else
9441 {
9442 SCIP_Real perturbation;
9443
9444 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9445 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9446 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9447 }
9448 assert(0.0 < aux[i] && aux[i] < 1.0);
9449 }
9450
9451 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9452 }
9453
9454 /* update LP */
9455 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9456 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9458
9459 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9460 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9461 {
9462 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9463 }
9464 /* set an iteration limit so we do not run forever */
9466 /* 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 */
9468 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9469 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9470 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9471 */
9473
9474#ifdef SCIP_DEBUG
9476#endif
9477
9478 /*
9479 * solve the LP and store the resulting facet for the transformed space
9480 */
9481 if( conshdlrdata->vp_dualsimplex )
9482 {
9483 lpsolveretcode = SCIPlpiSolveDual(lp);
9484 }
9485 else
9486 {
9487 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9488 }
9489 if( lpsolveretcode == SCIP_LPERROR )
9490 {
9491 SCIPdebugMsg(scip, "LP error, aborting.\n");
9492 goto CLEANUP;
9493 }
9494 SCIP_CALL( lpsolveretcode );
9495
9496 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9497 if( !SCIPlpiIsDualFeasible(lp) )
9498 {
9499 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9500 goto CLEANUP;
9501 }
9502
9503 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9504 * columns than needed, in particular, \bar \beta is the last dual multiplier
9505 */
9506 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9507
9508 for( i = 0; i < nvars; ++i )
9509 facetcoefs[nonfixedpos[i]] = aux[i];
9510 /* last dual multiplier is the constant */
9511 *facetconstant = aux[nrows - 1];
9512
9513#ifdef SCIP_DEBUG
9514 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9515 for( i = 0; i < nallvars; ++i )
9516 {
9517 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9518 }
9519 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9520#endif
9521
9522 /*
9523 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9524 */
9525
9526 SCIPdebugMsg(scip, "facet in orig. space: ");
9527
9528 facetvalue = 0.0;
9529 for( i = 0; i < nvars; ++i )
9530 {
9531 SCIP_Real lb;
9532 SCIP_Real ub;
9533 int varpos;
9534
9535 varpos = nonfixedpos[i];
9536 lb = box[2 * varpos];
9537 ub = box[2 * varpos + 1];
9538 assert(!SCIPisEQ(scip, lb, ub));
9539
9540 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9541 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9542
9543 /* beta = beta_bar - sum_i alpha_i * lb_i */
9544 *facetconstant -= facetcoefs[varpos] * lb;
9545
9546 /* evaluate */
9547 facetvalue += facetcoefs[varpos] * xstar[varpos];
9548
9549 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9550 }
9551 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9552
9553 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9554 facetvalue += *facetconstant;
9555
9556 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9557
9558 /* if overestimate, then we want facetvalue < targetvalue
9559 * if underestimate, then we want facetvalue > targetvalue
9560 * if none holds, give up
9561 * so maybe here we should check against the minimal violation
9562 */
9563 if( overestimate == (facetvalue > targetvalue) )
9564 {
9565 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9566 goto CLEANUP;
9567 }
9568
9569 /* if we made it until here, then we have a nice facet */
9570 *success = TRUE;
9571
9572CLEANUP:
9573 /* free allocated memory */
9574 SCIPfreeBufferArray(scip, &inds);
9576
9577 return SCIP_OKAY;
9578}
9579
9580/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9581 *
9582 * In other words, compute the line that passes through two given points.
9583 */
9584static
9586 SCIP* scip, /**< SCIP data structure */
9587 SCIP_Real left, /**< left coordinate */
9588 SCIP_Real right, /**< right coordinate */
9589 SCIP_Real funleft, /**< value of function in left coordinate */
9590 SCIP_Real funright, /**< value of function in right coordinate */
9591 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9592 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9593 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9594 )
9595{
9596 assert(scip != NULL);
9597 assert(SCIPisLE(scip, left, right));
9598 assert(!SCIPisInfinity(scip, -left));
9599 assert(!SCIPisInfinity(scip, right));
9600 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9601 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9602 assert(success != NULL);
9603 assert(facetcoef != NULL);
9604 assert(facetconstant != NULL);
9605
9606 *facetcoef = (funright - funleft) / (right - left);
9607 *facetconstant = funleft - *facetcoef * left;
9608
9609 *success = TRUE;
9610
9611 return SCIP_OKAY;
9612}
9613
9614/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9615 *
9616 * Three points a, b, and c are given.
9617 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9618 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9619 */
9620static
9622 SCIP* scip, /**< SCIP data structure */
9623 SCIP_Real a1, /**< first coordinate of a */
9624 SCIP_Real a2, /**< second coordinate of a */
9625 SCIP_Real a3, /**< third coordinate of a */
9626 SCIP_Real b1, /**< first coordinate of b */
9627 SCIP_Real b2, /**< second coordinate of b */
9628 SCIP_Real b3, /**< third coordinate of b */
9629 SCIP_Real c1, /**< first coordinate of c */
9630 SCIP_Real c2, /**< second coordinate of c */
9631 SCIP_Real c3, /**< third coordinate of c */
9632 SCIP_Real* alpha, /**< coefficient of first coordinate */
9633 SCIP_Real* beta, /**< coefficient of second coordinate */
9634 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9635 SCIP_Real* delta /**< constant right-hand side */
9636 )
9637{
9638 assert(scip != NULL);
9639 assert(alpha != NULL);
9640 assert(beta != NULL);
9641 assert(gamma_ != NULL);
9642 assert(delta != NULL);
9643
9644 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9645 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9646 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9647 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9648
9649 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9650
9651 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9652 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9653 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9654 {
9655 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9656 *delta = 0.0;
9657 *alpha = 0.0;
9658 *beta = 0.0;
9659 *gamma_ = 0.0;
9660 return SCIP_OKAY;
9661 }
9662
9663 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9664 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9665 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9666 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9667 {
9668 SCIP_Real m[9];
9669 SCIP_Real rhs[3];
9670 SCIP_Real x[3];
9671 SCIP_Bool success;
9672
9673 /*
9674 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));
9675 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));
9676 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));
9677 */
9678
9679 /* initialize matrix column-wise */
9680 m[0] = a1;
9681 m[1] = b1;
9682 m[2] = c1;
9683 m[3] = a2;
9684 m[4] = b2;
9685 m[5] = c2;
9686 m[6] = a3;
9687 m[7] = b3;
9688 m[8] = c3;
9689
9690 rhs[0] = 1.0;
9691 rhs[1] = 1.0;
9692 rhs[2] = 1.0;
9693
9694 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9695
9696 /* solve the linear problem */
9697 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9698
9699 *delta = rhs[0];
9700 *alpha = x[0];
9701 *beta = x[1];
9702 *gamma_ = x[2];
9703
9704 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9705 * not add a cut to SCIP and that all assertions are trivially fulfilled
9706 */
9707 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9708 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9709 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9710 {
9711 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9712 *delta = 0.0;
9713 *alpha = 0.0;
9714 *beta = 0.0;
9715 *gamma_ = 0.0;
9716 }
9717 }
9718
9719 if( *gamma_ < 0.0 )
9720 {
9721 *alpha = -*alpha;
9722 *beta = -*beta;
9723 *gamma_ = -*gamma_;
9724 *delta = -*delta;
9725 }
9726
9727 return SCIP_OKAY;
9728}
9729
9730/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9731static
9733 SCIP* scip, /**< SCIP data structure */
9734 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9735 SCIP_Real p1[2], /**< first vertex of box */
9736 SCIP_Real p2[2], /**< second vertex of box */
9737 SCIP_Real p3[2], /**< third vertex of box */
9738 SCIP_Real p4[2], /**< forth vertex of box */
9739 SCIP_Real p1val, /**< value in p1 */
9740 SCIP_Real p2val, /**< value in p2 */
9741 SCIP_Real p3val, /**< value in p3 */
9742 SCIP_Real p4val, /**< value in p4 */
9743 SCIP_Real xstar[2], /**< point to be separated */
9744 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9745 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9746 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9747 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9748 )
9749{
9750 SCIP_Real alpha, beta, gamma_, delta;
9751 SCIP_Real xstarval, candxstarval = 0.0;
9752 int leaveout;
9753
9754 assert(scip != NULL);
9755 assert(success != NULL);
9756 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9757 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9758 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9759 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9760 assert(facetcoefs != NULL);
9761 assert(facetconstant != NULL);
9762
9763 *success = FALSE;
9764
9765 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9766 if( !overestimate )
9767 {
9768 p1val = -p1val;
9769 p2val = -p2val;
9770 p3val = -p3val;
9771 p4val = -p4val;
9772 targetvalue = -targetvalue;
9773 }
9774
9775 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9776 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9777 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9778 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9779
9780 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9781 * alpha*x + beta*y + gamma*z = delta
9782 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9783 * the fourth corner point lies below this hyperplane.
9784 * 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.,
9785 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9786 * or, equivalently,
9787 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9788 */
9789 for( leaveout = 1; leaveout <= 4; ++leaveout )
9790 {
9791 switch( leaveout)
9792 {
9793 case 1 :
9794 /* get hyperplane through p2, p3, p4 */
9795 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9796 &alpha, &beta, &gamma_, &delta) );
9797 /* if not underestimating in p1, then go to next candidate */
9798 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9799 continue;
9800 break;
9801
9802 case 2 :
9803 /* get hyperplane through p1, p3, p4 */
9804 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9805 &alpha, &beta, &gamma_, &delta) );
9806 /* if not underestimating in p2, then go to next candidate */
9807 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9808 continue;
9809 break;
9810
9811 case 3 :
9812 /* get hyperplane through p1, p2, p4 */
9813 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9814 &alpha, &beta, &gamma_, &delta) );
9815 /* if not underestimating in p3, then go to next candidate */
9816 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9817 continue;
9818 break;
9819
9820 case 4 :
9821 /* get hyperplane through p1, p2, p3 */
9822 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9823 &alpha, &beta, &gamma_, &delta) );
9824 /* if not underestimating in p4, then stop */
9825 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9826 continue;
9827 break;
9828
9829 default: /* only for lint */
9831 beta = SCIP_INVALID;
9832 gamma_ = SCIP_INVALID;
9833 delta = SCIP_INVALID;
9834 break;
9835 }
9836
9837 /* check if bad luck: should not happen if numerics are fine */
9838 if( SCIPisZero(scip, gamma_) )
9839 continue;
9840 assert(!SCIPisNegative(scip, gamma_));
9841
9842 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9843 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9844 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9845 continue;
9846
9847 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9848
9849 /* value of hyperplane candidate in xstar */
9850 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9851
9852 /* if reaching target and first or better than previous candidate, then update */
9853 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9854 {
9855 /* flip hyperplane */
9856 if( !overestimate )
9857 gamma_ = -gamma_;
9858
9859 facetcoefs[0] = -alpha/gamma_;
9860 facetcoefs[1] = -beta/gamma_;
9861 *facetconstant = delta/gamma_;
9862
9863 *success = TRUE;
9864 candxstarval = xstarval;
9865 }
9866 }
9867
9868 return SCIP_OKAY;
9869}
9870
9871/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9872 * graph yet) in an array
9873 */
9874static
9876 SCIP* scip, /**< SCIP pointer */
9877 int** openidx, /**< address of openidx array */
9878 int nelems, /**< number of elements that need to be stored */
9879 int* maxnelems /**< pointer to store maximum number that can be stored */
9880 )
9881{
9882 assert(scip != NULL);
9883 assert(openidx != NULL);
9884 assert(maxnelems != NULL);
9885
9886 if( nelems > *maxnelems )
9887 {
9888 int newsize;
9889
9890 newsize = SCIPcalcMemGrowSize(scip, nelems);
9891 assert(newsize >= nelems);
9892
9893 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9894
9895 *maxnelems = newsize;
9896 }
9897
9898 return SCIP_OKAY;
9899}
9900
9901/** ensures that we can store information about local variables in an array */
9902static
9904 SCIP* scip, /**< SCIP pointer */
9905 SCIP_VAR*** vars, /**< address of variable array */
9906 SCIP_Real** vals, /**< address of value array */
9907 int nelems, /**< number of elements that need to be stored */
9908 int* maxnelems /**< pointer to store maximum number that can be stored */
9909 )
9910{
9911 assert(scip != NULL);
9912 assert(vars != NULL);
9913 assert(vals != NULL);
9914 assert(maxnelems != NULL);
9915
9916 if( nelems > *maxnelems )
9917 {
9918 int newsize;
9919
9920 newsize = SCIPcalcMemGrowSize(scip, nelems);
9921 assert(newsize > *maxnelems);
9922
9924 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9925
9926 *maxnelems = newsize;
9927 }
9928
9929 return SCIP_OKAY;
9930}
9931
9932/** tries to add gadget for finding signed permutations of bilinear products
9933 *
9934 * If a product has exactly two children being variables, negating both simultanteoulsy
9935 * is a signed permutation.
9936 */
9937static
9939 SCIP* scip, /**< SCIP pointer */
9940 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9941 SCIP_CONS* cons, /**< constraint containing product expression */
9942 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9943 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9944 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9945 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9946 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9947 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9948 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9949 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9950 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9951 )
9952{
9953 SYM_EXPRDATA* symdata;
9954 SCIP_EXPR** children;
9955 SCIP_VAR* var1 = NULL;
9956 SCIP_VAR* var2 = NULL;
9957 SCIP_Real val1 = 0.0;
9958 SCIP_Real val2 = 0.0;
9959 SCIP_Real coef;
9960 SCIP_Real prodval;
9961 SCIP_Real constant;
9962 int nlocvars;
9963 int optype;
9964 int nchildren;
9965 int prodidx;
9966 int coefidx1;
9967 int coefidx2;
9968 int childidx;
9969
9970 assert(scip != NULL);
9971 assert(expr != NULL);
9973 assert(graph != NULL);
9974 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9975 assert(consvars != NULL);
9976 assert(consvals != NULL);
9977 assert(maxnconsvars != NULL);
9978 assert(*maxnconsvars > 0);
9979 assert(handledexprs != NULL);
9980 assert(success != NULL);
9981
9982 *success = FALSE;
9983
9984 /* we require exactly two children being variables */
9985 nchildren = SCIPexprGetNChildren(expr);
9986 if( nchildren != 2 )
9987 return SCIP_OKAY;
9988
9989 children = SCIPexprGetChildren(expr);
9990 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9991 return SCIP_OKAY;
9992
9993 /* check whether each child is not multi-aggregated and is not shifted */
9994 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9995
9996 for( childidx = 0; childidx < 2; ++childidx )
9997 {
9998 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9999 (*consvals)[0] = 1.0;
10000 nlocvars = 1;
10001 constant = 0.0;
10002
10003 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
10004 &constant, SCIPconsIsTransformed(cons)) );
10005
10006 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10007 return SCIP_OKAY;
10008
10009 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
10010 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
10011 return SCIP_OKAY;
10012
10013 /* store information about variables */
10014 if( childidx == 0 )
10015 {
10016 var1 = (*consvars)[0];
10017 val1 = (*consvals)[0];
10018 }
10019 else
10020 {
10021 var2 = (*consvars)[0];
10022 val2 = (*consvals)[0];
10023 }
10024 }
10025 assert(var1 != NULL);
10026 assert(var2 != NULL);
10027
10028 /* store the we handle the children */
10029 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
10030 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
10031
10032 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10033 assert(symdata != NULL);
10034 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10035
10036 coef = SCIPgetSymExprdataConstants(symdata)[0];
10037
10038 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10039
10040 /* add gadget modeling the product
10041 *
10042 * Since the constants are 0, each variable is centered at the origin, which leads to
10043 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
10044 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
10045 * negate both variables simulataneously.
10046 */
10048 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
10049 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
10050
10051 prodval = coef * val1 * val2;
10052
10053 /* introduce nodes for the product value and its negation; since flipping both variables
10054 * simultaneously is a signed symmetry, assign both nodes the same value
10055 */
10056 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
10057 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
10058
10059 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
10060 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
10061 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
10062
10063 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10064 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10065 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10066 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10067 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10068 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10069 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10070 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10071
10072 *success = TRUE;
10073
10074 return SCIP_OKAY;
10075}
10076
10077/** returns whether an operator is even and, if yes, stores data about operator */
10078static
10080 SCIP* scip, /**< SCIP pointer */
10081 SCIP_EXPR* expr, /**< expression corresponding to operator */
10082 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
10083 * needed for symmetry computation */
10084 SCIP_Real* value /**< pointer to store value for symmetry computation */
10085 )
10086{
10087 SYM_EXPRDATA* symdata;
10088
10089 assert(scip != NULL);
10090 assert(expr != NULL);
10091 assert(hasvalue != NULL);
10092 assert(value != NULL);
10093
10094 /* check for different operators known to be even */
10095 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
10096 {
10097 /* get remaining information needed for symmetry detection */
10098 if( SCIPisExprSignpower(scip, expr) )
10099 {
10100 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10101 assert(symdata != NULL);
10102 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10103
10104 *value = SCIPgetSymExprdataConstants(symdata)[0];
10105 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
10106
10108 }
10109 else
10110 {
10111 assert(SCIPisExprCos(scip, expr));
10112 *hasvalue = FALSE;
10113 }
10114
10115 return TRUE;
10116 }
10117 else if( SCIPisExprPower(scip, expr) )
10118 {
10119 SCIP_Real exponent;
10120 int safeexponent;
10121
10122 /* only consider expressions corresponding to an even power */
10123 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10124 assert(symdata != NULL);
10125 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10126
10127 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10129
10130 /* check whether the exponent is an even integer */
10131 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
10132 return FALSE;
10133
10134 /* deal with numerics */
10135 safeexponent = (int) (exponent + 0.5);
10136 if( safeexponent % 2 != 0 )
10137 return FALSE;
10138
10139 *hasvalue = TRUE;
10140 *value = exponent;
10141
10142 return TRUE;
10143 }
10144 else if( SCIPisExprAbs(scip, expr) )
10145 {
10146 *hasvalue = FALSE;
10147
10148 return TRUE;
10149 }
10150
10151 return FALSE;
10152}
10153
10154/** returns whether a variable is centered at 0 */
10155static
10157 SCIP* scip, /**< SCIP pointer */
10158 SCIP_VAR* var /**< variable to be checked */
10159 )
10160{
10161 assert(scip != NULL);
10162 assert(var != NULL);
10163
10165 return FALSE;
10166
10168 return TRUE;
10169
10171 return TRUE;
10172
10173 return FALSE;
10174}
10175
10176/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
10177static
10179 SCIP* scip, /**< SCIP pointer */
10180 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10181 SCIP_EXPR* child, /**< child expression of evenopexpr */
10182 SCIP_CONS* cons, /**< constraint containing expression */
10183 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10184 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10185 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10186 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10187 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10188 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10189 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10190 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10191 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10192 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10193 )
10194{
10195 SCIP_VAR* var;
10196 SCIP_Real constant;
10197 SCIP_Real edgeweight;
10198 int nlocvars;
10199 int nodeidx;
10200 int optype;
10201 int thisopidx;
10202
10203 assert(scip != NULL);
10204 assert(evenopexpr != NULL);
10205 assert(child != NULL);
10206 assert(SCIPisExprVar(scip, child));
10207 assert(cons != NULL);
10208 assert(graph != NULL);
10209 assert(parentidx >= 0);
10210 assert(consvars != NULL);
10211 assert(consvals != NULL);
10212 assert(maxnconsvars != NULL);
10213 assert(success != NULL);
10214
10215 *success = FALSE;
10216
10217 /* check whether child variable is (multi-)aggregated */
10218 var = SCIPgetVarExprVar(child);
10219 (*consvars)[0] = var;
10220 (*consvals)[0] = 1.0;
10221 constant = 0.0;
10222 nlocvars = 1;
10223
10224 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10225 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10226 SCIPconsIsTransformed(cons)) );
10227
10228 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10229 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10230 return SCIP_OKAY;
10231
10232 if( !varIsCenteredAt0(scip, var) )
10233 return SCIP_OKAY;
10234
10235 /* store partial information for gadget */
10236 var = (*consvars)[0];
10237 edgeweight = (*consvals)[0];
10238
10239 /* add gadget to graph for even univariate expression */
10240 *success = TRUE;
10241
10243
10244 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10245 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10246
10248 TRUE, edgeweight) );
10250 TRUE, edgeweight) );
10251
10252 if( hassymval )
10253 {
10254 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10255 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10256 }
10257
10258 return SCIP_OKAY;
10259}
10260
10261/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10262static
10264 SCIP* scip, /**< SCIP pointer */
10265 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10266 SCIP_EXPR* child, /**< child expression of evenopexpr */
10267 SCIP_CONS* cons, /**< constraint containing expression */
10268 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10269 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10270 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10271 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10272 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10273 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10274 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10275 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10276 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10277 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10278 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10279 )
10280{
10281 SCIP_VAR* var;
10282 SCIP_Real constant;
10283 SCIP_Real weight;
10284 int nlocvars;
10285 int nodeidx;
10286 int optype;
10287 int thisopidx;
10288 int i;
10289
10290 assert(scip != NULL);
10291 assert(evenopexpr != NULL);
10292 assert(child != NULL);
10293 assert(SCIPisExprSum(scip, child));
10294 assert(cons != NULL);
10295 assert(graph != NULL);
10296 assert(parentidx >= 0);
10297 assert(consvars != NULL);
10298 assert(consvals != NULL);
10299 assert(maxnconsvars != NULL);
10300 assert(handledexprs != NULL);
10301 assert(success != NULL);
10302
10303 *success = FALSE;
10304
10305 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10306 nlocvars = SCIPexprGetNChildren(child);
10307
10308 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10309
10310 for( i = 0; i < nlocvars; ++i)
10311 {
10312 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10313 {
10314 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10315 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10316 }
10317 else
10318 return SCIP_OKAY;
10319 }
10320 constant = SCIPgetConstantExprSum(child);
10321
10322 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10323 SCIPconsIsTransformed(cons)) );
10324
10325 /* we can only handle the case without constant and two variables with domain centered at origin */
10326 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10327 return SCIP_OKAY;
10328 assert(nlocvars > 0);
10329
10330 var = (*consvars)[0];
10331 if( !varIsCenteredAt0(scip, var) )
10332 return SCIP_OKAY;
10333
10334 if( nlocvars == 2 )
10335 {
10336 var = (*consvars)[1];
10337 if( !varIsCenteredAt0(scip, var) )
10338 return SCIP_OKAY;
10339 }
10340
10341 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10342 *success = TRUE;
10343 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10344 {
10345 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10346 }
10347
10349
10350 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10351 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10352
10353 if( hassymval )
10354 {
10355 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10356 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10357 }
10358
10359 if( nlocvars == 1 )
10360 {
10361 var = (*consvars)[0];
10362 weight = (*consvals)[0];
10363
10365 TRUE, weight) );
10367 TRUE, weight) );
10368 }
10369 else
10370 {
10371 int dummyidx1;
10372 int dummyidx2;
10373
10374 /* add dummy nodes for gadget */
10375 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10376 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10377
10378 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10379 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10380 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10381
10382 /* connect dummy nodes with variables */
10383 for( i = 0; i < 2; ++i)
10384 {
10385 var = (*consvars)[i];
10386 weight = ABS((*consvals)[i]);
10387
10389 TRUE, weight) );
10391 TRUE, weight) );
10392 }
10393 }
10394
10395 return SCIP_OKAY;
10396}
10397
10398/** tries to add gadget for finding signed permutations of even univariate operators
10399 *
10400 * We handle two cases. First, if a univariate operator is even and has a variable
10401 * as child, negating the child is signed permutation. Second, the univariate operator
10402 * is even and has a weighted sum of two variables as child.
10403 */
10404static
10406 SCIP* scip, /**< SCIP pointer */
10407 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10408 SCIP_CONS* cons, /**< constraint containing expression */
10409 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10410 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10411 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10412 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10413 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10414 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10415 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10416 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10417 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10418 )
10419{
10420 SCIP_EXPR* child;
10421 SCIP_Real val = 0.0;
10422 SCIP_Bool hasval = FALSE;
10423
10424 assert(scip != NULL);
10425 assert(expr != NULL);
10426 assert(graph != NULL);
10427 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10428 assert(consvars != NULL);
10429 assert(consvals != NULL);
10430 assert(maxnconsvars != NULL);
10431 assert(*maxnconsvars > 0);
10432 assert(handledexprs != NULL);
10433 assert(success != NULL);
10434
10435 *success = FALSE;
10436
10437 /* ignore variable or value expressions */
10438 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10439 return SCIP_OKAY;
10440 assert(SCIPexprGetNChildren(expr) > 0);
10441
10442 /* ignore operators with too many children */
10443 if( SCIPexprGetNChildren(expr) > 1 )
10444 return SCIP_OKAY;
10445
10446 /* check whether operator is even */
10447 if( !isEvenOperator(scip, expr, &hasval, &val) )
10448 return SCIP_OKAY;
10449
10450 /* we can only treat the operator if its child is a variable or a sum */
10451 child = SCIPexprGetChildren(expr)[0];
10452 if( SCIPisExprVar(scip, child) )
10453 {
10454 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10455 hasval, val, consvars, consvals, maxnconsvars, success) );
10456 }
10457 else if( SCIPisExprSum(scip, child) )
10458 {
10459 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10460 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10461 }
10462
10463 if( *success )
10464 {
10465 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10466 }
10467
10468 return SCIP_OKAY;
10469}
10470
10471/** compares two variable pointers */
10472static
10474{ /*lint --e{715}*/
10475 SCIP_VAR** vars;
10476 SCIP_VAR* var1;
10477 SCIP_VAR* var2;
10478
10479 vars = (SCIP_VAR**) dataptr;
10480
10481 var1 = vars[ind1];
10482 var2 = vars[ind2];
10483 assert(var1 != NULL);
10484 assert(var2 != NULL);
10485
10486 /* sort variables by their unique index */
10487 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10488 return -1;
10489 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10490 return 1;
10491
10492 return 0;
10493}
10494
10495/** gets domain center of a variable which has not semi-infinite domain */
10496static
10498 SCIP* scip, /**< SCIP pointer */
10499 SCIP_VAR* var /**< variable */
10500 )
10501{
10502 SCIP_Real ub;
10503 SCIP_Real lb;
10504
10505 ub = SCIPvarGetUbGlobal(var);
10506 lb = SCIPvarGetLbGlobal(var);
10507
10508 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10509
10510 if ( SCIPisInfinity(scip, ub) )
10511 return 0.0;
10512
10513 return (ub + lb) / 2;
10514}
10515
10516/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10517static
10519 SCIP* scip, /**< SCIP pointer */
10520 SCIP_EXPR* sumexpr, /**< sum expression */
10521 SCIP_CONS* cons, /**< constraint containing the sum expression */
10522 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10523 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10524 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10525 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10526 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10527 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10528 )
10529{
10530 SYM_EXPRDATA* symdata;
10531 SCIP_EXPR** children;
10532 SCIP_EXPR** powexprs;
10533 SCIP_EXPR** prodexprs;
10534 SCIP_EXPR* child;
10535 SCIP_VAR** powvars;
10536 SCIP_VAR** prodvars;
10537 SCIP_VAR* actvar;
10538 SCIP_VAR* actvar2;
10539 SCIP_VAR* var;
10540 SCIP_VAR* var2;
10541 SCIP_Real* sumcoefs;
10542 SCIP_Real constant;
10543 SCIP_Real constant2;
10544 SCIP_Real val;
10545 SCIP_Real val2;
10546 SCIP_Bool* powexprused = NULL;
10547 int* powperm = NULL;
10548 int* prodperm = NULL;
10549 int nchildren;
10550 int nlocvars;
10551 int nodeidx;
10552 int coefnodeidx1;
10553 int coefnodeidx2;
10554 int cnt;
10555 int i;
10556 int j;
10557 int nterms;
10558 int npowexprs = 0;
10559 int nprodexprs = 0;
10560 int powcoef = 0;
10561
10562 assert(scip != NULL);
10563 assert(sumexpr != NULL);
10564 assert(cons != NULL);
10565 assert(SCIPisExprSum(scip, sumexpr));
10566 assert(consvars != NULL);
10567 assert(consvals != NULL);
10568 assert(maxnconsvars != NULL);
10569 assert(*maxnconsvars > 0);
10570 assert(handledexprs != NULL);
10571
10572 /* iterate over sum expression and extract all power and product expressions */
10573 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10574 children = SCIPexprGetChildren(sumexpr);
10575 nchildren = SCIPexprGetNChildren(sumexpr);
10576 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10577 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10578 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10579 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10580
10581 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10582 /** @todo make this work in a more general case */
10583 for( i = 0; i < nchildren; ++i )
10584 {
10585 if( SCIPisExprPower(scip, children[i]) )
10586 {
10587 SCIP_Real exponent;
10588
10589 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10590 if( powcoef == 0 )
10591 {
10592 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10593 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10594 }
10595 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10596 continue;
10597
10598 /* we only store power expressions if their child is a variable */
10599 assert(SCIPexprGetNChildren(children[i]) == 1);
10600 child = SCIPexprGetChildren(children[i])[0];
10601 if( !SCIPisExprVar(scip, child) )
10602 continue;
10603
10604 /* the power is required to be a 2 */
10605 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10606 assert(symdata != NULL);
10607 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10608
10609 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10610 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10611
10612 if( !SCIPisEQ(scip, exponent, 2.0) )
10613 continue;
10614
10615 /* we only store power expressions if the child is not multi-aggregated */
10616 var = SCIPgetVarExprVar(child);
10618 {
10619 powexprs[npowexprs] = children[i];
10620 powvars[npowexprs++] = var;
10621 }
10622 }
10623 else if( SCIPisExprProduct(scip, children[i]) )
10624 {
10625 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10626 if( powcoef == 0 )
10627 {
10628 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10629 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10630 }
10631 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10632 continue;
10633
10634 /* we only store power expressions if they have exactly two children being variables */
10635 if( SCIPexprGetNChildren(children[i]) != 2 )
10636 continue;
10637 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10638 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10639 continue;
10640
10641 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10642 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10643
10644 /* we only store product expressions if the children are not multi-aggregated */
10647 {
10648 prodexprs[nprodexprs] = children[i];
10649 prodvars[nprodexprs++] = var;
10650 prodexprs[nprodexprs] = children[i];
10651 prodvars[nprodexprs++] = var2;
10652 }
10653 }
10654 }
10655
10656 if( npowexprs == 0 || nprodexprs != npowexprs )
10657 goto FREEMEMORY;
10658
10659 /* check whether the power variables and product variables match */
10660 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10661 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10662
10663 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10664 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10665
10666 for( i = 0; i < npowexprs; ++i )
10667 {
10668 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10669 goto FREEMEMORY;
10670 }
10671
10672 /* if we reach this line, the variables match: we have found a potential norm constraint */
10673 assert(npowexprs % 2 == 0);
10674 nterms = npowexprs / 2;
10675 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10676
10677 /* add gadget of each squared difference term */
10678 cnt = 0;
10679 for( i = 0; i < nterms; ++i )
10680 {
10681 SCIP_Bool var1found = FALSE;
10682 SCIP_Bool var2found = FALSE;
10683
10684 (*consvals)[0] = 1.0;
10685 (*consvars)[0] = prodvars[cnt++];
10686 constant = 0.0;
10687 nlocvars = 1;
10688
10690 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10691
10692 if( nlocvars != 1 )
10693 {
10694 ++cnt;
10695 continue;
10696 }
10697 actvar = (*consvars)[0];
10698 val = (*consvals)[0];
10699
10700 (*consvals)[0] = 1.0;
10701 (*consvars)[0] = prodvars[cnt++];
10702 constant2 = 0.0;
10703 nlocvars = 1;
10704
10706 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10707
10708 if( nlocvars != 1 )
10709 continue;
10710 actvar2 = (*consvars)[0];
10711 val2 = (*consvals)[0];
10712
10713 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10714 * cannot be centered at the origin or they are not centered around the same point
10715 */
10716 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10720 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10721 continue;
10722
10723 /* add gadget */
10724 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10725 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10726 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10727
10728 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10729 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10730 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10731 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10732 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10733 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10734 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10735 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10736 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10737 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10738 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10739
10740 /* mark product expression as handled */
10741 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10742
10743 /* find corresponding unused power expressions and mark them as handled */
10744 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10745 {
10746 if( powexprused[j] )
10747 continue;
10748 assert(cnt >= 2);
10749
10750 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10751 {
10752 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10753 powexprused[j] = TRUE;
10754 var1found = TRUE;
10755 }
10756 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10757 {
10758 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10759 powexprused[j] = TRUE;
10760 var2found = TRUE;
10761 }
10762 }
10763 }
10764
10765 FREEMEMORY:
10766 SCIPfreeBufferArrayNull(scip, &powexprused);
10767 SCIPfreeBufferArrayNull(scip, &prodperm);
10768 SCIPfreeBufferArrayNull(scip, &powperm);
10769 SCIPfreeBufferArray(scip, &prodvars);
10770 SCIPfreeBufferArray(scip, &powvars);
10771 SCIPfreeBufferArray(scip, &prodexprs);
10772 SCIPfreeBufferArray(scip, &powexprs);
10773
10774 return SCIP_OKAY;
10775}
10776
10777/** adds symmetry information of constraint to a symmetry detection graph */
10778static
10780 SCIP* scip, /**< SCIP pointer */
10781 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10782 SCIP_CONS* cons, /**< constraint */
10783 SYM_GRAPH* graph, /**< symmetry detection graph */
10784 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10785 )
10786{ /*lint --e{850}*/
10787 SCIP_EXPRITER* it;
10788 SCIP_HASHSET* handledexprs;
10789 SCIP_EXPR* rootexpr;
10790 SCIP_EXPR* expr;
10791 SCIP_VAR** consvars;
10792 SCIP_Real* consvals;
10793 SCIP_Real constant;
10794 SCIP_Real parentcoef = 0.0;
10795 int* openidx;
10796 int maxnopenidx;
10797 int parentidx;
10798 int nconsvars;
10799 int maxnconsvars;
10800 int nlocvars;
10801 int nopenidx = 0;
10802 int consnodeidx;
10803 int nodeidx;
10804 int i;
10805 SCIP_Bool iscolored;
10806 SCIP_Bool hasparentcoef;
10807
10808 assert(scip != NULL);
10809 assert(cons != NULL);
10810 assert(graph != NULL);
10811 assert(success != NULL);
10812
10813 /* store lhs/rhs */
10815 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10816
10817 rootexpr = SCIPgetExprNonlinear(cons);
10818 assert(rootexpr != NULL);
10819
10820 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10821 expr = SCIPgetExprNonlinear(cons);
10822 assert(expr != NULL);
10823
10827
10828 /* find potential number of nodes in graph */
10829 maxnopenidx = 0;
10830 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10831 {
10833 continue;
10834
10835 ++maxnopenidx;
10836 }
10837
10838 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10839
10840 maxnconsvars = SCIPgetNVars(scip);
10841 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10842 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10843
10844 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10845 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10846
10847 /* iterate over expression tree and store nodes/edges */
10848 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10851
10852 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10853 {
10854 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10855 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10856 {
10857 SCIP_EXPR* baseexpr;
10858
10859 baseexpr = expr;
10860 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10861 expr = SCIPexpriterGetNext(it);
10862
10863 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10864
10865 /* leave the expression */
10866 continue;
10867 }
10868
10869 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10871 {
10872 --nopenidx;
10873 continue;
10874 }
10876
10877 /* find parentidx */
10878 if( expr == rootexpr )
10879 parentidx = consnodeidx;
10880 else
10881 {
10882 assert(nopenidx >= 1);
10883 parentidx = openidx[nopenidx - 1];
10884 }
10885
10886 /* possibly find a coefficient assigned to the expression by the parent */
10887 hasparentcoef = FALSE;
10888 if ( expr != rootexpr )
10889 {
10890 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10891 }
10892
10893 /* deal with different kinds of expressions and store them in the symmetry data structure */
10894 if( SCIPisExprVar(scip, expr) )
10895 {
10896 /* needed to correctly reset value when leaving expression */
10897 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10898
10899 openidx[nopenidx++] = -1;
10900
10901 assert(maxnconsvars > 0);
10902 assert(parentidx > 0);
10903
10904 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10905 if( hasparentcoef )
10906 {
10907 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10908
10909 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10910 parentidx = nodeidx;
10911 }
10912
10913 /* connect (aggregation of) variable expression with its parent */
10914 nconsvars = 1;
10915 consvars[0] = SCIPgetVarExprVar(expr);
10916 consvals[0] = 1.0;
10917 constant = 0.0;
10918
10919 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10920 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10921
10922 /* check whether variable is aggregated */
10923 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10924 {
10925 int thisidx;
10926
10927 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10928 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10929
10930 parentidx = thisidx;
10931 }
10932 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10933 nconsvars, constant) );
10934 }
10935 else if( SCIPisExprValue(scip, expr) )
10936 {
10937 assert(parentidx > 0);
10938
10939 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10940
10941 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10942
10943 /* needed to correctly reset value when leaving expression */
10944 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10945
10946 openidx[nopenidx++] = -1;
10947 }
10948 else
10949 {
10950 SCIP_Bool usedefaultgadget = TRUE;
10951
10952 assert(expr == rootexpr || parentidx > 0);
10953 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10954
10955 if( SCIPisExprSum(scip, expr) )
10956 {
10957 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10958 SCIP_EXPR** children;
10959 int sumidx;
10960 int optype;
10961 int childidx;
10962
10963 /* sums are handled by a special gadget */
10964 usedefaultgadget = FALSE;
10965
10966 /* extract all children being variables and compute the sum of active variables expression */
10967 nlocvars = 0;
10968 children = SCIPexprGetChildren(expr);
10969
10970 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10971
10972 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10973 {
10974 if( !SCIPisExprVar(scip, children[childidx]) )
10975 continue;
10976
10977 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10978 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10979
10980 /* store that we have already handled this expression */
10981 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10982 }
10983
10984 constant = SCIPgetConstantExprSum(expr);
10985
10986 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10987 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10988
10990
10991 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10992 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10993
10994 /* add the linear part of the sum */
10995 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10996
10997 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10998
10999 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
11000 if( symtype == SYM_SYMTYPE_SIGNPERM )
11001 {
11002 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
11003 &consvars, &consvals, &maxnconsvars, handledexprs) );
11004 }
11005
11006 /* store sumidx for children that have not been treated */
11007 openidx[nopenidx++] = sumidx;
11008 }
11009 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
11010 {
11011 SCIP_Bool succ;
11012
11013 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
11014 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
11015
11016 if( succ )
11017 {
11018 usedefaultgadget = FALSE;
11019 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
11020 }
11021 }
11022 else if( symtype == SYM_SYMTYPE_SIGNPERM )
11023 {
11024 SCIP_Bool succ;
11025
11026 /* we can find more signed permutations for even univariate operators */
11027 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
11028 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
11029
11030 if( succ )
11031 {
11032 usedefaultgadget = FALSE;
11033 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
11034 }
11035 }
11036
11037 if( usedefaultgadget )
11038 {
11039 int opidx;
11040 int optype;
11041
11043 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
11044 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
11045
11046 /* possibly add constants of expression */
11048 {
11049 SYM_EXPRDATA* symdata;
11050
11051 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
11052 assert(symdata != NULL);
11053
11054 /* if expression has multiple constants, assign colors to edges to distinguish them */
11055 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
11056 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
11057 {
11058 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
11059 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
11060 }
11061
11062 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
11063 }
11064
11065 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
11066
11067 openidx[nopenidx++] = opidx;
11068 }
11069 }
11070 }
11071
11072 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
11073 SCIPfreeBufferArray(scip, &consvals);
11074 SCIPfreeBufferArray(scip, &consvars);
11075 SCIPfreeBufferArray(scip, &openidx);
11076 SCIPfreeExpriter(&it);
11077
11078 *success = TRUE;
11079
11080 return SCIP_OKAY;
11081}
11082
11083/*
11084 * Callback methods of constraint handler
11085 */
11086
11087/** copy method for constraint handler plugins (called when SCIP copies plugins) */
11088static
11089SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
11090{ /*lint --e{715}*/
11091 SCIP_CONSHDLR* targetconshdlr;
11092 SCIP_CONSHDLRDATA* sourceconshdlrdata;
11093 int i;
11094
11095 assert(scip != NULL);
11096 assert(conshdlr != NULL);
11097 assert(valid != NULL);
11098 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11099
11100 /* create basic data of constraint handler and include it to scip */
11102
11103 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11104 assert(targetconshdlr != NULL);
11105 assert(targetconshdlr != conshdlr);
11106
11107 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
11108 assert(sourceconshdlrdata != NULL);
11109
11110 /* copy nonlinear handlers */
11111 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
11112 {
11113 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
11114 }
11115
11116 *valid = TRUE;
11117
11118 return SCIP_OKAY;
11119}
11120
11121/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11122static
11123SCIP_DECL_CONSFREE(consFreeNonlinear)
11124{ /*lint --e{715}*/
11125 SCIP_CONSHDLRDATA* conshdlrdata;
11126 int i;
11127
11128 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11129 assert(conshdlrdata != NULL);
11130
11131 /* free nonlinear handlers */
11132 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11133 {
11134 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11135 assert(conshdlrdata->nlhdlrs[i] == NULL);
11136 }
11137 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11138 conshdlrdata->nlhdlrssize = 0;
11139
11140 /* free upgrade functions */
11141 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11142 {
11143 assert(conshdlrdata->consupgrades[i] != NULL);
11144 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11145 }
11146 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11147
11148 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11149
11150 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11151
11152 if( conshdlrdata->vp_randnumgen != NULL )
11153 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11154
11155 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11156 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11157 {
11158 if( conshdlrdata->vp_lp[i] != NULL )
11159 {
11160 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11161 }
11162 }
11163
11164 assert(conshdlrdata->branchrandnumgen == NULL);
11165
11166 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11167 SCIPhashmapFree(&conshdlrdata->var2expr);
11168
11169 SCIPfreeBlockMemory(scip, &conshdlrdata);
11170 SCIPconshdlrSetData(conshdlr, NULL);
11171
11172 return SCIP_OKAY;
11173}
11174
11175
11176/** initialization method of constraint handler (called after problem was transformed) */
11177static
11178SCIP_DECL_CONSINIT(consInitNonlinear)
11179{ /*lint --e{715}*/
11180 SCIP_CONSHDLRDATA* conshdlrdata;
11181 int i;
11182
11183 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11184 assert(conshdlrdata != NULL);
11185
11186 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11187 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11188 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11189 conshdlrdata->enforound = 1;
11190 /* reset numbering for auxiliary variables */
11191 conshdlrdata->auxvarid = 0;
11192
11193 for( i = 0; i < nconss; ++i )
11194 {
11195 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11196 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11197 }
11198
11199 /* sort nonlinear handlers by detection priority, in decreasing order */
11200 if( conshdlrdata->nnlhdlrs > 1 )
11201 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11202
11203 /* get heuristics for later use */
11204 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11205 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11206
11207 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11208 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11209 {
11210 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11211 }
11212
11213 /* reset statistics in constraint handler */
11214 conshdlrdata->nweaksepa = 0;
11215 conshdlrdata->ntightenlp = 0;
11216 conshdlrdata->ndesperatebranch = 0;
11217 conshdlrdata->ndesperatecutoff = 0;
11218 conshdlrdata->ndesperatetightenlp = 0;
11219 conshdlrdata->nforcelp = 0;
11220 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11221 conshdlrdata->ncanonicalizecalls = 0;
11222
11223#ifdef ENFOLOGFILE
11224 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11225#endif
11226
11227 return SCIP_OKAY;
11228}
11229
11230
11231/** deinitialization method of constraint handler (called before transformed problem is freed) */
11232static
11233SCIP_DECL_CONSEXIT(consExitNonlinear)
11234{ /*lint --e{715}*/
11235 SCIP_CONSHDLRDATA* conshdlrdata;
11236 SCIP_CONS** consssorted;
11237 int i;
11238
11239 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11240 assert(conshdlrdata != NULL);
11241
11242 if( nconss > 0 )
11243 {
11244 /* for better performance of dropVarEvents, we sort by index, descending */
11245 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11246 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11247
11248 for( i = 0; i < nconss; ++i )
11249 {
11250 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11251 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11252 }
11253
11254 SCIPfreeBufferArray(scip, &consssorted);
11255 }
11256
11257 conshdlrdata->subnlpheur = NULL;
11258 conshdlrdata->trysolheur = NULL;
11259
11260 if( conshdlrdata->vp_randnumgen != NULL )
11261 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11262
11263 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11264 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11265 {
11266 if( conshdlrdata->vp_lp[i] != NULL )
11267 {
11268 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11269 }
11270 }
11271
11272 if( conshdlrdata->branchrandnumgen != NULL )
11273 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11274
11275 /* deinitialize nonlinear handlers */
11276 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11277 {
11278 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11279 }
11280
11281 ENFOLOG(
11282 if( enfologfile != NULL )
11283 {
11284 fclose(enfologfile);
11285 enfologfile = NULL;
11286 })
11287
11288 return SCIP_OKAY;
11289}
11290
11291
11292/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11293#ifdef SCIP_DISABLED_CODE
11294static
11296{ /*lint --e{715}*/
11297 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11298 SCIPABORT(); /*lint --e{527}*/
11299
11300 return SCIP_OKAY;
11301}
11302#else
11303#define consInitpreNonlinear NULL
11304#endif
11305
11306
11307/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11308static
11309SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11310{ /*lint --e{715}*/
11311 SCIP_Bool infeasible;
11312
11313 if( nconss == 0 )
11314 return SCIP_OKAY;
11315
11316 /* skip some extra work if already known to be infeasible */
11318 return SCIP_OKAY;
11319
11320 /* simplify constraints and replace common subexpressions */
11321 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11322
11323 /* currently SCIP does not offer to communicate this,
11324 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11325 * or if a constraint expression became constant
11326 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11327 */
11328 /* assert(!infeasible); */
11329
11330 /* tell SCIP that we have something nonlinear */
11332
11333 return SCIP_OKAY;
11334}
11335
11336
11337/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11338static
11339SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11340{ /*lint --e{715}*/
11341 SCIP_CONSHDLRDATA* conshdlrdata;
11342 int i;
11343
11344 /* skip remaining initializations if we have solved already
11345 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11346 * assumes nonempty activities in expressions
11347 */
11348 switch( SCIPgetStatus(scip) )
11349 {
11354 return SCIP_OKAY;
11355 default: ;
11356 } /*lint !e788 */
11357
11358 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11359 assert(conshdlrdata != NULL);
11360
11361 /* reset one of the number of detections counter to count only current round */
11362 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11363 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11364
11365 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11366
11367 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11368 if( conshdlrdata->branchpscostweight > 0.0 )
11369 {
11370 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11371 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11372 {
11373 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11374 SCIPABORT();
11375 return SCIP_INVALIDDATA;
11376 }
11377 }
11378
11379 return SCIP_OKAY;
11380}
11381
11382
11383/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11384static
11385SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11386{ /*lint --e{715}*/
11387 SCIP_CONSHDLRDATA* conshdlrdata;
11388
11389 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11390
11391 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11392 assert(conshdlrdata != NULL);
11393
11394 /* free hash table for bilinear terms */
11395 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11396
11397 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11398 conshdlrdata->checkedvarlocks = FALSE;
11399
11400 /* drop catching new solution event, if catched before */
11401 if( conshdlrdata->newsoleventfilterpos >= 0 )
11402 {
11403 SCIP_EVENTHDLR* eventhdlr;
11404
11405 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11406 assert(eventhdlr != NULL);
11407
11408 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11409 conshdlrdata->newsoleventfilterpos = -1;
11410 }
11411
11412 return SCIP_OKAY;
11413}
11414
11415
11416/** frees specific constraint data */
11417static
11418SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11419{ /*lint --e{715}*/
11420 assert(consdata != NULL);
11421 assert(*consdata != NULL);
11422 assert((*consdata)->expr != NULL);
11423
11424 /* constraint locks should have been removed */
11425 assert((*consdata)->nlockspos == 0);
11426 assert((*consdata)->nlocksneg == 0);
11427
11428 /* free variable expressions */
11429 SCIP_CALL( freeVarExprs(scip, *consdata) );
11430
11431 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11432
11433 /* free nonlinear row representation */
11434 if( (*consdata)->nlrow != NULL )
11435 {
11436 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11437 }
11438
11439 SCIPfreeBlockMemory(scip, consdata);
11440
11441 return SCIP_OKAY;
11442}
11443
11444
11445/** transforms constraint data into data belonging to the transformed problem */
11446static
11447SCIP_DECL_CONSTRANS(consTransNonlinear)
11448{ /*lint --e{715}*/
11449 SCIP_EXPR* targetexpr;
11450 SCIP_CONSDATA* sourcedata;
11451
11452 sourcedata = SCIPconsGetData(sourcecons);
11453 assert(sourcedata != NULL);
11454
11455 /* get a copy of sourceexpr with transformed vars */
11456 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11457 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11458
11459 /* create transformed cons (only captures targetexpr, no need to copy again) */
11460 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11461 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11462 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11463 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11464 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11465 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11466
11467 /* release target expr */
11468 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11469
11470 return SCIP_OKAY;
11471}
11472
11473
11474/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11475static
11476SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11477{ /*lint --e{715}*/
11478 SCIP_CONSHDLRDATA* conshdlrdata;
11479
11480 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11481 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11482 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11483 * for now, there is an assert in detectNlhdlrs to require initial if separated
11484 */
11485 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11486
11487 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11488 assert(conshdlrdata != NULL);
11489
11490 /* catch new solution event */
11491 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11492 {
11493 SCIP_EVENTHDLR* eventhdlr;
11494
11495 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11496 assert(eventhdlr != NULL);
11497
11498 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11499 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11500 }
11501
11502 /* collect all bilinear terms for which an auxvar is present
11503 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11504 * addition (and removal?) of constraints during solve
11505 * this is typically the majority of constraints, but the method should be made more flexible
11506 */
11507 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11508
11509 return SCIP_OKAY;
11510}
11511
11512
11513/** separation method of constraint handler for LP solutions */
11514static
11515SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11516{ /*lint --e{715}*/
11517 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11518
11519 return SCIP_OKAY;
11520}
11521
11522
11523/** separation method of constraint handler for arbitrary primal solutions */
11524static
11525SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11526{ /*lint --e{715}*/
11527 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11528
11529 return SCIP_OKAY;
11530}
11531
11532
11533/** constraint enforcing method of constraint handler for LP solutions */
11534static
11535SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11536{ /*lint --e{715}*/
11537 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11538
11539 return SCIP_OKAY;
11540}
11541
11542
11543/** constraint enforcing method of constraint handler for relaxation solutions */
11544static
11545SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11546{ /*lint --e{715}*/
11547 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11548
11549 return SCIP_OKAY;
11550}
11551
11552
11553/** constraint enforcing method of constraint handler for pseudo solutions */
11554static
11555SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11556{ /*lint --e{715}*/
11557 SCIP_RESULT propresult;
11558 SCIP_Longint soltag;
11559 int nchgbds;
11560 int nnotify;
11561 int c;
11562
11563 soltag = SCIPgetExprNewSoltag(scip);
11564
11566 for( c = 0; c < nconss; ++c )
11567 {
11568 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11569
11570 if( isConsViolated(scip, conss[c]) )
11572 }
11573
11574 if( *result == SCIP_FEASIBLE )
11575 return SCIP_OKAY;
11576
11577 /* try to propagate
11578 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11579 */
11580 nchgbds = 0;
11581 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11582
11583 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11584 {
11585 *result = propresult;
11586 return SCIP_OKAY;
11587 }
11588
11589 /* register all unfixed variables in all violated constraints as branching candidates */
11590 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11591 if( nnotify > 0 )
11592 {
11593 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11594
11595 return SCIP_OKAY;
11596 }
11597
11598 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11600 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11601
11602 return SCIP_OKAY;
11603}
11604
11605
11606/** feasibility check method of constraint handler for integral solutions */
11607static
11608SCIP_DECL_CONSCHECK(consCheckNonlinear)
11609{ /*lint --e{715}*/
11610 SCIP_CONSHDLRDATA* conshdlrdata;
11611 SCIP_CONSDATA* consdata;
11612 SCIP_Real maxviol;
11613 SCIP_Bool maypropfeasible;
11614 SCIP_Longint soltag;
11615 int c;
11616
11617 assert(scip != NULL);
11618 assert(conshdlr != NULL);
11619 assert(conss != NULL || nconss == 0);
11620 assert(result != NULL);
11621
11622 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11623 assert(conshdlrdata != NULL);
11624
11626 soltag = SCIPgetExprNewSoltag(scip);
11627 maxviol = 0.0;
11628 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11630
11632 maypropfeasible = FALSE;
11633
11634 /* check nonlinear constraints for feasibility */
11635 for( c = 0; c < nconss; ++c )
11636 {
11637 SCIP_Real absviol;
11638 SCIP_Real relviol;
11639
11640 assert(conss != NULL && conss[c] != NULL);
11641 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11642
11643 absviol = getConsAbsViolation(conss[c]);
11644 SCIP_CALL( getConsRelViolation(scip, conss[c], &relviol, sol, soltag) );
11645 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
11646
11647 if( absviol > SCIPfeastol(scip) )
11648 {
11650 maxviol = MAX(maxviol, absviol);
11651
11652 consdata = SCIPconsGetData(conss[c]);
11653 assert(consdata != NULL);
11654
11655 /* print reason for infeasibility */
11656 if( printreason )
11657 {
11658 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11659 SCIPinfoMessage(scip, NULL, ";\n");
11660
11661 if( consdata->lhsviol > SCIPfeastol(scip) )
11662 {
11663 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11664 }
11665 if( consdata->rhsviol > SCIPfeastol(scip) )
11666 {
11667 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11668 }
11669 }
11670 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11671 {
11672 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11673 return SCIP_OKAY;
11674 }
11675
11676 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11677 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11678 maypropfeasible = FALSE;
11679
11680 if( maypropfeasible )
11681 {
11682 if( consdata->lhsviol > SCIPfeastol(scip) )
11683 {
11684 /* check if there is a variable which may help to get the left hand side satisfied
11685 * if there is no such variable, then we cannot get feasible
11686 */
11687 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11688 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11689 maypropfeasible = FALSE;
11690 }
11691 else
11692 {
11693 assert(consdata->rhsviol > SCIPfeastol(scip));
11694 /* check if there is a variable which may help to get the right hand side satisfied
11695 * if there is no such variable, then we cannot get feasible
11696 */
11697 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11698 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11699 maypropfeasible = FALSE;
11700 }
11701 }
11702 }
11703 }
11704
11705 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11706 {
11707 SCIP_Bool success;
11708
11709 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11710
11711 /* do not pass solution to NLP heuristic if we made it feasible this way */
11712 if( success )
11713 return SCIP_OKAY;
11714 }
11715
11716 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11717 {
11718 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11719 }
11720
11721 return SCIP_OKAY;
11722}
11723
11724
11725/** domain propagation method of constraint handler */
11726static
11727SCIP_DECL_CONSPROP(consPropNonlinear)
11728{ /*lint --e{715}*/
11729 int nchgbds = 0;
11730
11731 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11732 assert(nchgbds >= 0);
11733
11734 /* TODO would it make sense to check for redundant constraints? */
11735
11736 return SCIP_OKAY;
11737}
11738
11739
11740/** presolving method of constraint handler */
11741static
11742SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11743{ /*lint --e{715}*/
11744 SCIP_CONSHDLRDATA* conshdlrdata;
11745 SCIP_Bool infeasible;
11746 int c;
11747
11749
11750 if( nconss == 0 )
11751 {
11753 return SCIP_OKAY;
11754 }
11755
11756 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11757 assert(conshdlrdata != NULL);
11758
11759 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11760 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11761 if( infeasible )
11762 {
11764 return SCIP_OKAY;
11765 }
11766
11767 /* merge constraints with the same root expression */
11768 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11769 {
11770 SCIP_Bool success;
11771
11772 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11773 if( success )
11775 }
11776
11777 /* propagate constraints */
11778 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11779 if( *result == SCIP_CUTOFF )
11780 return SCIP_OKAY;
11781
11782 /* propagate function domains (TODO integrate with simplify?) */
11783 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11784 {
11785 SCIP_RESULT localresult;
11786 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11787 if( localresult == SCIP_CUTOFF )
11788 {
11790 return SCIP_OKAY;
11791 }
11792 if( localresult == SCIP_REDUCEDDOM )
11794 }
11795
11796 /* check for redundant constraints, remove constraints that are a value expression */
11797 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11798 if( infeasible )
11799 {
11801 return SCIP_OKAY;
11802 }
11803
11804 /* try to upgrade constraints */
11805 for( c = 0; c < nconss; ++c )
11806 {
11807 SCIP_Bool upgraded;
11808
11809 /* skip inactive and deleted constraints */
11810 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11811 continue;
11812
11813 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11814 }
11815
11816 /* try to change continuous variables that appear linearly to be implicit integer */
11817 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11818 {
11819 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11820
11821 if( infeasible )
11822 {
11823 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11825 return SCIP_OKAY;
11826 }
11827 }
11828
11829 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11831 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11832 {
11833 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11834 * constraints multiple times
11835 */
11836 conshdlrdata->checkedvarlocks = TRUE;
11837
11838 for( c = 0; c < nconss; ++c )
11839 {
11840 int tmpnchgvartypes = 0;
11841 int tmpnaddconss = 0;
11842
11843 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11844 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11845 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11846
11847 if( infeasible )
11848 {
11849 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11851 return SCIP_OKAY;
11852 }
11853
11854 (*nchgvartypes) += tmpnchgvartypes;
11855 (*naddconss) += tmpnaddconss;
11856 }
11857 }
11858
11859 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11861 else
11863
11864 return SCIP_OKAY;
11865}
11866
11867
11868/** propagation conflict resolving method of constraint handler */
11869#ifdef SCIP_DISABLED_CODE
11870static
11872{ /*lint --e{715}*/
11873 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11874 SCIPABORT(); /*lint --e{527}*/
11875
11876 return SCIP_OKAY;
11877}
11878#else
11879#define consRespropNonlinear NULL
11880#endif
11881
11882
11883/** variable rounding lock method of constraint handler */
11884static
11885SCIP_DECL_CONSLOCK(consLockNonlinear)
11886{ /*lint --e{715}*/
11887 SCIP_CONSDATA* consdata;
11888 SCIP_EXPR_OWNERDATA* ownerdata;
11889 SCIP_Bool reinitsolve = FALSE;
11890
11891 assert(conshdlr != NULL);
11892 assert(cons != NULL);
11893
11894 consdata = SCIPconsGetData(cons);
11895 assert(consdata != NULL);
11896 assert(consdata->expr != NULL);
11897
11898 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11899
11900 /* check whether we need to initSolve again because
11901 * - we have enfo initialized (nenfos >= 0)
11902 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11903 */
11904 if( ownerdata->nenfos >= 0 )
11905 {
11906 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11907 reinitsolve = TRUE;
11908 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11909 reinitsolve = TRUE;
11910 }
11911
11912 if( reinitsolve )
11913 {
11914 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11915 }
11916
11917 /* add locks */
11918 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11919
11920 if( reinitsolve )
11921 {
11922 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11923 }
11924
11925 return SCIP_OKAY;
11926}
11927
11928
11929/** constraint activation notification method of constraint handler */
11930static
11931SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11932{ /*lint --e{715}*/
11933 SCIP_CONSDATA* consdata;
11934 SCIP_Bool infeasible = FALSE;
11935
11936 consdata = SCIPconsGetData(cons);
11937 assert(consdata != NULL);
11938
11939 /* simplify root expression if the constraint has been added after presolving */
11941 {
11942 SCIP_Bool replacedroot;
11943
11944 if( !consdata->issimplified )
11945 {
11946 SCIP_EXPR* simplified;
11947 SCIP_Bool changed;
11948
11949 /* simplify constraint */
11950 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11951 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11952 assert(simplified != NULL);
11953 consdata->expr = simplified;
11954 consdata->issimplified = TRUE;
11955 }
11956
11957 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11958 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11959 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11960
11961 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11962 {
11963 SCIP_CONSHDLRDATA* conshdlrdata;
11964 SCIP_EXPRITER* it;
11965 SCIP_EXPR* expr;
11966
11967 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11968 assert(conshdlrdata != NULL);
11969
11971 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11973 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11974 {
11975 SCIP_EXPR* child;
11976 SCIP_EXPR* hashmapexpr;
11977
11978 child = SCIPexpriterGetChildExprDFS(it);
11979 if( !SCIPisExprVar(scip, child) )
11980 continue;
11981
11982 /* check which expression is stored in the hashmap for the var of child */
11983 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11984 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11985 if( hashmapexpr != NULL && hashmapexpr != child )
11986 {
11988 }
11989 }
11990 SCIPfreeExpriter(&it);
11991 }
11992 }
11993
11994 /* store variable expressions */
11996 {
11997 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11998 }
11999
12000 /* add manually locks to constraints that are not checked for feasibility */
12001 if( !SCIPconsIsChecked(cons) )
12002 {
12003 assert(consdata->nlockspos == 0);
12004 assert(consdata->nlocksneg == 0);
12005
12006 SCIP_CALL( addLocks(scip, cons, 1, 0) );
12007 }
12008
12009 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
12010 {
12011 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
12012 }
12013
12014 /* TODO deal with infeasibility */
12015 assert(!infeasible);
12016
12017 return SCIP_OKAY;
12018}
12019
12020
12021/** constraint deactivation notification method of constraint handler */
12022static
12023SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
12024{ /*lint --e{715}*/
12025 SCIP_CONSHDLRDATA* conshdlrdata;
12026
12027 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12028 assert(conshdlrdata != NULL);
12029
12031 {
12032 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
12033 }
12034
12036 {
12037 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12039 }
12040
12041 /* remove locks that have been added in consActiveExpr() */
12042 if( !SCIPconsIsChecked(cons) )
12043 {
12044 SCIP_CALL( addLocks(scip, cons, -1, 0) );
12045
12046 assert(SCIPconsGetData(cons)->nlockspos == 0);
12047 assert(SCIPconsGetData(cons)->nlocksneg == 0);
12048 }
12049
12050 return SCIP_OKAY;
12051}
12052
12053
12054/** constraint enabling notification method of constraint handler */
12055static
12056SCIP_DECL_CONSENABLE(consEnableNonlinear)
12057{ /*lint --e{715}*/
12058 SCIP_CONSHDLRDATA* conshdlrdata;
12059
12060 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12061 assert(conshdlrdata != NULL);
12062
12064 {
12065 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12066 }
12067
12068 return SCIP_OKAY;
12069}
12070
12071
12072/** constraint disabling notification method of constraint handler */
12073static
12074SCIP_DECL_CONSDISABLE(consDisableNonlinear)
12075{ /*lint --e{715}*/
12076 SCIP_CONSHDLRDATA* conshdlrdata;
12077
12078 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12079 assert(conshdlrdata != NULL);
12080
12082 {
12083 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12084 }
12085
12086 return SCIP_OKAY;
12087}
12088
12089/** variable deletion of constraint handler */
12090#ifdef SCIP_DISABLED_CODE
12091static
12093{ /*lint --e{715}*/
12094 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12095 SCIPABORT(); /*lint --e{527}*/
12096
12097 return SCIP_OKAY;
12098}
12099#else
12100#define consDelvarsNonlinear NULL
12101#endif
12102
12103
12104/** constraint display method of constraint handler */
12105static
12106SCIP_DECL_CONSPRINT(consPrintNonlinear)
12107{ /*lint --e{715}*/
12108 SCIP_CONSDATA* consdata;
12109
12110 consdata = SCIPconsGetData(cons);
12111 assert(consdata != NULL);
12112 assert(consdata->expr != NULL);
12113
12114 /* print left hand side for ranged constraints */
12115 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12116 {
12117 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12118 }
12119
12120 /* print expression */
12121 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
12122
12123 /* print right hand side */
12124 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12125 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12126 else if( !SCIPisInfinity(scip, consdata->rhs) )
12127 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12128 else if( !SCIPisInfinity(scip, -consdata->lhs) )
12129 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12130 else
12131 SCIPinfoMessage(scip, file, " [free]");
12132
12133 return SCIP_OKAY;
12134}
12135
12136
12137/** constraint copying method of constraint handler */
12138static
12139SCIP_DECL_CONSCOPY(consCopyNonlinear)
12140{ /*lint --e{715}*/
12141 SCIP_CONSHDLR* targetconshdlr;
12142 SCIP_EXPR* targetexpr = NULL;
12143 SCIP_CONSDATA* sourcedata;
12144
12145 assert(cons != NULL);
12146
12147 sourcedata = SCIPconsGetData(sourcecons);
12148 assert(sourcedata != NULL);
12149
12150 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12151 assert(targetconshdlr != NULL);
12152
12153 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12154
12155 if( targetexpr == NULL )
12156 *valid = FALSE;
12157
12158 *cons = NULL;
12159 if( *valid )
12160 {
12161 /* create copy (only capture targetexpr, no need to copy again) */
12162 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12163 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12164 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12165 }
12166
12167 if( targetexpr != NULL )
12168 {
12169 /* release target expr */
12170 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12171 }
12172
12173 return SCIP_OKAY;
12174}
12175
12176
12177/** constraint parsing method of constraint handler */
12178static
12179SCIP_DECL_CONSPARSE(consParseNonlinear)
12180{ /*lint --e{715}*/
12181 SCIP_Real lhs;
12182 SCIP_Real rhs;
12183 char* endptr;
12184 SCIP_EXPR* consexprtree;
12185
12186 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12187
12188 assert(scip != NULL);
12189 assert(success != NULL);
12190 assert(str != NULL);
12191 assert(name != NULL);
12192 assert(cons != NULL);
12193
12194 *success = FALSE;
12195
12196 /* return if string empty */
12197 if( !*str )
12198 return SCIP_OKAY;
12199
12200 endptr = (char*)str;
12201
12202 /* set left and right hand side to their default values */
12203 lhs = -SCIPinfinity(scip);
12204 rhs = SCIPinfinity(scip);
12205
12206 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12207
12208 /* check for left hand side */
12209 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12210 {
12211 /* there is a number coming, maybe it is a left-hand-side */
12212 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12213 {
12214 SCIPerrorMessage("error parsing number from <%s>\n", str);
12215 return SCIP_READERROR;
12216 }
12217
12218 /* ignore whitespace */
12219 SCIP_CALL( SCIPskipSpace(&endptr) );
12220
12221 if( endptr[0] != '<' || endptr[1] != '=' )
12222 {
12223 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12224 lhs = -SCIPinfinity(scip);
12225 }
12226 else
12227 {
12228 /* it was indeed a left-hand-side, so continue parsing after it */
12229 str = endptr + 2;
12230
12231 /* ignore whitespace */
12232 SCIP_CALL( SCIPskipSpace((char**)&str) );
12233 }
12234 }
12235
12236 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12237
12238 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12239 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12240
12241 /* check for left or right hand side */
12242 SCIP_CALL( SCIPskipSpace((char**)&str) );
12243
12244 /* check for free constraint */
12245 if( strncmp(str, "[free]", 6) == 0 )
12246 {
12247 if( !SCIPisInfinity(scip, -lhs) )
12248 {
12249 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12250 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12251 return SCIP_OKAY;
12252 }
12253 *success = TRUE;
12254 }
12255 else
12256 {
12257 switch( *str )
12258 {
12259 case '<':
12260 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12261 break;
12262 case '=':
12263 if( !SCIPisInfinity(scip, -lhs) )
12264 {
12265 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12266 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12267 return SCIP_OKAY;
12268 }
12269 else
12270 {
12271 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12272 lhs = rhs;
12273 }
12274 break;
12275 case '>':
12276 if( !SCIPisInfinity(scip, -lhs) )
12277 {
12278 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12279 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12280 return SCIP_OKAY;
12281 }
12282 else
12283 {
12284 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12285 break;
12286 }
12287 case '\0':
12288 *success = TRUE;
12289 break;
12290 default:
12291 SCIPerrorMessage("unexpected character %c\n", *str);
12292 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12293 return SCIP_OKAY;
12294 }
12295 }
12296
12297 /* create constraint */
12298 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12299 consexprtree, lhs, rhs, FALSE,
12300 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12301 assert(*cons != NULL);
12302
12303 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12304
12305 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12306
12307 return SCIP_OKAY;
12308}
12309
12310
12311/** constraint method of constraint handler which returns the variables (if possible) */
12312static
12313SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12314{ /*lint --e{715}*/
12315 SCIP_CONSDATA* consdata;
12316 int i;
12317
12318 consdata = SCIPconsGetData(cons);
12319 assert(consdata != NULL);
12320
12321 /* store variable expressions if not done so far */
12322 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12323
12324 /* check whether array is too small in order to store all variables */
12325 if( varssize < consdata->nvarexprs )
12326 {
12327 *success = FALSE;
12328 return SCIP_OKAY;
12329 }
12330
12331 for( i = 0; i < consdata->nvarexprs; ++i )
12332 {
12333 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12334 assert(vars[i] != NULL);
12335 }
12336
12337 *success = TRUE;
12338
12339 return SCIP_OKAY;
12340}
12341
12342/** constraint method of constraint handler which returns the number of variables (if possible) */
12343static
12344SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12345{ /*lint --e{715}*/
12346 SCIP_CONSDATA* consdata;
12347
12348 consdata = SCIPconsGetData(cons);
12349 assert(consdata != NULL);
12350
12351 /* store variable expressions if not done so far */
12352 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12353
12354 *nvars = consdata->nvarexprs;
12355 *success = TRUE;
12356
12357 return SCIP_OKAY;
12358}
12359
12360/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12361#ifdef SCIP_DISABLED_CODE
12362static
12364{ /*lint --e{715}*/
12365 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12366 SCIPABORT(); /*lint --e{527}*/
12367
12368 return SCIP_OKAY;
12369}
12370#else
12371#define consGetDiveBdChgsNonlinear NULL
12372#endif
12373
12374/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12375static
12376SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12377{ /*lint --e{715}*/
12378 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12379
12380 return SCIP_OKAY;
12381}
12382
12383/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12384static
12385SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12386{ /*lint --e{715}*/
12387 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12388
12389 return SCIP_OKAY;
12390}
12391
12392/** output method of cons_nonlinear statistics table to output file stream 'file' */
12393static
12394SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12395{ /*lint --e{715}*/
12396 SCIP_CONSHDLR* conshdlr;
12397 SCIP_CONSHDLRDATA* conshdlrdata;
12398
12399 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12400 assert(conshdlr != NULL);
12401
12402 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12403 assert(conshdlrdata != NULL);
12404
12405 /* print statistics for constraint handler */
12406 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12407 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12408 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12409 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12410 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12411 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12412 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12413 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12414 SCIPinfoMessage(scip, file, "\n");
12415 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12416 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12417 SCIPinfoMessage(scip, file, "\n");
12418
12419 return SCIP_OKAY;
12420}
12421
12422/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
12423static
12424SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
12425{
12426 SCIP_CONSHDLR* conshdlr;
12427 SCIP_CONSHDLRDATA* conshdlrdata;
12428
12429 assert(scip != NULL);
12430 assert(table != NULL);
12431 assert(datatree != NULL);
12432
12433 /* Find the constraint handler */
12434 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12435 assert(conshdlr != NULL);
12436
12437 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12438 assert(conshdlrdata != NULL);
12439
12440 /* Insert statistics */
12441 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
12442 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
12443 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
12444 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
12445 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
12446 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
12447 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
12448
12449 return SCIP_OKAY;
12450}
12451
12452/** output method of nlhdlr statistics table to output file stream 'file' */
12453static
12454SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12455{ /*lint --e{715}*/
12456 SCIP_CONSHDLR* conshdlr;
12457 SCIP_CONSHDLRDATA* conshdlrdata;
12458
12459 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12460 assert(conshdlr != NULL);
12461
12462 /* skip nlhdlr table if there never were active nonlinear constraints */
12463 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12464 return SCIP_OKAY;
12465
12466 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12467 assert(conshdlrdata != NULL);
12468
12469 /* print statistics for nonlinear handlers */
12470 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12471
12472 return SCIP_OKAY;
12473}
12474
12475/** collect method of nlhdlr statistics table to SCIP_DATATREE */
12476static
12477SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
12478{ /*lint --e{715}*/
12479 SCIP_CONSHDLR* conshdlr;
12480 SCIP_CONSHDLRDATA* conshdlrdata;
12481
12482 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12483 assert(conshdlr != NULL);
12484
12485 /* skip nlhdlr table if there never were active nonlinear constraints */
12486 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12487 return SCIP_OKAY;
12488
12489 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12490 assert(conshdlrdata != NULL);
12491
12492 /* collect statistics for nonlinear handlers */
12493 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
12494
12495 return SCIP_OKAY;
12496}
12497
12498/** execution method of display nlhdlrs dialog */
12499static
12500SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12501{ /*lint --e{715}*/
12502 SCIP_CONSHDLR* conshdlr;
12503 SCIP_CONSHDLRDATA* conshdlrdata;
12504 int i;
12505
12506 /* add dialog to history of dialogs that have been executed */
12507 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12508
12509 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12510 assert(conshdlr != NULL);
12511
12512 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12513 assert(conshdlrdata != NULL);
12514
12515 /* display list of nonlinear handler */
12516 SCIPdialogMessage(scip, NULL, "\n");
12517 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12518 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12519 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12520 {
12521 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12522 assert(nlhdlr != NULL);
12523
12524 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12525 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12528 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12529 SCIPdialogMessage(scip, NULL, "\n");
12530 }
12531 SCIPdialogMessage(scip, NULL, "\n");
12532
12533 /* next dialog will be root dialog again */
12534 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12535
12536 return SCIP_OKAY;
12537}
12538
12539/*
12540 * constraint handler specific interface methods
12541 */
12542
12543/** creates the handler for nonlinear constraints and includes it in SCIP */
12545 SCIP* scip /**< SCIP data structure */
12546 )
12547{
12548 SCIP_CONSHDLRDATA* conshdlrdata;
12549 SCIP_DIALOG* parentdialog;
12550
12551 /* create nonlinear constraint handler data */
12552 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12553 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12554 conshdlrdata->curboundstag = 1;
12555 conshdlrdata->lastboundrelax = 1;
12556 conshdlrdata->curpropboundstag = 1;
12557 conshdlrdata->newsoleventfilterpos = -1;
12558 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12559 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12560 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12561
12562 /* include constraint handler */
12568 conshdlrCopyNonlinear,
12569 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12570 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12571 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12572 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12573 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12574 consActiveNonlinear, consDeactiveNonlinear,
12575 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12576 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12577 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12578 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12579
12580 /* add nonlinear constraint handler parameters */
12581 /* TODO organize into more subcategories */
12582 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12583 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12584 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12585
12586 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12587 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12588 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12589
12590 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12591 "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",
12592 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12593
12594 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12595 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12596 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12597
12598 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12599 "by how much to relax constraint sides during bound tightening",
12600 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12601
12602 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12603 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12604 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12605
12606 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12607 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12608 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12609
12610 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12611 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12612 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12613
12614 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12615 "maximal number of auxiliary expressions per bilinear term",
12616 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12617
12618 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12619 "whether to reformulate products of binary variables during presolving",
12620 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12621
12622 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12623 "whether to use the AND constraint handler for reformulating binary products",
12624 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12625
12626 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12627 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12628 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12629
12630 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12631 "whether to forbid multiaggregation of nonlinear variables",
12632 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12633
12634 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12635 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12636 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12637
12638 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12639 "whether to (re)run propagation in enforcement",
12640 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12641
12642 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12643 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12644 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12645
12646 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12647 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12648 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12649
12650 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12651 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12652 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12653
12654 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12655 "whether to force \"strong\" cuts in enforcement",
12656 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12657
12658 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12659 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12660 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12661
12662 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12663 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12664 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12665
12666 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12667 "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",
12668 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12669
12670 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12671 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12672 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12673
12674 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12675 "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)",
12676 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12677
12678 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12679 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12680 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12681
12682 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12683 "whether to use external branching candidates and branching rules for branching",
12684 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12685
12686 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12687 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12688 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12689
12690 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12691 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12692 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12693
12694 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12695 "weight by how much to consider the violation assigned to a variable for its branching score",
12696 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12697
12698 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12699 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12700 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12701
12702 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12703 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12704 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12705
12706 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12707 "weight by how much to consider the pseudo cost of a variable for its branching score",
12708 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12709
12710 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12711 "weight by how much to consider the domain width in branching score",
12712 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12713
12714 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12715 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12716 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12717
12718 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12719 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12720 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12721
12722 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12723 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12724 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12725
12726 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12727 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12728 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12729
12730 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12731 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12732 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12733
12734 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12735 "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)",
12736 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12737
12738 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12739 "whether to assume that any constraint in the presolved problem is convex",
12740 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
12741
12742 /* include handler for bound change events */
12743 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12744 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12745 assert(conshdlrdata->eventhdlr != NULL);
12746
12747 /* include tables for statistics */
12750 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
12752
12755 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
12757
12758 /* create, include, and release display nlhdlrs dialog */
12759 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12760 {
12761 SCIP_DIALOG* dialog;
12762
12763 assert(parentdialog != NULL);
12764 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12765
12767 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12769 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12770 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12771 }
12772
12773 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12774 processNewSolutionEvent, NULL) );
12775
12776 return SCIP_OKAY;
12777}
12778
12779/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12781 SCIP* scip, /**< SCIP data structure */
12782 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12783 int priority, /**< priority of upgrading method */
12784 SCIP_Bool active, /**< should the upgrading method by active by default? */
12785 const char* conshdlrname /**< name of the constraint handler */
12786 )
12787{
12788 SCIP_CONSHDLR* conshdlr;
12789 SCIP_CONSHDLRDATA* conshdlrdata;
12790 CONSUPGRADE* consupgrade;
12792 char paramdesc[SCIP_MAXSTRLEN];
12793 int i;
12794
12795 assert(conshdlrname != NULL );
12796 assert(nlconsupgd != NULL);
12797
12798 /* find the nonlinear constraint handler */
12799 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12800 if( conshdlr == NULL )
12801 {
12802 SCIPerrorMessage("nonlinear constraint handler not found\n");
12803 return SCIP_PLUGINNOTFOUND;
12804 }
12805
12806 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12807 assert(conshdlrdata != NULL);
12808
12809 /* check whether upgrade method exists already */
12810 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12811 {
12812 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12813 {
12814#ifdef SCIP_DEBUG
12815 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12816#endif
12817 return SCIP_OKAY;
12818 }
12819 }
12820
12821 /* create a nonlinear constraint upgrade data object */
12822 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12823 consupgrade->consupgd = nlconsupgd;
12824 consupgrade->priority = priority;
12825 consupgrade->active = active;
12826
12827 /* insert nonlinear constraint upgrade method into constraint handler data */
12828 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12829 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12830
12831 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12832 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12833 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12834 conshdlrdata->consupgrades[i] = consupgrade;
12835 conshdlrdata->nconsupgrades++;
12836
12837 /* adds parameter to turn on and off the upgrading step */
12838 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12839 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12841 paramname, paramdesc,
12842 &consupgrade->active, FALSE, active, NULL, NULL) );
12843
12844 return SCIP_OKAY;
12845}
12846
12847/** creates and captures a nonlinear constraint
12848 *
12849 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12850 */
12852 SCIP* scip, /**< SCIP data structure */
12853 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12854 const char* name, /**< name of constraint */
12855 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12856 SCIP_Real lhs, /**< left hand side of constraint */
12857 SCIP_Real rhs, /**< right hand side of constraint */
12858 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12859 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12860 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12861 * Usually set to TRUE. */
12862 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12863 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12864 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12865 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12866 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12867 * Usually set to TRUE. */
12868 SCIP_Bool local, /**< is constraint only valid locally?
12869 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12870 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12871 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12872 * adds coefficients to this constraint. */
12873 SCIP_Bool dynamic, /**< is constraint subject to aging?
12874 * Usually set to FALSE. Set to TRUE for own cuts which
12875 * are separated as constraints. */
12876 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12877 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12878 )
12879{
12880 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12881 SCIP_CONSHDLR* conshdlr;
12882
12883 /* find the nonlinear constraint handler */
12884 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12885 if( conshdlr == NULL )
12886 {
12887 SCIPerrorMessage("nonlinear constraint handler not found\n");
12888 return SCIP_PLUGINNOTFOUND;
12889 }
12890
12891 /* create constraint */
12892 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12893 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12894
12895 return SCIP_OKAY;
12896}
12897
12898/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12899 *
12900 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12901 *
12902 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12903 *
12904 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12905 */
12907 SCIP* scip, /**< SCIP data structure */
12908 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12909 const char* name, /**< name of constraint */
12910 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12911 SCIP_Real lhs, /**< left hand side of constraint */
12912 SCIP_Real rhs /**< right hand side of constraint */
12913 )
12914{
12915 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12917
12918 return SCIP_OKAY;
12919}
12920
12921/** creates and captures a quadratic nonlinear constraint
12922 *
12923 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12924 */
12926 SCIP* scip, /**< SCIP data structure */
12927 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12928 const char* name, /**< name of constraint */
12929 int nlinvars, /**< number of linear terms */
12930 SCIP_VAR** linvars, /**< array with variables in linear part */
12931 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12932 int nquadterms, /**< number of quadratic terms */
12933 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12934 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12935 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12936 SCIP_Real lhs, /**< left hand side of quadratic equation */
12937 SCIP_Real rhs, /**< right hand side of quadratic equation */
12938 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12939 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12940 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12941 * Usually set to TRUE. */
12942 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12943 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12944 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12945 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12946 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12947 * Usually set to TRUE. */
12948 SCIP_Bool local, /**< is constraint only valid locally?
12949 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12950 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12951 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12952 * adds coefficients to this constraint. */
12953 SCIP_Bool dynamic, /**< is constraint subject to aging?
12954 * Usually set to FALSE. Set to TRUE for own cuts which
12955 * are separated as constraints. */
12956 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12957 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12958 )
12959{
12960 SCIP_CONSHDLR* conshdlr;
12961 SCIP_EXPR* expr;
12962 int i;
12963
12964 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12965 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12966
12967 /* check data for infinity or nan values */
12968 for( i = 0; i < nlinvars; ++i )
12969 {
12970 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
12971 {
12972 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
12973 return SCIP_INVALIDDATA;
12974 }
12975 }
12976 for( i = 0; i < nquadterms; ++i )
12977 {
12978 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
12979 {
12980 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
12981 return SCIP_INVALIDDATA;
12982 }
12983 }
12984 /* lhs and rhs will be checked in createCons */
12985
12986 /* get nonlinear constraint handler */
12987 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12988 if( conshdlr == NULL )
12989 {
12990 SCIPerrorMessage("nonlinear constraint handler not found\n");
12991 return SCIP_PLUGINNOTFOUND;
12992 }
12993
12994 /* create quadratic expression */
12995 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12996 assert(expr != NULL);
12997
12998 /* create nonlinear constraint */
12999 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
13000 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13001
13002 /* release quadratic expression (captured by constraint now) */
13003 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13004
13005 return SCIP_OKAY;
13006}
13007
13008/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
13009 *
13010 * All flags can be set via SCIPconsSetFLAGNAME-methods.
13011 *
13012 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
13013 *
13014 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13015 */
13017 SCIP* scip, /**< SCIP data structure */
13018 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13019 const char* name, /**< name of constraint */
13020 int nlinvars, /**< number of linear terms */
13021 SCIP_VAR** linvars, /**< array with variables in linear part */
13022 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
13023 int nquadterms, /**< number of quadratic terms */
13024 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
13025 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
13026 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
13027 SCIP_Real lhs, /**< left hand side of quadratic equation */
13028 SCIP_Real rhs /**< right hand side of quadratic equation */
13029 )
13030{
13031 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
13033
13034 return SCIP_OKAY;
13035}
13036
13037/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
13038 *
13039 * \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$
13040 *
13041 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13042 */
13044 SCIP* scip, /**< SCIP data structure */
13045 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13046 const char* name, /**< name of constraint */
13047 int nvars, /**< number of variables on left hand side of constraint (n) */
13048 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
13049 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
13050 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
13051 SCIP_Real constant, /**< constant on left hand side (gamma) */
13052 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
13053 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
13054 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
13055 )
13056{
13057 SCIP_EXPR* expr;
13058 SCIP_EXPR* lhssum;
13059 SCIP_EXPR* terms[2];
13060 SCIP_Real termcoefs[2];
13061 int i;
13062
13063 assert(vars != NULL || nvars == 0);
13064
13065 /* check values for infinity or nan */
13066 for( i = 0; i < nvars; ++i )
13067 {
13068 if( coefs != NULL && ( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) ) )
13069 {
13070 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13071 return SCIP_INVALIDDATA;
13072 }
13073 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, offsets[i])) )
13074 {
13075 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13076 return SCIP_INVALIDDATA;
13077 }
13078 }
13079 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
13080 {
13081 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
13082 return SCIP_INVALIDDATA;
13083 }
13084 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
13085 {
13086 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
13087 return SCIP_INVALIDDATA;
13088 }
13089 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
13090 {
13091 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
13092 return SCIP_INVALIDDATA;
13093 }
13094 /* lhs and rhs will be checked in createCons */
13095
13096 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
13097 for( i = 0; i < nvars; ++i )
13098 {
13099 SCIP_EXPR* varexpr;
13100 SCIP_EXPR* powexpr;
13101
13102 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
13103 if( offsets != NULL && offsets[i] != 0.0 )
13104 {
13105 SCIP_EXPR* sum;
13106 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
13107 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
13108 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
13109 }
13110 else
13111 {
13112 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
13113 }
13114
13115 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
13116 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
13117 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
13118 }
13119
13120 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
13121 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
13122 termcoefs[0] = 1.0;
13123
13124 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
13125 termcoefs[1] = -rhscoeff;
13126
13127 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
13128
13129 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13130 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13131
13132 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
13133
13134 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13135
13136 return SCIP_OKAY;
13137}
13138
13139/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
13140 *
13141 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
13142 *
13143 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13144 */
13146 SCIP* scip, /**< SCIP data structure */
13147 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13148 const char* name, /**< name of constraint */
13149 SCIP_VAR* x, /**< nonlinear variable x in constraint */
13150 SCIP_VAR* z, /**< linear variable z in constraint */
13151 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
13152 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
13153 SCIP_Real zcoef, /**< coefficient of z in constraint */
13154 SCIP_Real lhs, /**< left hand side of constraint */
13155 SCIP_Real rhs /**< right hand side of constraint */
13156 )
13157{
13158 SCIP_EXPR* xexpr;
13159 SCIP_EXPR* terms[2];
13160 SCIP_Real coefs[2];
13161 SCIP_EXPR* sumexpr;
13162
13163 assert(x != NULL);
13164 assert(z != NULL);
13165
13166 if( !SCIPisFinite(exponent) )
13167 {
13168 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13169 return SCIP_INVALIDDATA;
13170 }
13171
13172 if( !SCIPisFinite(xoffset) )
13173 {
13174 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13175 return SCIP_INVALIDDATA;
13176 }
13177
13178 if( !SCIPisFinite(zcoef) )
13179 {
13180 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13181 return SCIP_INVALIDDATA;
13182 }
13183
13184 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
13185 if( xoffset != 0.0 )
13186 {
13187 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
13188 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
13189
13190 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13191 }
13192 else
13193 {
13194 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
13195 }
13196 coefs[0] = 1.0;
13197
13198 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
13199 coefs[1] = zcoef;
13200
13201 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
13202
13203 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
13204
13205 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13206 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13207 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13208 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
13209
13210 return SCIP_OKAY;
13211}
13212
13213/** gets tag indicating current local variable bounds */
13215 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13216 )
13217{
13218 SCIP_CONSHDLRDATA* conshdlrdata;
13219
13220 assert(conshdlr != NULL);
13221 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13222
13223 return conshdlrdata->curboundstag;
13224}
13225
13226/** gets the `curboundstag` from the last time where variable bounds were relaxed */
13228 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13229 )
13230{
13231 SCIP_CONSHDLRDATA* conshdlrdata;
13232
13233 assert(conshdlr != NULL);
13234 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13235
13236 return conshdlrdata->lastboundrelax;
13237}
13238
13239/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
13240 *
13241 * @attention This method is not intended for normal use.
13242 * These tags are maintained by the event handler for variable bound change events.
13243 * This method is used by some unittests.
13244 */
13246 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13247 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
13248 )
13249{
13250 SCIP_CONSHDLRDATA* conshdlrdata;
13251
13252 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13253 assert(conshdlrdata != NULL);
13254
13255 ++conshdlrdata->curboundstag;
13256 assert(conshdlrdata->curboundstag > 0);
13257
13258 if( boundrelax )
13259 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13260}
13261
13262/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13264 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13265 )
13266{
13267 assert(conshdlr != NULL);
13268
13269 return SCIPconshdlrGetData(conshdlr)->var2expr;
13270}
13271
13272/** processes a rowprep for cut addition and maybe report branchscores */
13274 SCIP* scip, /**< SCIP data structure */
13275 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13276 SCIP_CONS* cons, /**< nonlinear constraint */
13277 SCIP_EXPR* expr, /**< expression */
13278 SCIP_ROWPREP* rowprep, /**< cut to be added */
13279 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13280 SCIP_VAR* auxvar, /**< auxiliary variable */
13281 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13282 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13283 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13284 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13285 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13286 SCIP_RESULT* result /**< pointer to store the result */
13287 )
13288{
13289 SCIP_Real cutviol;
13290 SCIP_CONSHDLRDATA* conshdlrdata;
13291 SCIP_Real auxvarvalue = SCIP_INVALID;
13292 SCIP_Bool sepasuccess;
13293 SCIP_Real estimateval = SCIP_INVALID;
13294 SCIP_Real mincutviolation;
13295
13296 assert(nlhdlr != NULL);
13297 assert(cons != NULL);
13298 assert(expr != NULL);
13299 assert(rowprep != NULL);
13300 assert(auxvar != NULL);
13301 assert(result != NULL);
13302
13303 /* decide on minimal violation of cut */
13304 if( sol == NULL )
13305 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13306 else
13307 mincutviolation = SCIPfeastol(scip);
13308
13309 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13310 assert(conshdlrdata != NULL);
13311
13312 sepasuccess = TRUE;
13313
13314 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13315 if( cutviol > 0.0 )
13316 {
13317 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13318
13319 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13320 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13321 {
13322 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13323 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13324 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13325 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13326 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13327 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13328 *
13329 * if we are overestimating, we have z >= c'x-b >= f(x)
13330 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13331 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13332 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13333 *
13334 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13335 */
13336 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13337 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13338 {
13339 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13340 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13341 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13342 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13343 sepasuccess = FALSE;
13344 }
13345 }
13346
13347 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13348 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13349 }
13350 else
13351 {
13352 sepasuccess = FALSE;
13353 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13354 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13355 }
13356
13357 /* clean up estimator */
13358 if( sepasuccess )
13359 {
13360 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13361 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13362 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13363 SCIPprintRowprep(scip, rowprep, enfologfile); )
13364
13365 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13366 * instead, may even scale them down, that is, scale so that max coef is close to 1
13367 */
13368 if( !allowweakcuts )
13369 {
13370 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13371
13372 if( !sepasuccess )
13373 {
13374 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13375 }
13376 else
13377 {
13378 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13379 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13380 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13381 if( sepasuccess )
13382 sepasuccess = cutviol > mincutviolation;
13383 }
13384
13385 if( sepasuccess && auxvalue != SCIP_INVALID )
13386 {
13387 /* check whether cut is weak now
13388 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13389 * reconstructing estimateval from cutviol (TODO improve or remove?)
13390 */
13391 SCIP_Real auxvarcoef = 0.0;
13392 int i;
13393
13394 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13395 * it should be...
13396 */
13397 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13398 {
13399 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13400 {
13401 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13402 break;
13403 }
13404 }
13405
13406 if( auxvarcoef == 0.0 ||
13407 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13408 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13409 {
13410 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13411 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13412 sepasuccess = FALSE;
13413 }
13414 }
13415 }
13416 else
13417 {
13418 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13419
13420 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13421 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13422 */
13423 if( !branchscoresuccess )
13425
13426 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13427
13428 if( !sepasuccess )
13429 {
13430 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13431 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13432 }
13433
13434 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13435 * changed
13436 */
13437 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13438 {
13439 SCIP_Real violscore;
13440
13441#ifdef BRSCORE_ABSVIOL
13442 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13443#else
13444 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13445#endif
13446 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13447
13448 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13449 * - were fixed,
13450 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13451 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13452 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13453 * so I'm disabling the assert for now
13454 */
13455 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13456 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13457 }
13458 }
13459 }
13460
13461 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13462 if( sepasuccess )
13463 {
13464 SCIP_ROW* row;
13465
13466 if( conshdlrdata->branchdualweight > 0.0 )
13467 {
13468 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13469 * skip if gap is zero
13470 */
13471 if( auxvalue == SCIP_INVALID )
13472 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13473 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13474 {
13475 char gap[40];
13476 /* coverity[secure_coding] */
13477 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13478 strcat(SCIProwprepGetName(rowprep), gap);
13479 }
13480 }
13481
13482 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13483
13484 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13485 {
13486 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13488 }
13489 else if( !SCIPisCutApplicable(scip, row) )
13490 {
13491 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13492 }
13493 else
13494 {
13495 SCIP_Bool infeasible;
13496
13497 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13498 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13499
13500 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13501 * if we haven't found strong cuts before)
13502 */
13503 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13504
13505 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13506 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13508
13509 if( infeasible )
13510 {
13513 }
13514 else
13515 {
13518 }
13519 }
13520
13521 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13522 }
13523 else if( branchscoresuccess )
13524 {
13525 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13526 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13527
13528 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13529 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13530 */
13532 }
13533 else
13534 {
13535 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13536 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13537 " (!)" : ""); )
13538 }
13539
13540 return SCIP_OKAY;
13541}
13542
13543/** returns whether all nonlinear constraints are assumed to be convex */
13545 SCIP_CONSHDLR* conshdlr
13546 )
13547{
13548 SCIP_CONSHDLRDATA* conshdlrdata;
13549
13550 assert(conshdlr != NULL);
13551
13552 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13553 assert(conshdlrdata != NULL);
13554
13555 return conshdlrdata->assumeconvex;
13556}
13557
13558/** collects all bilinear terms for a given set of constraints
13559 *
13560 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13561 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13562 */
13564 SCIP* scip, /**< SCIP data structure */
13565 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13566 SCIP_CONS** conss, /**< nonlinear constraints */
13567 int nconss /**< total number of nonlinear constraints */
13568 )
13569{
13570 assert(conshdlr != NULL);
13571 assert(conss != NULL || nconss == 0);
13572
13573 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13574
13575 return SCIP_OKAY;
13576}
13577
13578/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13579 *
13580 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13581 */
13583 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13584 )
13585{
13586 SCIP_CONSHDLRDATA* conshdlrdata;
13587
13588 assert(conshdlr != NULL);
13589
13590 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13591 assert(conshdlrdata != NULL);
13592
13593 return conshdlrdata->nbilinterms;
13594}
13595
13596/** returns all bilinear terms that are contained in all nonlinear constraints
13597 *
13598 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13599 * @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.
13600 */
13602 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13603 )
13604{
13605 SCIP_CONSHDLRDATA* conshdlrdata;
13606
13607 assert(conshdlr != NULL);
13608
13609 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13610 assert(conshdlrdata != NULL);
13611
13612 return conshdlrdata->bilinterms;
13613}
13614
13615/** returns the index of the bilinear term representing the product of the two given variables
13616 *
13617 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13618 * @return The method returns -1 if the variables do not appear bilinearly.
13619 */
13621 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13622 SCIP_VAR* x, /**< first variable */
13623 SCIP_VAR* y /**< second variable */
13624 )
13625{
13626 SCIP_CONSHDLRDATA* conshdlrdata;
13628 int idx;
13629
13630 assert(conshdlr != NULL);
13631 assert(x != NULL);
13632 assert(y != NULL);
13633
13634 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13635 assert(conshdlrdata != NULL);
13636
13637 if( conshdlrdata->bilinhashtable == NULL )
13638 {
13639 return -1;
13640 }
13641
13642 /* ensure that x.index <= y.index */
13643 if( SCIPvarCompare(x, y) == 1 )
13644 {
13645 SCIPswapPointers((void**)&x, (void**)&y);
13646 }
13647 assert(SCIPvarCompare(x, y) < 1);
13648
13649 /* use a new entry to find the image in the bilinear hash table */
13650 entry.x = x;
13651 entry.y = y;
13652 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13653 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13654 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13655 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13656
13657 return idx;
13658}
13659
13660/** returns the bilinear term that represents the product of two given variables
13661 *
13662 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13663 * @return The method returns NULL if the variables do not appear bilinearly.
13664 */
13666 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13667 SCIP_VAR* x, /**< first variable */
13668 SCIP_VAR* y /**< second variable */
13669 )
13670{
13671 SCIP_CONSHDLRDATA* conshdlrdata;
13672 int idx;
13673
13674 assert(conshdlr != NULL);
13675 assert(x != NULL);
13676 assert(y != NULL);
13677
13678 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13679 assert(conshdlrdata != NULL);
13680
13681 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13682 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13683
13684 if( idx >= 0 )
13685 {
13686 return &conshdlrdata->bilinterms[idx];
13687 }
13688
13689 return NULL;
13690}
13691
13692/** evaluates an auxiliary expression for a bilinear term */
13694 SCIP* scip, /**< SCIP data structure */
13695 SCIP_VAR* x, /**< first variable of the bilinear term */
13696 SCIP_VAR* y, /**< second variable of the bilinear term */
13697 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13698 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13699 )
13700{
13701 assert(scip != NULL);
13702 assert(x != NULL);
13703 assert(y != NULL);
13704 assert(auxexpr != NULL);
13705 assert(auxexpr->auxvar != NULL);
13706
13707 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13708 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13709}
13710
13711/** stores the variables of a bilinear term in the data of the constraint handler */
13713 SCIP* scip, /**< SCIP data structure */
13714 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13715 SCIP_VAR* x, /**< first variable */
13716 SCIP_VAR* y, /**< second variable */
13717 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13718 int nlockspos, /**< number of positive expression locks */
13719 int nlocksneg /**< number of negative expression locks */
13720 )
13721{
13722 SCIP_CONSHDLRDATA* conshdlrdata;
13724 int idx;
13725
13726 assert(conshdlr != NULL);
13727
13728 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13729 assert(conshdlrdata != NULL);
13730
13731 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13732
13733 term = &conshdlrdata->bilinterms[idx];
13734 assert(term != NULL);
13735 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13736 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) */
13737
13738 /* store and capture auxiliary variable */
13739 if( auxvar != NULL )
13740 {
13741 term->aux.var = auxvar;
13742 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13743 }
13744
13745 return SCIP_OKAY;
13746}
13747
13748/** stores the variables of a bilinear term in the data of the constraint handler */
13750 SCIP* scip, /**< SCIP data structure */
13751 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13752 SCIP_VAR* x, /**< first variable */
13753 SCIP_VAR* y, /**< second variable */
13754 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13755 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13756 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13757 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13758 SCIP_Real cst, /**< constant of the auxiliary expression */
13759 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13760 )
13761{
13762 SCIP_CONSHDLRDATA* conshdlrdata;
13765 int idx;
13766 int nlockspos;
13767 int nlocksneg;
13768 SCIP_Bool added;
13769
13770 assert(conshdlr != NULL);
13771
13772 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13773 assert(conshdlrdata != NULL);
13774
13775 nlockspos = overestimate ? 1 : 0;
13776 nlocksneg = overestimate ? 0 : 1;
13777
13778 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13779
13780 term = &conshdlrdata->bilinterms[idx];
13781 assert(term != NULL);
13782 assert(SCIPvarCompare(term->x, term->y) < 1);
13783
13784 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13785 {
13786 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13787 /* this is the case where we are adding an implicitly defined relation for a product that has already
13788 * been explicitly defined; convert auxvar into an auxexpr */
13789
13790 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13791 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13792 return SCIP_OKAY;
13793
13794 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13795 auxvarexpr->cst = 0.0;
13796 auxvarexpr->coefs[0] = 1.0;
13797 auxvarexpr->coefs[1] = 0.0;
13798 auxvarexpr->coefs[2] = 0.0;
13799 auxvarexpr->auxvar = term->aux.var;
13800 auxvarexpr->underestimate = term->nlocksneg > 0;
13801 auxvarexpr->overestimate = term->nlockspos > 0;
13802
13803 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13804 term->aux.exprs = NULL;
13805
13806 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13807
13808 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13809 assert(added);
13810 }
13811
13812 /* create and add auxexpr */
13813 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13814 auxexpr->underestimate = !overestimate;
13815 auxexpr->overestimate = overestimate;
13816 auxexpr->auxvar = auxvar;
13817 auxexpr->coefs[0] = coefaux;
13818 if( term->x == x )
13819 {
13820 assert(term->y == y);
13821 auxexpr->coefs[1] = coefx;
13822 auxexpr->coefs[2] = coefy;
13823 }
13824 else
13825 {
13826 assert(term->x == y);
13827 assert(term->y == x);
13828 auxexpr->coefs[1] = coefy;
13829 auxexpr->coefs[2] = coefx;
13830 }
13831 auxexpr->cst = cst;
13832 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13833
13834 if( !added )
13835 {
13836 SCIPfreeBlockMemory(scip, &auxexpr);
13837 }
13838 else if( auxvar != NULL )
13839 { /* capture auxiliary variable */
13840 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13841 }
13842
13843 return SCIP_OKAY;
13844}
13845
13846/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13848 SCIP* scip, /**< SCIP data structure */
13849 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13850 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13851 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13852 void* fundata, /**< data for function evaluation (can be NULL) */
13853 SCIP_Real* xstar, /**< point to be separated */
13854 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13855 int nallvars, /**< half of the length of box */
13856 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13857 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13858 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13859 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13860 )
13861{
13862 SCIP_Real* corner;
13863 SCIP_Real* funvals;
13864 int* nonfixedpos;
13865 SCIP_Real maxfaceterror;
13866 int nvars; /* number of nonfixed variables */
13867 unsigned int ncorners;
13868 unsigned int i;
13869 int j;
13870
13871 assert(scip != NULL);
13872 assert(conshdlr != NULL);
13873 assert(function != NULL);
13874 assert(xstar != NULL);
13875 assert(box != NULL);
13876 assert(success != NULL);
13877 assert(facetcoefs != NULL);
13878 assert(facetconstant != NULL);
13879
13880 *success = FALSE;
13881
13882 /* identify fixed variables */
13883 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13884 nvars = 0;
13885 for( j = 0; j < nallvars; ++j )
13886 {
13887 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13888 continue;
13889 nonfixedpos[nvars] = j;
13890 nvars++;
13891 }
13892
13893 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13894 * if too many variables are not fixed, then we do nothing currently
13895 */
13896 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13897 {
13898 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13899 SCIPfreeBufferArray(scip, &nonfixedpos);
13900 return SCIP_OKAY;
13901 }
13902
13903 /* compute f(v^i) for each corner v^i of [l,u] */
13904 ncorners = POWEROFTWO(nvars);
13905 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13906 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13907 for( j = 0; j < nallvars; ++j )
13908 {
13909 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13910 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13911 }
13912 for( i = 0; i < ncorners; ++i )
13913 {
13914 SCIPdebugMsg(scip, "corner %u: ", i);
13915 for( j = 0; j < nvars; ++j )
13916 {
13917 int varpos = nonfixedpos[j];
13918 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13919 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13920 */
13921 if( (i >> j) & 0x1 )
13922 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13923 else
13924 corner[varpos] = box[2 * varpos ]; /* lb of var */
13925 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13926 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13927 }
13928
13929 funvals[i] = function(corner, nallvars, fundata);
13930
13931 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13932
13933 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13934 {
13935 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13936 goto CLEANUP;
13937 }
13938 }
13939
13940 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13941 BMSclearMemoryArray(facetcoefs, nallvars);
13942
13943 if( nvars == 1 )
13944 {
13945 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13946
13947 /* check whether target has been missed */
13948 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13949 {
13950 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13951 *success = FALSE;
13952 }
13953 }
13954 else if( nvars == 2 && SCIPlapackIsAvailable() )
13955 {
13956 int idx1 = nonfixedpos[0];
13957 int idx2 = nonfixedpos[1];
13958 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13959 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13960 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13961 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13962 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13963 SCIP_Real coefs[2] = { 0.0, 0.0 };
13964
13965 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13966
13967 facetcoefs[idx1] = coefs[0];
13968 facetcoefs[idx2] = coefs[1];
13969 }
13970 else
13971 {
13972 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13973 }
13974 if( !*success )
13975 {
13976 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13977 goto CLEANUP;
13978 }
13979
13980 /*
13981 * check and adjust facet with the algorithm of Rikun et al.
13982 */
13983
13984 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13985
13986 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13987 if( maxfaceterror > 0.0 )
13988 {
13989 SCIP_CONSHDLRDATA* conshdlrdata;
13990 SCIP_Real midval;
13991 SCIP_Real feastol;
13992
13994
13995 /* evaluate function in middle point to get some idea for a scaling */
13996 for( j = 0; j < nvars; ++j )
13997 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13998 midval = function(corner, nallvars, fundata);
13999 if( midval == SCIP_INVALID )
14000 midval = 1.0;
14001
14002 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14003 assert(conshdlrdata != NULL);
14004
14005 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
14006 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
14007 {
14008 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
14009 *success = FALSE;
14010 goto CLEANUP;
14011 }
14012
14013 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
14014
14015 if( overestimate )
14016 *facetconstant += maxfaceterror;
14017 else
14018 *facetconstant -= maxfaceterror;
14019 }
14020
14021 /* if we made it until here, then we have a nice facet */
14022 assert(*success);
14023
14024CLEANUP:
14025 /* free allocated memory */
14026 SCIPfreeBufferArray(scip, &corner);
14027 SCIPfreeBufferArray(scip, &funvals);
14028 SCIPfreeBufferArray(scip, &nonfixedpos);
14029
14030 return SCIP_OKAY;
14031}
14032
14033/*
14034 * constraint specific interface methods
14035 */
14036
14037/** returns the expression of the given nonlinear constraint */
14039 SCIP_CONS* cons /**< constraint data */
14040 )
14041{
14042 SCIP_CONSDATA* consdata;
14043
14044 assert(cons != NULL);
14046
14047 consdata = SCIPconsGetData(cons);
14048 assert(consdata != NULL);
14049
14050 return consdata->expr;
14051}
14052
14053/** gets the left hand side of a nonlinear constraint */
14055 SCIP_CONS* cons /**< constraint data */
14056 )
14057{
14058 SCIP_CONSDATA* consdata;
14059
14060 assert(cons != NULL);
14062
14063 consdata = SCIPconsGetData(cons);
14064 assert(consdata != NULL);
14065
14066 return consdata->lhs;
14067}
14068
14069/** gets the right hand side of a nonlinear constraint */
14071 SCIP_CONS* cons /**< constraint data */
14072 )
14073{
14074 SCIP_CONSDATA* consdata;
14075
14076 assert(cons != NULL);
14078
14079 consdata = SCIPconsGetData(cons);
14080 assert(consdata != NULL);
14081
14082 return consdata->rhs;
14083}
14084
14085/** gets the nonlinear constraint as a nonlinear row representation. */
14087 SCIP* scip, /**< SCIP data structure */
14088 SCIP_CONS* cons, /**< constraint */
14089 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14090 )
14091{
14092 SCIP_CONSDATA* consdata;
14093
14094 assert(cons != NULL);
14095 assert(nlrow != NULL);
14097
14098 consdata = SCIPconsGetData(cons);
14099 assert(consdata != NULL);
14100
14101 if( consdata->nlrow == NULL )
14102 {
14103 SCIP_CALL( createNlRow(scip, cons) );
14104 }
14105 assert(consdata->nlrow != NULL);
14106 *nlrow = consdata->nlrow;
14107
14108 return SCIP_OKAY;
14109}
14110
14111/** returns the curvature of the expression of a given nonlinear constraint
14112 *
14113 * @note The curvature information is computed during CONSINITSOL.
14114 */
14116 SCIP_CONS* cons /**< constraint data */
14117 )
14118{
14119 SCIP_CONSDATA* consdata;
14120
14121 assert(cons != NULL);
14123
14124 consdata = SCIPconsGetData(cons);
14125 assert(consdata != NULL);
14126
14127 return consdata->curv;
14128}
14129
14130/** checks whether expression of constraint can be represented as quadratic form
14131 *
14132 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
14133 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
14134 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
14135 */
14137 SCIP* scip, /**< SCIP data structure */
14138 SCIP_CONS* cons, /**< constraint data */
14139 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
14140 )
14141{
14142 SCIP_CONSDATA* consdata;
14143
14144 assert(scip != NULL);
14145 assert(cons != NULL);
14146 assert(isquadratic != NULL);
14148
14149 consdata = SCIPconsGetData(cons);
14150 assert(consdata != NULL);
14151 assert(consdata->expr != NULL);
14152
14153 /* check whether constraint expression is quadratic in extended formulation */
14154 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
14155
14156 /* if not quadratic in non-extended formulation, then do indicate quadratic */
14157 if( *isquadratic )
14158 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
14159
14160 return SCIP_OKAY;
14161}
14162
14163/** changes left-hand-side of a nonlinear constraint
14164 *
14165 * @attention This method can only be called in the problem stage.
14166 */
14168 SCIP* scip, /**< SCIP data structure */
14169 SCIP_CONS* cons, /**< constraint data */
14170 SCIP_Real lhs /**< new left-hand-side */
14171 )
14172{
14173 SCIP_CONSDATA* consdata;
14174
14175 assert(scip != NULL);
14176 assert(cons != NULL);
14178
14180 {
14181 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14182 return SCIP_INVALIDCALL;
14183 }
14184
14185 /* we should have an original constraint */
14187
14188 consdata = SCIPconsGetData(cons);
14189 assert(consdata != NULL);
14190
14191 if( consdata->lhs == lhs )
14192 return SCIP_OKAY;
14193
14194 consdata->lhs = lhs;
14195
14196 /* not sure we care about any of these flags for original constraints */
14197 consdata->ispropagated = FALSE;
14198
14199 return SCIP_OKAY;
14200}
14201
14202/** changes right-hand-side of a nonlinear constraint
14203 *
14204 * @attention This method can only be called in the problem stage.
14205 */
14207 SCIP* scip, /**< SCIP data structure */
14208 SCIP_CONS* cons, /**< constraint data */
14209 SCIP_Real rhs /**< new right-hand-side */
14210 )
14211{
14212 SCIP_CONSDATA* consdata;
14213
14214 assert(scip != NULL);
14215 assert(cons != NULL);
14217
14219 {
14220 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14221 return SCIP_INVALIDCALL;
14222 }
14223
14224 /* we should have an original constraint */
14226
14227 consdata = SCIPconsGetData(cons);
14228 assert(consdata != NULL);
14229
14230 if( consdata->rhs == rhs )
14231 return SCIP_OKAY;
14232
14233 consdata->rhs = rhs;
14234
14235 /* not sure we care about any of these flags for original constraints */
14236 consdata->ispropagated = FALSE;
14237
14238 return SCIP_OKAY;
14239}
14240
14241/** changes expression of a nonlinear constraint
14242 *
14243 * @attention This method can only be called in the problem stage.
14244 */
14246 SCIP* scip, /**< SCIP data structure */
14247 SCIP_CONS* cons, /**< constraint data */
14248 SCIP_EXPR* expr /**< new expression */
14249 )
14250{
14251 SCIP_CONSHDLR* conshdlr;
14252 SCIP_CONSDATA* consdata;
14253
14254 assert(scip != NULL);
14255 assert(cons != NULL);
14256 assert(expr != NULL);
14257
14259 {
14260 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14261 return SCIP_INVALIDCALL;
14262 }
14263
14264 /* we should have an original constraint */
14266
14267 conshdlr = SCIPconsGetHdlr(cons);
14268 assert(conshdlr != NULL);
14269 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14270
14271 consdata = SCIPconsGetData(cons);
14272 assert(consdata != NULL);
14273 assert(consdata->expr != NULL);
14274
14275 /* we should not have collected additional data for the expr
14276 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14277 */
14278 assert(consdata->nvarexprs == 0);
14279 assert(consdata->varexprs == NULL);
14280 assert(!consdata->catchedevents);
14281
14282 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14283
14284 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14285 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14286
14287 /* not sure we care about any of these flags for original constraints */
14288 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14289 consdata->issimplified = FALSE;
14290 consdata->ispropagated = FALSE;
14291
14292 return SCIP_OKAY;
14293}
14294
14295/** adds coef * var to nonlinear constraint
14296 *
14297 * @attention This method can only be called in the problem stage.
14298 */
14300 SCIP* scip, /**< SCIP data structure */
14301 SCIP_CONS* cons, /**< constraint data */
14302 SCIP_VAR* var, /**< variable */
14303 SCIP_Real coef /**< coefficient */
14304 )
14305{
14306 SCIP_CONSHDLR* conshdlr;
14307 SCIP_CONSDATA* consdata;
14308 SCIP_EXPR* varexpr;
14309
14310 assert(scip != NULL);
14311 assert(cons != NULL);
14312
14314 {
14315 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14316 return SCIP_INVALIDCALL;
14317 }
14318
14319 /* we should have an original constraint */
14321
14322 if( coef == 0.0 )
14323 return SCIP_OKAY;
14324
14325 conshdlr = SCIPconsGetHdlr(cons);
14326 assert(conshdlr != NULL);
14327 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14328
14329 consdata = SCIPconsGetData(cons);
14330 assert(consdata != NULL);
14331 assert(consdata->expr != NULL);
14332
14333 /* we should not have collected additional data for it
14334 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14335 */
14336 assert(consdata->nvarexprs == 0);
14337 assert(consdata->varexprs == NULL);
14338 assert(!consdata->catchedevents);
14339
14340 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14341
14342 /* append to sum, if consdata->expr is sum and not used anywhere else */
14343 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14344 {
14345 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14346 }
14347 else
14348 {
14349 /* create new expression = 1 * consdata->expr + coef * var */
14350 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14351 SCIP_Real coefs[2] = { 1.0, coef };
14352
14353 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14354
14355 /* release old root expr */
14356 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14357 }
14358
14359 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14360
14361 /* not sure we care about any of these flags for original constraints */
14362 consdata->issimplified = FALSE;
14363 consdata->ispropagated = FALSE;
14364
14365 return SCIP_OKAY;
14366}
14367
14368/** adds coef * expr to nonlinear constraint
14369 *
14370 * @attention This method can only be called in the problem stage.
14371 */
14373 SCIP* scip, /**< SCIP data structure */
14374 SCIP_CONS* cons, /**< nonlinear constraint */
14375 SCIP_EXPR* expr, /**< expression */
14376 SCIP_Real coef /**< coefficient */
14377 )
14378{
14379 SCIP_CONSHDLR* conshdlr;
14380 SCIP_CONSDATA* consdata;
14381 SCIP_EXPR* exprowned;
14382
14383 assert(scip != NULL);
14384 assert(cons != NULL);
14385
14387 {
14388 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14389 return SCIP_INVALIDCALL;
14390 }
14391
14392 /* we should have an original constraint */
14394
14395 if( coef == 0.0 )
14396 return SCIP_OKAY;
14397
14398 conshdlr = SCIPconsGetHdlr(cons);
14399 assert(conshdlr != NULL);
14400 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14401
14402 consdata = SCIPconsGetData(cons);
14403 assert(consdata != NULL);
14404 assert(consdata->expr != NULL);
14405
14406 /* free quadratic representation, if any is stored */
14407 SCIPfreeExprQuadratic(scip, consdata->expr);
14408
14409 /* free varexprs in consdata, in case they have been stored
14410 * (e.g., by a call to consGet(N)VarsNonlinear)
14411 */
14412 SCIP_CALL( freeVarExprs(scip, consdata) );
14413
14414 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14415 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14416
14417 /* append to sum, if consdata->expr is sum and not used anywhere else */
14418 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14419 {
14420 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14421 }
14422 else
14423 {
14424 /* create new expression = 1 * consdata->expr + coef * var */
14425 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14426 SCIP_Real coefs[2] = { 1.0, coef };
14427
14428 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14429
14430 /* release old root expr */
14431 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14432 }
14433
14434 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14435
14436 /* not sure we care about any of these flags for original constraints */
14437 consdata->issimplified = FALSE;
14438 consdata->ispropagated = FALSE;
14439
14440 return SCIP_OKAY;
14441}
14442
14443/** computes value of constraint expression in a given solution
14444 *
14445 * Stores value of constraint expression in sol in activity.
14446 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14447 */
14449 SCIP* scip, /**< SCIP data structure */
14450 SCIP_CONS* cons, /**< constraint */
14451 SCIP_SOL* sol, /**< solution */
14452 SCIP_Real* activity /**< buffer to store computed activity */
14453 )
14454{
14455 SCIP_CONSDATA* consdata;
14456
14457 assert(cons != NULL);
14458 assert(activity != NULL);
14459
14460 consdata = SCIPconsGetData(cons);
14461 assert(consdata != NULL);
14462
14463 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14464 *activity = SCIPexprGetEvalValue(consdata->expr);
14465
14466 return SCIP_OKAY;
14467}
14468
14469/** gets absolute violation of nonlinear constraint
14470 *
14471 * This function evaluates the constraints in the given solution.
14472 *
14473 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14474 */
14476 SCIP* scip, /**< SCIP data structure */
14477 SCIP_CONS* cons, /**< constraint */
14478 SCIP_SOL* sol, /**< solution to check */
14479 SCIP_Real* viol /**< buffer to store computed violation */
14480 )
14481{
14482 assert(cons != NULL);
14483 assert(viol != NULL);
14484
14485 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14486 *viol = getConsAbsViolation(cons);
14487
14488 return SCIP_OKAY;
14489}
14490
14491/** gets scaled violation of nonlinear constraint
14492 *
14493 * This function evaluates the constraints in the given solution.
14494 *
14495 * The scaling that is applied to the absolute violation of the constraint
14496 * depends on the setting of parameter constraints/nonlinear/violscale.
14497 */
14499 SCIP* scip, /**< SCIP data structure */
14500 SCIP_CONS* cons, /**< constraint */
14501 SCIP_SOL* sol, /**< solution to check */
14502 SCIP_Real* viol /**< buffer to store computed violation */
14503 )
14504{
14505 assert(cons != NULL);
14506 assert(viol != NULL);
14507
14508 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14509 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14510
14511 return SCIP_OKAY;
14512}
14513
14514/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14516 SCIP* scip, /**< SCIP data structure */
14517 SCIP_CONS* cons, /**< nonlinear constraint */
14518 SCIP_VAR** var, /**< pointer to store the variable */
14519 SCIP_Real* coef /**< pointer to store the coefficient */
14520 )
14521{
14522 SCIP_CONSDATA* consdata;
14523
14524 assert(cons != NULL);
14525 assert(var != NULL);
14526 assert(coef != NULL);
14527
14528 /* check for a linear variable that can be increased or decreased without harming feasibility */
14530
14531 consdata = SCIPconsGetData(cons);
14532 assert(consdata != NULL);
14533
14534 *var = consdata->linvardecr;
14535 *coef = consdata->linvardecrcoef;
14536}
14537
14538/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14540 SCIP* scip, /**< SCIP data structure */
14541 SCIP_CONS* cons, /**< nonlinear constraint */
14542 SCIP_VAR** var, /**< pointer to store the variable */
14543 SCIP_Real* coef /**< pointer to store the coefficient */
14544 )
14545{
14546 SCIP_CONSDATA* consdata;
14547
14548 assert(cons != NULL);
14549 assert(var != NULL);
14550 assert(coef != NULL);
14551
14552 /* check for a linear variable that can be increased or decreased without harming feasibility */
14554
14555 consdata = SCIPconsGetData(cons);
14556 assert(consdata != NULL);
14557
14558 *var = consdata->linvarincr;
14559 *coef = consdata->linvarincrcoef;
14560}
14561
14562
14563/*
14564 * Methods for Expressions in Nonlinear Constraints
14565 */
14566
14567/** returns the number of positive rounding locks of an expression */
14569 SCIP_EXPR* expr /**< expression */
14570 )
14571{
14572 assert(expr != NULL);
14574
14575 return SCIPexprGetOwnerData(expr)->nlockspos;
14576}
14577
14578/** returns the number of negative rounding locks of an expression */
14580 SCIP_EXPR* expr /**< expression */
14581 )
14582{
14583 assert(expr != NULL);
14585
14586 return SCIPexprGetOwnerData(expr)->nlocksneg;
14587}
14588
14589/** returns the variable used for linearizing a given expression (return value might be NULL)
14590 *
14591 * @note for variable expression it returns the corresponding variable
14592 */
14594 SCIP_EXPR* expr /**< expression */
14595 )
14596{
14597 SCIP_EXPR_OWNERDATA* ownerdata;
14598
14599 assert(expr != NULL);
14600
14601 ownerdata = SCIPexprGetOwnerData(expr);
14602 assert(ownerdata != NULL);
14603
14604 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14605}
14606
14607/** returns the number of enforcements for an expression */
14609 SCIP_EXPR* expr /**< expression */
14610 )
14611{
14612 assert(expr != NULL);
14614
14615 return SCIPexprGetOwnerData(expr)->nenfos;
14616}
14617
14618/** returns the data for one of the enforcements of an expression */
14620 SCIP_EXPR* expr, /**< expression */
14621 int idx, /**< position of enforcement in enfos array */
14622 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14623 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14624 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14625 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14626 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14627 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14628 )
14629{
14630 SCIP_EXPR_OWNERDATA* ownerdata;
14631
14632 assert(expr != NULL);
14633
14634 ownerdata = SCIPexprGetOwnerData(expr);
14635 assert(ownerdata != NULL);
14636 assert(idx >= 0);
14637 assert(idx < ownerdata->nenfos);
14638 assert(ownerdata->enfos[idx] != NULL);
14639 assert(nlhdlr != NULL);
14640
14641 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14642
14643 if( nlhdlrexprdata != NULL )
14644 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14645
14646 if( nlhdlrparticipation != NULL )
14647 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14648
14649 if( sepabelowusesactivity != NULL )
14650 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14651
14652 if( sepaaboveusesactivity != NULL )
14653 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14654
14655 if( auxvalue != NULL )
14656 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14657}
14658
14659/** sets the auxiliary value of expression for one of the enforcements of an expression */
14661 SCIP_EXPR* expr, /**< expression */
14662 int idx, /**< position of enforcement in enfos array */
14663 SCIP_Real auxvalue /**< the new value of auxval */
14664 )
14665{
14666 SCIP_EXPR_OWNERDATA* ownerdata;
14667
14668 assert(expr != NULL);
14669
14670 ownerdata = SCIPexprGetOwnerData(expr);
14671 assert(ownerdata != NULL);
14672
14673 assert(idx >= 0);
14674 assert(idx < ownerdata->nenfos);
14675 assert(ownerdata->enfos[idx] != NULL);
14676
14677 ownerdata->enfos[idx]->auxvalue = auxvalue;
14678}
14679
14680/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14681 *
14682 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14683 */
14685 SCIP_EXPR* expr /**< expression */
14686 )
14687{
14688 assert(expr != NULL);
14690
14691 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14692}
14693
14694/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14695 *
14696 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14697 */
14699 SCIP_EXPR* expr /**< expression */
14700 )
14701{
14702 assert(expr != NULL);
14704
14705 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14706}
14707
14708/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14709 *
14710 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14711 */
14713 SCIP_EXPR* expr /**< expression */
14714 )
14715{
14716 assert(expr != NULL);
14718
14719 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14720}
14721
14722/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14723 *
14724 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14725 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14726 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14727 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14728 * and also increments this count for all variables in the expression.
14729 *
14730 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14731 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14732 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14733 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14734 */
14736 SCIP* scip, /**< SCIP data structure */
14737 SCIP_EXPR* expr, /**< expression */
14738 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14739 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14740 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14741 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14742 )
14743{
14744 SCIP_EXPR_OWNERDATA* ownerdata;
14745
14746 assert(expr != NULL);
14747
14748 ownerdata = SCIPexprGetOwnerData(expr);
14749 assert(ownerdata != NULL);
14750
14751 /* do not store auxvar request for variable expressions */
14752 if( useauxvar && SCIPisExprVar(scip, expr) )
14753 useauxvar = FALSE;
14754
14755 if( ownerdata->nenfos >= 0 &&
14756 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14757 (ownerdata->nauxvaruses == 0 && useauxvar)
14758 ) )
14759 {
14760 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14761 * we require additional enforcement methods, that is,
14762 * - activity of expr was not used before but will be used now, or
14763 * - auxiliary variable of expr was not required before but will be used now
14764 */
14765 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14766 }
14767
14768 if( useauxvar )
14769 ++ownerdata->nauxvaruses;
14770
14771 if( useactivityforprop )
14772 ++ownerdata->nactivityusesprop;
14773
14774 if( useactivityforsepabelow || useactivityforsepaabove )
14775 ++ownerdata->nactivityusessepa;
14776
14777 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14778 * information is used in detectNlhdlr()
14779 */
14780 if( useactivityforsepabelow )
14781 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14782 if( useactivityforsepaabove )
14783 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14784
14785 if( useactivityforprop )
14786 {
14787 /* if activity will be used for propagation, then make sure there is a valid activity
14788 * this way, we can do a reversepropcall after detectNlhdlr
14789 */
14791 }
14792
14793 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14794 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14795 {
14796 SCIP_EXPRITER* it;
14797
14798 /* create and initialize iterator */
14801
14802 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14803 if( SCIPisExprVar(scip, expr) )
14804 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14805
14806 /* free iterator */
14807 SCIPfreeExpriter(&it);
14808 }
14809
14810 return SCIP_OKAY;
14811}
14812
14813/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14814 *
14815 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14816 * Assume that f(x) is associated with auxiliary variable z.
14817 *
14818 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14819 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14820 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14821 *
14822 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14823 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14824 */
14826 SCIP* scip, /**< SCIP data structure */
14827 SCIP_EXPR* expr, /**< expression */
14828 SCIP_SOL* sol, /**< solution */
14829 SCIP_Longint soltag, /**< tag of solution */
14830 SCIP_Real* viol, /**< buffer to store computed violation */
14831 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14832 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14833 )
14834{
14835 assert(scip != NULL);
14836 assert(expr != NULL);
14837 assert(viol != NULL);
14838
14839 /* make sure expression has been evaluated */
14840 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14841
14842 /* get violation from internal method */
14843 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14844
14845 return SCIP_OKAY;
14846}
14847
14848/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14849 *
14850 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14851 * Assume that f(w) is associated with auxiliary variable z.
14852 *
14853 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14854 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14855 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14856 *
14857 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14858 * both `violover` and `violunder` are set to TRUE.
14859 */
14861 SCIP* scip, /**< SCIP data structure */
14862 SCIP_EXPR* expr, /**< expression */
14863 SCIP_Real auxvalue, /**< the value of f(w) */
14864 SCIP_SOL* sol, /**< solution that has been evaluated */
14865 SCIP_Real* viol, /**< buffer to store computed violation */
14866 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14867 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14868 )
14869{
14870 assert(scip != NULL);
14871 assert(expr != NULL);
14872 assert(viol != NULL);
14873
14874 /* get violation from internal method */
14875 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14876
14877 return SCIP_OKAY;
14878}
14879
14880
14881/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14882 *
14883 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14884 * Assume that f(w) is associated with auxiliary variable z.
14885 *
14886 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14887 * the absolute violation divided by max(1,|f(w)|).
14888 *
14889 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14890 * both `violover` and `violunder` are set to TRUE.
14891 */
14893 SCIP* scip, /**< SCIP data structure */
14894 SCIP_EXPR* expr, /**< expression */
14895 SCIP_Real auxvalue, /**< the value of f(w) */
14896 SCIP_SOL* sol, /**< solution that has been evaluated */
14897 SCIP_Real* viol, /**< buffer to store computed violation */
14898 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14899 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14900 )
14901{
14902 assert(scip != NULL);
14903 assert(expr != NULL);
14904 assert(viol != NULL);
14905
14906 /* get violation from internal method */
14907 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14908
14909 if( !SCIPisInfinity(scip, *viol) )
14910 {
14911 assert(auxvalue != SCIP_INVALID);
14912 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14913 *viol /= MAX(1.0, REALABS(auxvalue));
14914 }
14915
14916 return SCIP_OKAY;
14917}
14918
14919/** returns bounds on the expression
14920 *
14921 * This gives an intersection of bounds from
14922 * - activity calculation (SCIPexprGetActivity()), if valid,
14923 * - auxiliary variable, if present,
14924 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14925 *
14926 * @note The returned interval can be empty!
14927 */
14929 SCIP* scip, /**< SCIP data structure */
14930 SCIP_EXPR* expr /**< expression */
14931 )
14932{
14933 SCIP_EXPR_OWNERDATA* ownerdata;
14934 SCIP_CONSHDLRDATA* conshdlrdata;
14935 SCIP_INTERVAL bounds;
14936
14937 assert(scip != NULL);
14938 assert(expr != NULL);
14939
14940 ownerdata = SCIPexprGetOwnerData(expr);
14941 assert(ownerdata != NULL);
14942
14943 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14944 assert(conshdlrdata != NULL);
14945
14946 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14947
14948 /* start with propbounds if they belong to current propagation */
14949 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14950 {
14951 bounds = ownerdata->propbounds;
14952 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14953 }
14954 else
14956
14957 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14958 {
14959 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14960 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14962 }
14963
14964 if( ownerdata->auxvar != NULL )
14965 {
14966 /* apply auxiliary variable bounds to bounds */
14967 SCIP_INTERVAL auxvarbounds;
14968
14969 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14970 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14971 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14972 }
14973
14974 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14975
14976 return bounds;
14977}
14978
14979/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14980 * corresponding (auxiliary) variable (if any)
14981 *
14982 * @attention this function should only be called during domain propagation in cons_nonlinear
14983 */
14985 SCIP* scip, /**< SCIP data structure */
14986 SCIP_EXPR* expr, /**< expression to be tightened */
14987 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14988 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14989 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14990 )
14991{
14992 SCIP_EXPR_OWNERDATA* ownerdata;
14993 SCIP_CONSHDLRDATA* conshdlrdata;
14994
14995 assert(scip != NULL);
14996 assert(expr != NULL);
14997 assert(cutoff != NULL);
14998
14999 ownerdata = SCIPexprGetOwnerData(expr);
15000 assert(ownerdata != NULL);
15001 assert(ownerdata->conshdlr != NULL);
15002
15003 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15004 assert(conshdlrdata != NULL);
15005
15006 /* the code below assumes that current activity is valid
15007 * if it turns out that we cannot ensure that, then we should change code
15008 */
15009 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
15011
15012 *cutoff = FALSE;
15013
15014#ifdef DEBUG_PROP
15015 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
15016 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
15017 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
15018#endif
15019
15020 if( SCIPexprIsIntegral(expr) )
15021 {
15022 /* apply integrality to new bounds
15023 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
15024 */
15025 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
15026 newbounds.inf = SCIPceil(scip, newbounds.inf);
15027 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
15028 newbounds.sup = SCIPfloor(scip, newbounds.sup);
15029#ifdef DEBUG_PROP
15030 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
15031#endif
15032 }
15033
15035 {
15036 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
15037
15038 *cutoff = TRUE;
15039 return SCIP_OKAY;
15040 }
15041
15042 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
15043 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
15044 {
15045 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
15046
15047 *cutoff = TRUE;
15048 return SCIP_OKAY;
15049 }
15050
15051 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
15052 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
15053 {
15054 /* if already having propbounds in expr, then tighten newbounds by propbounds */
15055 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
15056 }
15057 else
15058 {
15059 /* first time we have propbounds for expr in this propagation rounds:
15060 * intersect with activity (though don't let it become empty if very close intervals)
15061 */
15062 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
15063 }
15064#ifdef DEBUG_PROP
15065 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
15066#endif
15067
15068 /* check if the new bounds lead to an empty interval */
15070 {
15071 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
15072
15073 *cutoff = TRUE;
15074 return SCIP_OKAY;
15075 }
15076
15077 /* if expr is not constant or variable, then store newbounds in expr->propbounds
15078 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
15079 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
15080 */
15081 if( SCIPexprGetNChildren(expr) > 0 )
15082 {
15083 ownerdata->propbounds = newbounds;
15084 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
15085 }
15086
15087 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
15088 * propagation or update of auxvar bounds
15089 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
15090 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
15091 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
15092 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
15093 * one or should we not even update propbounds to newbounds if the update is small?
15094 */
15095 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
15096 {
15097#ifdef DEBUG_PROP
15098 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);
15099#endif
15100 return SCIP_OKAY;
15101 }
15102
15103 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
15104 {
15105 /* add expression to propagation queue if not there yet and not var or constant and
15106 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
15107 */
15108#ifdef DEBUG_PROP
15109 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
15110#endif
15111 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
15112 ownerdata->inpropqueue = TRUE;
15113 }
15114
15115 /* update bounds on variable or auxiliary variable */
15116 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
15117
15118 return SCIP_OKAY;
15119}
15120
15121/** mark constraints that include this expression to be propagated again
15122 *
15123 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
15124 * a change of variable bounds, e.g., because new information on the expression is available
15125 * that could potentially lead to tighter expression activity values.
15126 *
15127 * Note, that this call marks also constraints for propagation which only share some variable
15128 * with this expression.
15129 */
15131 SCIP* scip, /**< SCIP data structure */
15132 SCIP_EXPR* expr /**< expression to propagate again */
15133 )
15134{
15135 SCIP_EXPRITER* it;
15136 SCIP_CONSDATA* consdata;
15137 SCIP_EXPR_OWNERDATA* ownerdata;
15138 int c;
15139
15140 assert(scip != NULL);
15141 assert(expr != NULL);
15142
15143 ownerdata = SCIPexprGetOwnerData(expr);
15144 assert(ownerdata != NULL);
15145
15146 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
15147
15150
15151 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
15152 {
15153 if( !SCIPisExprVar(scip, expr) )
15154 continue;
15155
15156 ownerdata = SCIPexprGetOwnerData(expr);
15157 assert(ownerdata != NULL);
15158
15159 for( c = 0; c < ownerdata->nconss; ++c )
15160 {
15161 consdata = SCIPconsGetData(ownerdata->conss[c]);
15162 assert(consdata != NULL);
15163 consdata->ispropagated = FALSE;
15164 }
15165 }
15166
15167 SCIPfreeExpriter(&it);
15168
15169 return SCIP_OKAY;
15170}
15171
15172/** adds violation-branching score to an expression
15173 *
15174 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
15175 * The expression must either be a variable expression or have an aux-variable.
15176 * In the latter case, branching on auxiliary variables must have been enabled.
15177 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
15178 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
15179 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
15180 *
15181 * @see SCIPaddExprsViolScoreNonlinear()
15182 */
15184 SCIP* scip, /**< SCIP data structure */
15185 SCIP_EXPR* expr, /**< expression where to add branching score */
15186 SCIP_Real violscore /**< violation score to add to expression */
15187 )
15188{
15189 SCIP_EXPR_OWNERDATA* ownerdata;
15190 SCIP_CONSHDLRDATA* conshdlrdata;
15191
15192 assert(scip != NULL);
15193 assert(expr != NULL);
15194 assert(violscore >= 0.0);
15195
15196 ownerdata = SCIPexprGetOwnerData(expr);
15197 assert(ownerdata != NULL);
15198
15199 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15200 assert(conshdlrdata != NULL);
15201
15202 /* if not allowing to branch on auxvars, then expr must be a var-expr */
15203 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
15204 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
15205 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
15206
15207 /* reset branching score if we are in a different enfo round */
15208 if( ownerdata->violscoretag != conshdlrdata->enforound )
15209 {
15210 ownerdata->violscoresum = violscore;
15211 ownerdata->violscoremax = violscore;
15212 ownerdata->nviolscores = 1;
15213 ownerdata->violscoretag = conshdlrdata->enforound;
15214 return;
15215 }
15216
15217 ownerdata->violscoresum += violscore;
15218 if( violscore > ownerdata->violscoremax )
15219 ownerdata->violscoremax = violscore;
15220 ++ownerdata->nviolscores;
15221}
15222
15223/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
15224 *
15225 * Each expression must either be a variable expression or have an aux-variable.
15226 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
15227 * variables present in `exprs`.
15228 */
15230 SCIP* scip, /**< SCIP data structure */
15231 SCIP_EXPR** exprs, /**< expressions where to add branching score */
15232 int nexprs, /**< number of expressions */
15233 SCIP_Real violscore, /**< violation score to add to expression */
15234 SCIP_SOL* sol, /**< current solution */
15235 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
15236 )
15237{
15238 SCIP_EXPRITER* it;
15239 SCIP_EXPR** varexprs;
15240 SCIP_EXPR* e;
15241 int nvars;
15242 int varssize;
15243 int i;
15244
15245 assert(exprs != NULL || nexprs == 0);
15246 assert(success != NULL);
15247
15248 if( nexprs == 0 )
15249 {
15250 *success = FALSE;
15251 return SCIP_OKAY;
15252 }
15253
15254 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
15255 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
15256 {
15257 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15258 return SCIP_OKAY;
15259 }
15260
15261 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15262 nvars = 0;
15263 varssize = 5;
15264 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15265
15268
15269 for( i = 0; i < nexprs; ++i )
15270 {
15271 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15272 {
15273 assert(e != NULL);
15274
15275 if( SCIPisExprVar(scip, e) )
15276 {
15277 /* add variable expression to vars array */
15278 if( varssize == nvars )
15279 {
15280 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15281 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15282 }
15283 assert(varssize > nvars);
15284
15285 varexprs[nvars++] = e;
15286 }
15287 }
15288 }
15289
15290 SCIPfreeExpriter(&it);
15291
15292 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15293
15294 SCIPfreeBufferArray(scip, &varexprs);
15295
15296 return SCIP_OKAY;
15297}
15298
15299/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15301 SCIP_EXPR* expr /**< expression */
15302 )
15303{
15304 SCIP_EXPR_OWNERDATA* ownerdata;
15305 SCIP_CONSHDLRDATA* conshdlrdata;
15306
15307 assert(expr != NULL);
15308
15309 ownerdata = SCIPexprGetOwnerData(expr);
15310 assert(ownerdata != NULL);
15311
15312 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15313 assert(conshdlrdata != NULL);
15314
15315 if( conshdlrdata->enforound != ownerdata->violscoretag )
15316 return 0.0;
15317
15318 if( ownerdata->nviolscores == 0 )
15319 return 0.0;
15320
15321 switch( conshdlrdata->branchscoreagg )
15322 {
15323 case 'a' :
15324 /* average */
15325 return ownerdata->violscoresum / ownerdata->nviolscores;
15326
15327 case 'm' :
15328 /* maximum */
15329 return ownerdata->violscoremax;
15330
15331 case 's' :
15332 /* sum */
15333 return ownerdata->violscoresum;
15334
15335 default:
15336 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15337 SCIPABORT();
15338 return SCIP_INVALID;
15339 }
15340}
15341
15342/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15343 *
15344 * @see SCIPexprGetDerivative()
15345 */
15347 SCIP* scip, /**< SCIP data structure */
15348 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15349 SCIP_VAR* var /**< variable (needs to be in the expression) */
15350 )
15351{
15352 SCIP_EXPR_OWNERDATA* ownerdata;
15353 SCIP_CONSHDLRDATA* conshdlrdata;
15354 SCIP_EXPR* varexpr;
15355
15356 assert(scip != NULL);
15357 assert(expr != NULL);
15358 assert(var != NULL);
15359
15360 /* return 0.0 for value expression */
15361 if( SCIPisExprValue(scip, expr) )
15362 {
15363 assert(SCIPexprGetDerivative(expr) == 0.0);
15364 return 0.0;
15365 }
15366
15367 /* check if an error occurred during the last SCIPevalExprGradient() call */
15368 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15369 return SCIP_INVALID;
15370
15371 ownerdata = SCIPexprGetOwnerData(expr);
15372 assert(ownerdata != NULL);
15373
15374 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15375 assert(conshdlrdata != NULL);
15376
15377 /* use variable to expressions mapping which is stored in the constraint handler data */
15378 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15379
15380 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15381 assert(varexpr != NULL);
15382 assert(SCIPisExprVar(scip, varexpr));
15383
15384 /* use difftag to decide whether the variable belongs to the expression */
15385 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15386}
15387
15388/** 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)
15389 *
15390 * @see SCIPexprGetBardot()
15391 */
15393 SCIP* scip, /**< SCIP data structure */
15394 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15395 SCIP_VAR* var /**< variable (needs to be in the expression) */
15396 )
15397{
15398 SCIP_EXPR_OWNERDATA* ownerdata;
15399 SCIP_CONSHDLRDATA* conshdlrdata;
15400 SCIP_EXPR* varexpr;
15401
15402 assert(scip != NULL);
15403 assert(expr != NULL);
15404 assert(var != NULL);
15405
15406 /* return 0.0 for value expression */
15407 if( SCIPisExprValue(scip, expr) )
15408 return 0.0;
15409
15410 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15411 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15412 return SCIP_INVALID;
15413
15414 ownerdata = SCIPexprGetOwnerData(expr);
15415 assert(ownerdata != NULL);
15416
15417 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15418 assert(conshdlrdata != NULL);
15419
15420 /* use variable to expressions mapping which is stored in the constraint handler data;
15421 * if this fails it means that we are asking for the var's component of H*u for a var
15422 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15423 */
15424 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15425
15426 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15427 assert(varexpr != NULL);
15428 assert(SCIPisExprVar(scip, varexpr));
15429
15430 /* use difftag to decide whether the variable belongs to the expression */
15431 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15432}
15433
15434/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15435 *
15436 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15437 */
15439 SCIP* scip, /**< SCIP data structure */
15440 SCIP_EXPR* expr, /**< quadratic expression */
15441 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15442 )
15443{
15444 SCIP_Real auxvalue;
15445 int nlinexprs;
15446 SCIP_Real* lincoefs;
15447 SCIP_EXPR** linexprs;
15448 int nquadexprs;
15449 int nbilinexprs;
15450 int i;
15451
15452 assert(scip != NULL);
15453 assert(expr != NULL);
15454
15455 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15456
15457 /* linear terms */
15458 for( i = 0; i < nlinexprs; ++i )
15459 {
15460 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15461 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15462 }
15463
15464 /* quadratic terms */
15465 for( i = 0; i < nquadexprs; ++i )
15466 {
15467 SCIP_EXPR* quadexprterm;
15468 SCIP_Real lincoef;
15469 SCIP_Real sqrcoef;
15470 SCIP_Real solval;
15471
15472 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15473
15474 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15475
15476 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15477 auxvalue += (lincoef + sqrcoef * solval) * solval;
15478 }
15479
15480 /* bilinear terms */
15481 for( i = 0; i < nbilinexprs; ++i )
15482 {
15483 SCIP_EXPR* expr1;
15484 SCIP_EXPR* expr2;
15485 SCIP_Real coef;
15486
15487 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15488
15492 }
15493
15494 return auxvalue;
15495}
15496
15497/**@addtogroup PublicNlhdlrInterfaceMethods
15498 * @{
15499 */
15500
15501/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15503 SCIP* scip, /**< SCIP data structure */
15504 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15505 const char* name, /**< name of nonlinear handler (must not be NULL) */
15506 const char* desc, /**< description of nonlinear handler (can be NULL) */
15507 int detectpriority, /**< detection priority of nonlinear handler */
15508 int enfopriority, /**< enforcement priority of nonlinear handler */
15509 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15510 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15511 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15512 )
15513{
15514 SCIP_CONSHDLR* conshdlr;
15515 SCIP_CONSHDLRDATA* conshdlrdata;
15516
15517 assert(scip != NULL);
15518 assert(nlhdlr != NULL);
15519 assert(detect != NULL);
15520
15521 /* find myself */
15522 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15523 if( conshdlr == NULL )
15524 {
15525 SCIPerrorMessage("nonlinear constraint handler not found");
15526 return SCIP_PLUGINNOTFOUND;
15527 }
15528
15529 /* create nlhdlr */
15530 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15531
15532 /* include into constraint handler */
15533 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15534 assert(conshdlrdata != NULL);
15535
15536 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15537
15538 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15539 ++conshdlrdata->nnlhdlrs;
15540
15541 /* sort nonlinear handlers by detection priority, in decreasing order
15542 * will happen in INIT, so only do when called late
15543 */
15544 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15545 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15546
15547 return SCIP_OKAY;
15548}
15549
15550/** get number of nonlinear handler */
15552 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15553 )
15554{
15555 SCIP_CONSHDLRDATA* conshdlrdata;
15556
15557 assert(conshdlr != NULL);
15558
15559 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15560 assert(conshdlrdata != NULL);
15561
15562 return conshdlrdata->nnlhdlrs;
15563}
15564
15565/** get nonlinear handlers */
15567 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15568 )
15569{
15570 SCIP_CONSHDLRDATA* conshdlrdata;
15571
15572 assert(conshdlr != NULL);
15573
15574 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15575 assert(conshdlrdata != NULL);
15576
15577 return conshdlrdata->nlhdlrs;
15578}
15579
15580/** returns a nonlinear handler of a given name (or NULL if not found) */
15582 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15583 const char* name /**< name of nonlinear handler */
15584 )
15585{
15586 SCIP_CONSHDLRDATA* conshdlrdata;
15587 int h;
15588
15589 assert(conshdlr != NULL);
15590 assert(name != NULL);
15591
15592 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15593 assert(conshdlrdata != NULL);
15594
15595 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15596 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15597 return conshdlrdata->nlhdlrs[h];
15598
15599 return NULL;
15600}
15601
15602/** gives expression data that a given nonlinear handler stored in an expression
15603 *
15604 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15605 */
15607 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15608 SCIP_EXPR* expr /**< expression */
15609 )
15610{
15611 SCIP_EXPR_OWNERDATA* ownerdata;
15612 int e;
15613
15614 assert(nlhdlr != NULL);
15615 assert(expr != NULL);
15616
15617 ownerdata = SCIPexprGetOwnerData(expr);
15618 assert(ownerdata != NULL);
15619
15620 for( e = 0; e < ownerdata->nenfos; ++e )
15621 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15622 return ownerdata->enfos[e]->nlhdlrexprdata;
15623
15624 return NULL;
15625}
15626
15627/** @} */
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 the set partitioning / packing / covering constraints .
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)
SCIP_RETCODE SCIPcreateConsBasicSetcover(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
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)
SCIP_RETCODE SCIPcreateConsBasicSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
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:4350
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5116
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4782
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
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:4739
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition cons.c:8511
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition cons.c:8692
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
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:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition cons.c:8490
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition cons.c:8500
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
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:23684
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23479
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:23387
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23499
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24269
SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
Definition var.c:23507
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23901
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition var.c:23619
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:23454
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24143
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23653
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:23268
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:23491
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition scip_var.c:10113
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition scip_var.c:2166
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24643
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24235
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24654
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24121
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
Definition var.c:23464
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17275
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:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#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:867
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
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:736
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:920
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:691
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:706
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSENABLE(x)
Definition type_cons.h:721
#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:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
#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:753
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