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
11100
11101 /* create basic data of constraint handler and include it to scip */
11103
11104 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11105 assert(targetconshdlr != NULL);
11106 assert(targetconshdlr != conshdlr);
11107
11108 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
11109 assert(sourceconshdlrdata != NULL);
11110
11111 /* copy nonlinear handlers */
11112 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
11113 {
11114 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
11115 }
11116
11117 *valid = TRUE;
11118
11119 return SCIP_OKAY;
11120}
11121
11122/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11123static
11124SCIP_DECL_CONSFREE(consFreeNonlinear)
11125{ /*lint --e{715}*/
11126 SCIP_CONSHDLRDATA* conshdlrdata;
11127 int i;
11128
11129 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11130 assert(conshdlrdata != NULL);
11131
11132 /* free nonlinear handlers */
11133 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11134 {
11135 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11136 assert(conshdlrdata->nlhdlrs[i] == NULL);
11137 }
11138 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11139 conshdlrdata->nlhdlrssize = 0;
11140
11141 /* free upgrade functions */
11142 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11143 {
11144 assert(conshdlrdata->consupgrades[i] != NULL);
11145 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11146 }
11147 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11148
11149 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11150
11151 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11152
11153 if( conshdlrdata->vp_randnumgen != NULL )
11154 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11155
11156 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11157 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11158 {
11159 if( conshdlrdata->vp_lp[i] != NULL )
11160 {
11161 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11162 }
11163 }
11164
11165 assert(conshdlrdata->branchrandnumgen == NULL);
11166
11167 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11168 SCIPhashmapFree(&conshdlrdata->var2expr);
11169
11170 SCIPfreeBlockMemory(scip, &conshdlrdata);
11171 SCIPconshdlrSetData(conshdlr, NULL);
11172
11173 return SCIP_OKAY;
11174}
11175
11176
11177/** initialization method of constraint handler (called after problem was transformed) */
11178static
11179SCIP_DECL_CONSINIT(consInitNonlinear)
11180{ /*lint --e{715}*/
11181 SCIP_CONSHDLRDATA* conshdlrdata;
11182 int i;
11183
11184 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11185 assert(conshdlrdata != NULL);
11186
11187 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11188 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11189 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11190 conshdlrdata->enforound = 1;
11191 /* reset numbering for auxiliary variables */
11192 conshdlrdata->auxvarid = 0;
11193
11194 for( i = 0; i < nconss; ++i )
11195 {
11196 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11197 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11198 }
11199
11200 /* sort nonlinear handlers by detection priority, in decreasing order */
11201 if( conshdlrdata->nnlhdlrs > 1 )
11202 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11203
11204 /* get heuristics for later use */
11205 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11206 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11207
11208 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11209 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11210 {
11211 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11212 }
11213
11214 /* reset statistics in constraint handler */
11215 conshdlrdata->nweaksepa = 0;
11216 conshdlrdata->ntightenlp = 0;
11217 conshdlrdata->ndesperatebranch = 0;
11218 conshdlrdata->ndesperatecutoff = 0;
11219 conshdlrdata->ndesperatetightenlp = 0;
11220 conshdlrdata->nforcelp = 0;
11221 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11222 conshdlrdata->ncanonicalizecalls = 0;
11223
11224#ifdef ENFOLOGFILE
11225 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11226#endif
11227
11228 return SCIP_OKAY;
11229}
11230
11231
11232/** deinitialization method of constraint handler (called before transformed problem is freed) */
11233static
11234SCIP_DECL_CONSEXIT(consExitNonlinear)
11235{ /*lint --e{715}*/
11236 SCIP_CONSHDLRDATA* conshdlrdata;
11237 SCIP_CONS** consssorted;
11238 int i;
11239
11240 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11241 assert(conshdlrdata != NULL);
11242
11243 if( nconss > 0 )
11244 {
11245 /* for better performance of dropVarEvents, we sort by index, descending */
11246 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11247 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11248
11249 for( i = 0; i < nconss; ++i )
11250 {
11251 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11252 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11253 }
11254
11255 SCIPfreeBufferArray(scip, &consssorted);
11256 }
11257
11258 conshdlrdata->subnlpheur = NULL;
11259 conshdlrdata->trysolheur = NULL;
11260
11261 if( conshdlrdata->vp_randnumgen != NULL )
11262 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11263
11264 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11265 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11266 {
11267 if( conshdlrdata->vp_lp[i] != NULL )
11268 {
11269 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11270 }
11271 }
11272
11273 if( conshdlrdata->branchrandnumgen != NULL )
11274 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11275
11276 /* deinitialize nonlinear handlers */
11277 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11278 {
11279 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11280 }
11281
11282 ENFOLOG(
11283 if( enfologfile != NULL )
11284 {
11285 fclose(enfologfile);
11286 enfologfile = NULL;
11287 })
11288
11289 return SCIP_OKAY;
11290}
11291
11292
11293/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11294#ifdef SCIP_DISABLED_CODE
11295static
11297{ /*lint --e{715}*/
11298 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11299 SCIPABORT(); /*lint --e{527}*/
11300
11301 return SCIP_OKAY;
11302}
11303#else
11304#define consInitpreNonlinear NULL
11305#endif
11306
11307
11308/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11309static
11310SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11311{ /*lint --e{715}*/
11312 SCIP_Bool infeasible;
11313
11314 if( nconss == 0 )
11315 return SCIP_OKAY;
11316
11317 /* skip some extra work if already known to be infeasible */
11319 return SCIP_OKAY;
11320
11321 /* simplify constraints and replace common subexpressions */
11322 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11323
11324 /* currently SCIP does not offer to communicate this,
11325 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11326 * or if a constraint expression became constant
11327 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11328 */
11329 /* assert(!infeasible); */
11330
11331 /* tell SCIP that we have something nonlinear */
11333
11334 return SCIP_OKAY;
11335}
11336
11337
11338/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11339static
11340SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11341{ /*lint --e{715}*/
11342 SCIP_CONSHDLRDATA* conshdlrdata;
11343 int i;
11344
11345 /* skip remaining initializations if we have solved already
11346 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11347 * assumes nonempty activities in expressions
11348 */
11349 switch( SCIPgetStatus(scip) )
11350 {
11355 return SCIP_OKAY;
11356 default: ;
11357 } /*lint !e788 */
11358
11359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11360 assert(conshdlrdata != NULL);
11361
11362 /* reset one of the number of detections counter to count only current round */
11363 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11364 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11365
11366 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11367
11368 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11369 if( conshdlrdata->branchpscostweight > 0.0 )
11370 {
11371 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11372 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11373 {
11374 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11375 SCIPABORT();
11376 return SCIP_INVALIDDATA;
11377 }
11378 }
11379
11380 return SCIP_OKAY;
11381}
11382
11383
11384/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11385static
11386SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11387{ /*lint --e{715}*/
11388 SCIP_CONSHDLRDATA* conshdlrdata;
11389
11390 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11391
11392 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11393 assert(conshdlrdata != NULL);
11394
11395 /* free hash table for bilinear terms */
11396 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11397
11398 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11399 conshdlrdata->checkedvarlocks = FALSE;
11400
11401 /* drop catching new solution event, if catched before */
11402 if( conshdlrdata->newsoleventfilterpos >= 0 )
11403 {
11404 SCIP_EVENTHDLR* eventhdlr;
11405
11406 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11407 assert(eventhdlr != NULL);
11408
11409 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11410 conshdlrdata->newsoleventfilterpos = -1;
11411 }
11412
11413 return SCIP_OKAY;
11414}
11415
11416
11417/** frees specific constraint data */
11418static
11419SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11420{ /*lint --e{715}*/
11421 assert(consdata != NULL);
11422 assert(*consdata != NULL);
11423 assert((*consdata)->expr != NULL);
11424
11425 /* constraint locks should have been removed */
11426 assert((*consdata)->nlockspos == 0);
11427 assert((*consdata)->nlocksneg == 0);
11428
11429 /* free variable expressions */
11430 SCIP_CALL( freeVarExprs(scip, *consdata) );
11431
11432 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11433
11434 /* free nonlinear row representation */
11435 if( (*consdata)->nlrow != NULL )
11436 {
11437 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11438 }
11439
11440 SCIPfreeBlockMemory(scip, consdata);
11441
11442 return SCIP_OKAY;
11443}
11444
11445
11446/** transforms constraint data into data belonging to the transformed problem */
11447static
11448SCIP_DECL_CONSTRANS(consTransNonlinear)
11449{ /*lint --e{715}*/
11450 SCIP_EXPR* targetexpr;
11451 SCIP_CONSDATA* sourcedata;
11452
11453 sourcedata = SCIPconsGetData(sourcecons);
11454 assert(sourcedata != NULL);
11455
11456 /* get a copy of sourceexpr with transformed vars */
11457 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11458 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11459
11460 /* create transformed cons (only captures targetexpr, no need to copy again) */
11461 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11462 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11463 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11464 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11465 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11466 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11467
11468 /* release target expr */
11469 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11470
11471 return SCIP_OKAY;
11472}
11473
11474
11475/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11476static
11477SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11478{ /*lint --e{715}*/
11479 SCIP_CONSHDLRDATA* conshdlrdata;
11480
11481 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11482 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11483 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11484 * for now, there is an assert in detectNlhdlrs to require initial if separated
11485 */
11486 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11487
11488 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11489 assert(conshdlrdata != NULL);
11490
11491 /* catch new solution event */
11492 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11493 {
11494 SCIP_EVENTHDLR* eventhdlr;
11495
11496 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11497 assert(eventhdlr != NULL);
11498
11499 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11500 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11501 }
11502
11503 /* collect all bilinear terms for which an auxvar is present
11504 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11505 * addition (and removal?) of constraints during solve
11506 * this is typically the majority of constraints, but the method should be made more flexible
11507 */
11508 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11509
11510 return SCIP_OKAY;
11511}
11512
11513
11514/** separation method of constraint handler for LP solutions */
11515static
11516SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11517{ /*lint --e{715}*/
11518 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11519
11520 return SCIP_OKAY;
11521}
11522
11523
11524/** separation method of constraint handler for arbitrary primal solutions */
11525static
11526SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11527{ /*lint --e{715}*/
11528 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11529
11530 return SCIP_OKAY;
11531}
11532
11533
11534/** constraint enforcing method of constraint handler for LP solutions */
11535static
11536SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11537{ /*lint --e{715}*/
11538 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11539
11540 return SCIP_OKAY;
11541}
11542
11543
11544/** constraint enforcing method of constraint handler for relaxation solutions */
11545static
11546SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11547{ /*lint --e{715}*/
11548 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11549
11550 return SCIP_OKAY;
11551}
11552
11553
11554/** constraint enforcing method of constraint handler for pseudo solutions */
11555static
11556SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11557{ /*lint --e{715}*/
11558 SCIP_RESULT propresult;
11559 SCIP_Longint soltag;
11560 int nchgbds;
11561 int nnotify;
11562 int c;
11563
11564 soltag = SCIPgetExprNewSoltag(scip);
11565
11567 for( c = 0; c < nconss; ++c )
11568 {
11569 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11570
11571 if( isConsViolated(scip, conss[c]) )
11573 }
11574
11575 if( *result == SCIP_FEASIBLE )
11576 return SCIP_OKAY;
11577
11578 /* try to propagate
11579 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11580 */
11581 nchgbds = 0;
11582 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11583
11584 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11585 {
11586 *result = propresult;
11587 return SCIP_OKAY;
11588 }
11589
11590 /* register all unfixed variables in all violated constraints as branching candidates */
11591 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11592 if( nnotify > 0 )
11593 {
11594 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11595
11596 return SCIP_OKAY;
11597 }
11598
11599 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11601 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11602
11603 return SCIP_OKAY;
11604}
11605
11606
11607/** feasibility check method of constraint handler for integral solutions */
11608static
11609SCIP_DECL_CONSCHECK(consCheckNonlinear)
11610{ /*lint --e{715}*/
11611 SCIP_CONSHDLRDATA* conshdlrdata;
11612 SCIP_CONSDATA* consdata;
11613 SCIP_Real maxviol;
11614 SCIP_Bool maypropfeasible;
11615 SCIP_Longint soltag;
11616 int c;
11617
11618 assert(scip != NULL);
11619 assert(conshdlr != NULL);
11620 assert(conss != NULL || nconss == 0);
11621 assert(result != NULL);
11622
11623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11624 assert(conshdlrdata != NULL);
11625
11627 soltag = SCIPgetExprNewSoltag(scip);
11628 maxviol = 0.0;
11629 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11631
11633 maypropfeasible = FALSE;
11634
11635 /* check nonlinear constraints for feasibility */
11636 for( c = 0; c < nconss; ++c )
11637 {
11638 SCIP_Real absviol;
11639 SCIP_Real relviol;
11640
11641 assert(conss != NULL && conss[c] != NULL);
11642 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11643
11644 absviol = getConsAbsViolation(conss[c]);
11645 SCIP_CALL( getConsRelViolation(scip, conss[c], &relviol, sol, soltag) );
11646 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
11647
11648 if( absviol > SCIPfeastol(scip) )
11649 {
11651 maxviol = MAX(maxviol, absviol);
11652
11653 consdata = SCIPconsGetData(conss[c]);
11654 assert(consdata != NULL);
11655
11656 /* print reason for infeasibility */
11657 if( printreason )
11658 {
11659 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11660 SCIPinfoMessage(scip, NULL, ";\n");
11661
11662 if( consdata->lhsviol > SCIPfeastol(scip) )
11663 {
11664 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11665 }
11666 if( consdata->rhsviol > SCIPfeastol(scip) )
11667 {
11668 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11669 }
11670 }
11671 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11672 {
11673 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11674 return SCIP_OKAY;
11675 }
11676
11677 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11678 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11679 maypropfeasible = FALSE;
11680
11681 if( maypropfeasible )
11682 {
11683 if( consdata->lhsviol > SCIPfeastol(scip) )
11684 {
11685 /* check if there is a variable which may help to get the left hand side satisfied
11686 * if there is no such variable, then we cannot get feasible
11687 */
11688 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11689 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11690 maypropfeasible = FALSE;
11691 }
11692 else
11693 {
11694 assert(consdata->rhsviol > SCIPfeastol(scip));
11695 /* check if there is a variable which may help to get the right hand side satisfied
11696 * if there is no such variable, then we cannot get feasible
11697 */
11698 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11699 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11700 maypropfeasible = FALSE;
11701 }
11702 }
11703 }
11704 }
11705
11706 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11707 {
11708 SCIP_Bool success;
11709
11710 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11711
11712 /* do not pass solution to NLP heuristic if we made it feasible this way */
11713 if( success )
11714 return SCIP_OKAY;
11715 }
11716
11717 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11718 {
11719 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11720 }
11721
11722 return SCIP_OKAY;
11723}
11724
11725
11726/** domain propagation method of constraint handler */
11727static
11728SCIP_DECL_CONSPROP(consPropNonlinear)
11729{ /*lint --e{715}*/
11730 int nchgbds = 0;
11731
11732 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11733 assert(nchgbds >= 0);
11734
11735 /* TODO would it make sense to check for redundant constraints? */
11736
11737 return SCIP_OKAY;
11738}
11739
11740
11741/** presolving method of constraint handler */
11742static
11743SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11744{ /*lint --e{715}*/
11745 SCIP_CONSHDLRDATA* conshdlrdata;
11746 SCIP_Bool infeasible;
11747 int c;
11748
11750
11751 if( nconss == 0 )
11752 {
11754 return SCIP_OKAY;
11755 }
11756
11757 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11758 assert(conshdlrdata != NULL);
11759
11760 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11761 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11762 if( infeasible )
11763 {
11765 return SCIP_OKAY;
11766 }
11767
11768 /* merge constraints with the same root expression */
11769 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11770 {
11771 SCIP_Bool success;
11772
11773 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11774 if( success )
11776 }
11777
11778 /* propagate constraints */
11779 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11780 if( *result == SCIP_CUTOFF )
11781 return SCIP_OKAY;
11782
11783 /* propagate function domains (TODO integrate with simplify?) */
11784 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11785 {
11786 SCIP_RESULT localresult;
11787 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11788 if( localresult == SCIP_CUTOFF )
11789 {
11791 return SCIP_OKAY;
11792 }
11793 if( localresult == SCIP_REDUCEDDOM )
11795 }
11796
11797 /* check for redundant constraints, remove constraints that are a value expression */
11798 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11799 if( infeasible )
11800 {
11802 return SCIP_OKAY;
11803 }
11804
11805 /* try to upgrade constraints */
11806 for( c = 0; c < nconss; ++c )
11807 {
11808 SCIP_Bool upgraded;
11809
11810 /* skip inactive and deleted constraints */
11811 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11812 continue;
11813
11814 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11815 }
11816
11817 /* try to change continuous variables that appear linearly to be implicit integer */
11818 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11819 {
11820 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11821
11822 if( infeasible )
11823 {
11824 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11826 return SCIP_OKAY;
11827 }
11828 }
11829
11830 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11832 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11833 {
11834 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11835 * constraints multiple times
11836 */
11837 conshdlrdata->checkedvarlocks = TRUE;
11838
11839 for( c = 0; c < nconss; ++c )
11840 {
11841 int tmpnchgvartypes = 0;
11842 int tmpnaddconss = 0;
11843
11844 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11845 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11846 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11847
11848 if( infeasible )
11849 {
11850 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11852 return SCIP_OKAY;
11853 }
11854
11855 (*nchgvartypes) += tmpnchgvartypes;
11856 (*naddconss) += tmpnaddconss;
11857 }
11858 }
11859
11860 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11862 else
11864
11865 return SCIP_OKAY;
11866}
11867
11868
11869/** propagation conflict resolving method of constraint handler */
11870#ifdef SCIP_DISABLED_CODE
11871static
11873{ /*lint --e{715}*/
11874 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11875 SCIPABORT(); /*lint --e{527}*/
11876
11877 return SCIP_OKAY;
11878}
11879#else
11880#define consRespropNonlinear NULL
11881#endif
11882
11883
11884/** variable rounding lock method of constraint handler */
11885static
11886SCIP_DECL_CONSLOCK(consLockNonlinear)
11887{ /*lint --e{715}*/
11888 SCIP_CONSDATA* consdata;
11889 SCIP_EXPR_OWNERDATA* ownerdata;
11890 SCIP_Bool reinitsolve = FALSE;
11891
11892 assert(conshdlr != NULL);
11893 assert(cons != NULL);
11894
11895 consdata = SCIPconsGetData(cons);
11896 assert(consdata != NULL);
11897 assert(consdata->expr != NULL);
11898
11899 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11900
11901 /* check whether we need to initSolve again because
11902 * - we have enfo initialized (nenfos >= 0)
11903 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11904 */
11905 if( ownerdata->nenfos >= 0 )
11906 {
11907 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11908 reinitsolve = TRUE;
11909 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11910 reinitsolve = TRUE;
11911 }
11912
11913 if( reinitsolve )
11914 {
11915 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11916 }
11917
11918 /* add locks */
11919 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11920
11921 if( reinitsolve )
11922 {
11923 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11924 }
11925
11926 return SCIP_OKAY;
11927}
11928
11929
11930/** constraint activation notification method of constraint handler */
11931static
11932SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11933{ /*lint --e{715}*/
11934 SCIP_CONSDATA* consdata;
11935 SCIP_Bool infeasible = FALSE;
11936
11937 consdata = SCIPconsGetData(cons);
11938 assert(consdata != NULL);
11939
11940 /* simplify root expression if the constraint has been added after presolving */
11942 {
11943 SCIP_Bool replacedroot;
11944
11945 if( !consdata->issimplified )
11946 {
11947 SCIP_EXPR* simplified;
11948 SCIP_Bool changed;
11949
11950 /* simplify constraint */
11951 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11952 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11953 assert(simplified != NULL);
11954 consdata->expr = simplified;
11955 consdata->issimplified = TRUE;
11956 }
11957
11958 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11959 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11960 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11961
11962 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11963 {
11964 SCIP_CONSHDLRDATA* conshdlrdata;
11965 SCIP_EXPRITER* it;
11966 SCIP_EXPR* expr;
11967
11968 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11969 assert(conshdlrdata != NULL);
11970
11972 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11974 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11975 {
11976 SCIP_EXPR* child;
11977 SCIP_EXPR* hashmapexpr;
11978
11979 child = SCIPexpriterGetChildExprDFS(it);
11980 if( !SCIPisExprVar(scip, child) )
11981 continue;
11982
11983 /* check which expression is stored in the hashmap for the var of child */
11984 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11985 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11986 if( hashmapexpr != NULL && hashmapexpr != child )
11987 {
11989 }
11990 }
11991 SCIPfreeExpriter(&it);
11992 }
11993 }
11994
11995 /* store variable expressions */
11997 {
11998 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11999 }
12000
12001 /* add manually locks to constraints that are not checked for feasibility */
12002 if( !SCIPconsIsChecked(cons) )
12003 {
12004 assert(consdata->nlockspos == 0);
12005 assert(consdata->nlocksneg == 0);
12006
12007 SCIP_CALL( addLocks(scip, cons, 1, 0) );
12008 }
12009
12010 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
12011 {
12012 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
12013 }
12014
12015 /* TODO deal with infeasibility */
12016 assert(!infeasible);
12017
12018 return SCIP_OKAY;
12019}
12020
12021
12022/** constraint deactivation notification method of constraint handler */
12023static
12024SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
12025{ /*lint --e{715}*/
12026 SCIP_CONSHDLRDATA* conshdlrdata;
12027
12028 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12029 assert(conshdlrdata != NULL);
12030
12032 {
12033 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
12034 }
12035
12037 {
12038 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12040 }
12041
12042 /* remove locks that have been added in consActiveExpr() */
12043 if( !SCIPconsIsChecked(cons) )
12044 {
12045 SCIP_CALL( addLocks(scip, cons, -1, 0) );
12046
12047 assert(SCIPconsGetData(cons)->nlockspos == 0);
12048 assert(SCIPconsGetData(cons)->nlocksneg == 0);
12049 }
12050
12051 return SCIP_OKAY;
12052}
12053
12054
12055/** constraint enabling notification method of constraint handler */
12056static
12057SCIP_DECL_CONSENABLE(consEnableNonlinear)
12058{ /*lint --e{715}*/
12059 SCIP_CONSHDLRDATA* conshdlrdata;
12060
12061 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12062 assert(conshdlrdata != NULL);
12063
12065 {
12066 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12067 }
12068
12069 return SCIP_OKAY;
12070}
12071
12072
12073/** constraint disabling notification method of constraint handler */
12074static
12075SCIP_DECL_CONSDISABLE(consDisableNonlinear)
12076{ /*lint --e{715}*/
12077 SCIP_CONSHDLRDATA* conshdlrdata;
12078
12079 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12080 assert(conshdlrdata != NULL);
12081
12083 {
12084 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12085 }
12086
12087 return SCIP_OKAY;
12088}
12089
12090/** variable deletion of constraint handler */
12091#ifdef SCIP_DISABLED_CODE
12092static
12094{ /*lint --e{715}*/
12095 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12096 SCIPABORT(); /*lint --e{527}*/
12097
12098 return SCIP_OKAY;
12099}
12100#else
12101#define consDelvarsNonlinear NULL
12102#endif
12103
12104
12105/** constraint display method of constraint handler */
12106static
12107SCIP_DECL_CONSPRINT(consPrintNonlinear)
12108{ /*lint --e{715}*/
12109 SCIP_CONSDATA* consdata;
12110
12111 consdata = SCIPconsGetData(cons);
12112 assert(consdata != NULL);
12113 assert(consdata->expr != NULL);
12114
12115 /* print left hand side for ranged constraints */
12116 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12117 {
12118 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12119 }
12120
12121 /* print expression */
12122 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
12123
12124 /* print right hand side */
12125 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12126 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12127 else if( !SCIPisInfinity(scip, consdata->rhs) )
12128 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12129 else if( !SCIPisInfinity(scip, -consdata->lhs) )
12130 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12131 else
12132 SCIPinfoMessage(scip, file, " [free]");
12133
12134 return SCIP_OKAY;
12135}
12136
12137
12138/** constraint copying method of constraint handler */
12139static
12140SCIP_DECL_CONSCOPY(consCopyNonlinear)
12141{ /*lint --e{715}*/
12142 SCIP_CONSHDLR* targetconshdlr;
12143 SCIP_EXPR* targetexpr = NULL;
12144 SCIP_CONSDATA* sourcedata;
12145
12146 assert(cons != NULL);
12147
12148 sourcedata = SCIPconsGetData(sourcecons);
12149 assert(sourcedata != NULL);
12150
12151 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12152 assert(targetconshdlr != NULL);
12153
12154 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12155
12156 if( targetexpr == NULL )
12157 *valid = FALSE;
12158
12159 *cons = NULL;
12160 if( *valid )
12161 {
12162 /* create copy (only capture targetexpr, no need to copy again) */
12163 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12164 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12165 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12166 }
12167
12168 if( targetexpr != NULL )
12169 {
12170 /* release target expr */
12171 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12172 }
12173
12174 return SCIP_OKAY;
12175}
12176
12177
12178/** constraint parsing method of constraint handler */
12179static
12180SCIP_DECL_CONSPARSE(consParseNonlinear)
12181{ /*lint --e{715}*/
12182 SCIP_Real lhs;
12183 SCIP_Real rhs;
12184 char* endptr;
12185 SCIP_EXPR* consexprtree;
12186
12187 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12188
12189 assert(scip != NULL);
12190 assert(success != NULL);
12191 assert(str != NULL);
12192 assert(name != NULL);
12193 assert(cons != NULL);
12194
12195 *success = FALSE;
12196
12197 /* return if string empty */
12198 if( !*str )
12199 return SCIP_OKAY;
12200
12201 endptr = (char*)str;
12202
12203 /* set left and right hand side to their default values */
12204 lhs = -SCIPinfinity(scip);
12205 rhs = SCIPinfinity(scip);
12206
12207 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12208
12209 /* check for left hand side */
12210 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12211 {
12212 /* there is a number coming, maybe it is a left-hand-side */
12213 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12214 {
12215 SCIPerrorMessage("error parsing number from <%s>\n", str);
12216 return SCIP_READERROR;
12217 }
12218
12219 /* ignore whitespace */
12220 SCIP_CALL( SCIPskipSpace(&endptr) );
12221
12222 if( endptr[0] != '<' || endptr[1] != '=' )
12223 {
12224 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12225 lhs = -SCIPinfinity(scip);
12226 }
12227 else
12228 {
12229 /* it was indeed a left-hand-side, so continue parsing after it */
12230 str = endptr + 2;
12231
12232 /* ignore whitespace */
12233 SCIP_CALL( SCIPskipSpace((char**)&str) );
12234 }
12235 }
12236
12237 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12238
12239 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12240 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12241
12242 /* check for left or right hand side */
12243 SCIP_CALL( SCIPskipSpace((char**)&str) );
12244
12245 /* check for free constraint */
12246 if( strncmp(str, "[free]", 6) == 0 )
12247 {
12248 if( !SCIPisInfinity(scip, -lhs) )
12249 {
12250 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12251 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12252 return SCIP_OKAY;
12253 }
12254 *success = TRUE;
12255 }
12256 else
12257 {
12258 switch( *str )
12259 {
12260 case '<':
12261 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12262 break;
12263 case '=':
12264 if( !SCIPisInfinity(scip, -lhs) )
12265 {
12266 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12267 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12268 return SCIP_OKAY;
12269 }
12270 else
12271 {
12272 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12273 lhs = rhs;
12274 }
12275 break;
12276 case '>':
12277 if( !SCIPisInfinity(scip, -lhs) )
12278 {
12279 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12280 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12281 return SCIP_OKAY;
12282 }
12283 else
12284 {
12285 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12286 break;
12287 }
12288 case '\0':
12289 *success = TRUE;
12290 break;
12291 default:
12292 SCIPerrorMessage("unexpected character %c\n", *str);
12293 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12294 return SCIP_OKAY;
12295 }
12296 }
12297
12298 /* create constraint */
12299 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12300 consexprtree, lhs, rhs, FALSE,
12301 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12302 assert(*cons != NULL);
12303
12304 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12305
12306 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12307
12308 return SCIP_OKAY;
12309}
12310
12311
12312/** constraint method of constraint handler which returns the variables (if possible) */
12313static
12314SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12315{ /*lint --e{715}*/
12316 SCIP_CONSDATA* consdata;
12317 int i;
12318
12319 consdata = SCIPconsGetData(cons);
12320 assert(consdata != NULL);
12321
12322 /* store variable expressions if not done so far */
12323 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12324
12325 /* check whether array is too small in order to store all variables */
12326 if( varssize < consdata->nvarexprs )
12327 {
12328 *success = FALSE;
12329 return SCIP_OKAY;
12330 }
12331
12332 for( i = 0; i < consdata->nvarexprs; ++i )
12333 {
12334 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12335 assert(vars[i] != NULL);
12336 }
12337
12338 *success = TRUE;
12339
12340 return SCIP_OKAY;
12341}
12342
12343/** constraint method of constraint handler which returns the number of variables (if possible) */
12344static
12345SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12346{ /*lint --e{715}*/
12347 SCIP_CONSDATA* consdata;
12348
12349 consdata = SCIPconsGetData(cons);
12350 assert(consdata != NULL);
12351
12352 /* store variable expressions if not done so far */
12353 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12354
12355 *nvars = consdata->nvarexprs;
12356 *success = TRUE;
12357
12358 return SCIP_OKAY;
12359}
12360
12361/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12362#ifdef SCIP_DISABLED_CODE
12363static
12365{ /*lint --e{715}*/
12366 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12367 SCIPABORT(); /*lint --e{527}*/
12368
12369 return SCIP_OKAY;
12370}
12371#else
12372#define consGetDiveBdChgsNonlinear NULL
12373#endif
12374
12375/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12376static
12377SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12378{ /*lint --e{715}*/
12379 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12380
12381 return SCIP_OKAY;
12382}
12383
12384/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12385static
12386SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12387{ /*lint --e{715}*/
12388 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12389
12390 return SCIP_OKAY;
12391}
12392
12393/** output method of cons_nonlinear statistics table to output file stream 'file' */
12394static
12395SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12396{ /*lint --e{715}*/
12397 SCIP_CONSHDLR* conshdlr;
12398 SCIP_CONSHDLRDATA* conshdlrdata;
12399
12400 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12401 assert(conshdlr != NULL);
12402
12403 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12404 assert(conshdlrdata != NULL);
12405
12406 /* print statistics for constraint handler */
12407 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12408 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12409 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12410 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12411 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12412 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12413 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12414 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12415 SCIPinfoMessage(scip, file, "\n");
12416 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12417 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12418 SCIPinfoMessage(scip, file, "\n");
12419
12420 return SCIP_OKAY;
12421}
12422
12423/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
12424static
12425SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
12426{
12427 SCIP_CONSHDLR* conshdlr;
12428 SCIP_CONSHDLRDATA* conshdlrdata;
12429
12430 assert(scip != NULL);
12431 assert(table != NULL);
12432 assert(datatree != NULL);
12433
12434 /* Find the constraint handler */
12435 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12436 assert(conshdlr != NULL);
12437
12438 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12439 assert(conshdlrdata != NULL);
12440
12441 /* Insert statistics */
12442 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
12443 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
12444 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
12445 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
12446 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
12447 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
12448 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
12449
12450 return SCIP_OKAY;
12451}
12452
12453/** output method of nlhdlr statistics table to output file stream 'file' */
12454static
12455SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12456{ /*lint --e{715}*/
12457 SCIP_CONSHDLR* conshdlr;
12458 SCIP_CONSHDLRDATA* conshdlrdata;
12459
12460 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12461 assert(conshdlr != NULL);
12462
12463 /* skip nlhdlr table if there never were active nonlinear constraints */
12464 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12465 return SCIP_OKAY;
12466
12467 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12468 assert(conshdlrdata != NULL);
12469
12470 /* print statistics for nonlinear handlers */
12471 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12472
12473 return SCIP_OKAY;
12474}
12475
12476/** collect method of nlhdlr statistics table to SCIP_DATATREE */
12477static
12478SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
12479{ /*lint --e{715}*/
12480 SCIP_CONSHDLR* conshdlr;
12481 SCIP_CONSHDLRDATA* conshdlrdata;
12482
12483 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12484 assert(conshdlr != NULL);
12485
12486 /* skip nlhdlr table if there never were active nonlinear constraints */
12487 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12488 return SCIP_OKAY;
12489
12490 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12491 assert(conshdlrdata != NULL);
12492
12493 /* collect statistics for nonlinear handlers */
12494 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
12495
12496 return SCIP_OKAY;
12497}
12498
12499/** execution method of display nlhdlrs dialog */
12500static
12501SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12502{ /*lint --e{715}*/
12503 SCIP_CONSHDLR* conshdlr;
12504 SCIP_CONSHDLRDATA* conshdlrdata;
12505 int i;
12506
12507 /* add dialog to history of dialogs that have been executed */
12508 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12509
12510 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12511 assert(conshdlr != NULL);
12512
12513 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12514 assert(conshdlrdata != NULL);
12515
12516 /* display list of nonlinear handler */
12517 SCIPdialogMessage(scip, NULL, "\n");
12518 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12519 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12520 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12521 {
12522 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12523 assert(nlhdlr != NULL);
12524
12525 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12526 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12529 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12530 SCIPdialogMessage(scip, NULL, "\n");
12531 }
12532 SCIPdialogMessage(scip, NULL, "\n");
12533
12534 /* next dialog will be root dialog again */
12535 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12536
12537 return SCIP_OKAY;
12538}
12539
12540/*
12541 * constraint handler specific interface methods
12542 */
12543
12544/** creates the handler for nonlinear constraints and includes it in SCIP */
12546 SCIP* scip /**< SCIP data structure */
12547 )
12548{
12549 SCIP_CONSHDLRDATA* conshdlrdata;
12550 SCIP_DIALOG* parentdialog;
12551
12552 /* create nonlinear constraint handler data */
12553 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12554 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12555 conshdlrdata->curboundstag = 1;
12556 conshdlrdata->lastboundrelax = 1;
12557 conshdlrdata->curpropboundstag = 1;
12558 conshdlrdata->newsoleventfilterpos = -1;
12559 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12560 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12561 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12562
12563 /* include constraint handler */
12569 conshdlrCopyNonlinear,
12570 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12571 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12572 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12573 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12574 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12575 consActiveNonlinear, consDeactiveNonlinear,
12576 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12577 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12578 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12579 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12580
12581 /* add nonlinear constraint handler parameters */
12582 /* TODO organize into more subcategories */
12583 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12584 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12585 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12586
12587 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12588 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12589 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12590
12591 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12592 "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",
12593 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12594
12595 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12596 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12597 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12598
12599 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12600 "by how much to relax constraint sides during bound tightening",
12601 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12602
12603 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12604 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12605 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12606
12607 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12608 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12609 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12610
12611 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12612 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12613 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12614
12615 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12616 "maximal number of auxiliary expressions per bilinear term",
12617 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12618
12619 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12620 "whether to reformulate products of binary variables during presolving",
12621 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12622
12623 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12624 "whether to use the AND constraint handler for reformulating binary products",
12625 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12626
12627 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12628 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12629 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12630
12631 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12632 "whether to forbid multiaggregation of nonlinear variables",
12633 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12634
12635 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12636 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12637 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12638
12639 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12640 "whether to (re)run propagation in enforcement",
12641 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12642
12643 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12644 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12645 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12646
12647 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12648 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12649 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12650
12651 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12652 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12653 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12654
12655 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12656 "whether to force \"strong\" cuts in enforcement",
12657 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12658
12659 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12660 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12661 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12662
12663 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12664 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12665 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12666
12667 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12668 "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",
12669 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12670
12671 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12672 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12673 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12674
12675 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12676 "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)",
12677 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12678
12679 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12680 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12681 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12682
12683 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12684 "whether to use external branching candidates and branching rules for branching",
12685 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12686
12687 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12688 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12689 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12690
12691 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12692 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12693 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12694
12695 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12696 "weight by how much to consider the violation assigned to a variable for its branching score",
12697 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12698
12699 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12700 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12701 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12702
12703 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12704 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12705 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12706
12707 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12708 "weight by how much to consider the pseudo cost of a variable for its branching score",
12709 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12710
12711 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12712 "weight by how much to consider the domain width in branching score",
12713 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12714
12715 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12716 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12717 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12718
12719 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12720 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12721 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12722
12723 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12724 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12725 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12726
12727 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12728 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12729 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12730
12731 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12732 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12733 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12734
12735 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12736 "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)",
12737 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12738
12739 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12740 "whether to assume that any constraint in the presolved problem is convex",
12741 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
12742
12743 /* include handler for bound change events */
12744 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12745 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12746 assert(conshdlrdata->eventhdlr != NULL);
12747
12748 /* include tables for statistics */
12751 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
12753
12756 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
12758
12759 /* create, include, and release display nlhdlrs dialog */
12760 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12761 {
12762 SCIP_DIALOG* dialog;
12763
12764 assert(parentdialog != NULL);
12765 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12766
12768 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12770 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12771 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12772 }
12773
12774 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12775 processNewSolutionEvent, NULL) );
12776
12777 return SCIP_OKAY;
12778}
12779
12780/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12782 SCIP* scip, /**< SCIP data structure */
12783 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12784 int priority, /**< priority of upgrading method */
12785 SCIP_Bool active, /**< should the upgrading method by active by default? */
12786 const char* conshdlrname /**< name of the constraint handler */
12787 )
12788{
12789 SCIP_CONSHDLR* conshdlr;
12790 SCIP_CONSHDLRDATA* conshdlrdata;
12791 CONSUPGRADE* consupgrade;
12793 char paramdesc[SCIP_MAXSTRLEN];
12794 int i;
12795
12796 assert(conshdlrname != NULL );
12797 assert(nlconsupgd != NULL);
12798
12799 /* find the nonlinear constraint handler */
12800 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12801 if( conshdlr == NULL )
12802 {
12803 SCIPerrorMessage("nonlinear constraint handler not found\n");
12804 return SCIP_PLUGINNOTFOUND;
12805 }
12806
12807 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12808 assert(conshdlrdata != NULL);
12809
12810 /* check whether upgrade method exists already */
12811 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12812 {
12813 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12814 {
12815#ifdef SCIP_DEBUG
12816 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12817#endif
12818 return SCIP_OKAY;
12819 }
12820 }
12821
12822 /* create a nonlinear constraint upgrade data object */
12823 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12824 consupgrade->consupgd = nlconsupgd;
12825 consupgrade->priority = priority;
12826 consupgrade->active = active;
12827
12828 /* insert nonlinear constraint upgrade method into constraint handler data */
12829 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12830 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12831
12832 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12833 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12834 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12835 conshdlrdata->consupgrades[i] = consupgrade;
12836 conshdlrdata->nconsupgrades++;
12837
12838 /* adds parameter to turn on and off the upgrading step */
12839 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12840 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12842 paramname, paramdesc,
12843 &consupgrade->active, FALSE, active, NULL, NULL) );
12844
12845 return SCIP_OKAY;
12846}
12847
12848/** creates and captures a nonlinear constraint
12849 *
12850 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12851 */
12853 SCIP* scip, /**< SCIP data structure */
12854 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12855 const char* name, /**< name of constraint */
12856 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12857 SCIP_Real lhs, /**< left hand side of constraint */
12858 SCIP_Real rhs, /**< right hand side of constraint */
12859 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12860 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12861 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12862 * Usually set to TRUE. */
12863 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12864 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12865 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12866 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12867 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12868 * Usually set to TRUE. */
12869 SCIP_Bool local, /**< is constraint only valid locally?
12870 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12871 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12872 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12873 * adds coefficients to this constraint. */
12874 SCIP_Bool dynamic, /**< is constraint subject to aging?
12875 * Usually set to FALSE. Set to TRUE for own cuts which
12876 * are separated as constraints. */
12877 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12878 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12879 )
12880{
12881 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12882 SCIP_CONSHDLR* conshdlr;
12883
12884 /* find the nonlinear constraint handler */
12885 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12886 if( conshdlr == NULL )
12887 {
12888 SCIPerrorMessage("nonlinear constraint handler not found\n");
12889 return SCIP_PLUGINNOTFOUND;
12890 }
12891
12892 /* create constraint */
12893 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12894 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12895
12896 return SCIP_OKAY;
12897}
12898
12899/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12900 *
12901 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12902 *
12903 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12904 *
12905 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12906 */
12908 SCIP* scip, /**< SCIP data structure */
12909 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12910 const char* name, /**< name of constraint */
12911 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12912 SCIP_Real lhs, /**< left hand side of constraint */
12913 SCIP_Real rhs /**< right hand side of constraint */
12914 )
12915{
12916 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12918
12919 return SCIP_OKAY;
12920}
12921
12922/** creates and captures a quadratic nonlinear constraint
12923 *
12924 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12925 */
12927 SCIP* scip, /**< SCIP data structure */
12928 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12929 const char* name, /**< name of constraint */
12930 int nlinvars, /**< number of linear terms */
12931 SCIP_VAR** linvars, /**< array with variables in linear part */
12932 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12933 int nquadterms, /**< number of quadratic terms */
12934 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12935 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12936 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12937 SCIP_Real lhs, /**< left hand side of quadratic equation */
12938 SCIP_Real rhs, /**< right hand side of quadratic equation */
12939 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12940 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12941 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12942 * Usually set to TRUE. */
12943 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12944 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12945 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12946 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12947 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12948 * Usually set to TRUE. */
12949 SCIP_Bool local, /**< is constraint only valid locally?
12950 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12951 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12952 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12953 * adds coefficients to this constraint. */
12954 SCIP_Bool dynamic, /**< is constraint subject to aging?
12955 * Usually set to FALSE. Set to TRUE for own cuts which
12956 * are separated as constraints. */
12957 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12958 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12959 )
12960{
12961 SCIP_CONSHDLR* conshdlr;
12962 SCIP_EXPR* expr;
12963 int i;
12964
12965 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12966 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12967
12968 /* check data for infinity or nan values */
12969 for( i = 0; i < nlinvars; ++i )
12970 {
12971 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
12972 {
12973 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
12974 return SCIP_INVALIDDATA;
12975 }
12976 }
12977 for( i = 0; i < nquadterms; ++i )
12978 {
12979 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
12980 {
12981 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
12982 return SCIP_INVALIDDATA;
12983 }
12984 }
12985 /* lhs and rhs will be checked in createCons */
12986
12987 /* get nonlinear constraint handler */
12988 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12989 if( conshdlr == NULL )
12990 {
12991 SCIPerrorMessage("nonlinear constraint handler not found\n");
12992 return SCIP_PLUGINNOTFOUND;
12993 }
12994
12995 /* create quadratic expression */
12996 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12997 assert(expr != NULL);
12998
12999 /* create nonlinear constraint */
13000 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
13001 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13002
13003 /* release quadratic expression (captured by constraint now) */
13004 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13005
13006 return SCIP_OKAY;
13007}
13008
13009/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
13010 *
13011 * All flags can be set via SCIPconsSetFLAGNAME-methods.
13012 *
13013 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
13014 *
13015 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13016 */
13018 SCIP* scip, /**< SCIP data structure */
13019 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13020 const char* name, /**< name of constraint */
13021 int nlinvars, /**< number of linear terms */
13022 SCIP_VAR** linvars, /**< array with variables in linear part */
13023 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
13024 int nquadterms, /**< number of quadratic terms */
13025 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
13026 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
13027 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
13028 SCIP_Real lhs, /**< left hand side of quadratic equation */
13029 SCIP_Real rhs /**< right hand side of quadratic equation */
13030 )
13031{
13032 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
13034
13035 return SCIP_OKAY;
13036}
13037
13038/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
13039 *
13040 * \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$
13041 *
13042 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13043 */
13045 SCIP* scip, /**< SCIP data structure */
13046 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13047 const char* name, /**< name of constraint */
13048 int nvars, /**< number of variables on left hand side of constraint (n) */
13049 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
13050 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
13051 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
13052 SCIP_Real constant, /**< constant on left hand side (gamma) */
13053 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
13054 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
13055 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
13056 )
13057{
13058 SCIP_EXPR* expr;
13059 SCIP_EXPR* lhssum;
13060 SCIP_EXPR* terms[2];
13061 SCIP_Real termcoefs[2];
13062 int i;
13063
13064 assert(vars != NULL || nvars == 0);
13065
13066 /* check values for infinity or nan */
13067 for( i = 0; i < nvars; ++i )
13068 {
13069 if( coefs != NULL && ( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) ) )
13070 {
13071 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13072 return SCIP_INVALIDDATA;
13073 }
13074 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, offsets[i])) )
13075 {
13076 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13077 return SCIP_INVALIDDATA;
13078 }
13079 }
13080 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
13081 {
13082 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
13083 return SCIP_INVALIDDATA;
13084 }
13085 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
13086 {
13087 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
13088 return SCIP_INVALIDDATA;
13089 }
13090 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
13091 {
13092 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
13093 return SCIP_INVALIDDATA;
13094 }
13095 /* lhs and rhs will be checked in createCons */
13096
13097 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
13098 for( i = 0; i < nvars; ++i )
13099 {
13100 SCIP_EXPR* varexpr;
13101 SCIP_EXPR* powexpr;
13102
13103 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
13104 if( offsets != NULL && offsets[i] != 0.0 )
13105 {
13106 SCIP_EXPR* sum;
13107 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
13108 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
13109 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
13110 }
13111 else
13112 {
13113 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
13114 }
13115
13116 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
13117 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
13118 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
13119 }
13120
13121 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
13122 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
13123 termcoefs[0] = 1.0;
13124
13125 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
13126 termcoefs[1] = -rhscoeff;
13127
13128 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
13129
13130 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13131 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13132
13133 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
13134
13135 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13136
13137 return SCIP_OKAY;
13138}
13139
13140/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
13141 *
13142 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
13143 *
13144 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13145 */
13147 SCIP* scip, /**< SCIP data structure */
13148 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13149 const char* name, /**< name of constraint */
13150 SCIP_VAR* x, /**< nonlinear variable x in constraint */
13151 SCIP_VAR* z, /**< linear variable z in constraint */
13152 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
13153 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
13154 SCIP_Real zcoef, /**< coefficient of z in constraint */
13155 SCIP_Real lhs, /**< left hand side of constraint */
13156 SCIP_Real rhs /**< right hand side of constraint */
13157 )
13158{
13159 SCIP_EXPR* xexpr;
13160 SCIP_EXPR* terms[2];
13161 SCIP_Real coefs[2];
13162 SCIP_EXPR* sumexpr;
13163
13164 assert(x != NULL);
13165 assert(z != NULL);
13166
13167 if( !SCIPisFinite(exponent) )
13168 {
13169 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13170 return SCIP_INVALIDDATA;
13171 }
13172
13173 if( !SCIPisFinite(xoffset) )
13174 {
13175 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13176 return SCIP_INVALIDDATA;
13177 }
13178
13179 if( !SCIPisFinite(zcoef) )
13180 {
13181 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13182 return SCIP_INVALIDDATA;
13183 }
13184
13185 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
13186 if( xoffset != 0.0 )
13187 {
13188 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
13189 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
13190
13191 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13192 }
13193 else
13194 {
13195 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
13196 }
13197 coefs[0] = 1.0;
13198
13199 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
13200 coefs[1] = zcoef;
13201
13202 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
13203
13204 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
13205
13206 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13207 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13208 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13209 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
13210
13211 return SCIP_OKAY;
13212}
13213
13214/** gets tag indicating current local variable bounds */
13216 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13217 )
13218{
13219 SCIP_CONSHDLRDATA* conshdlrdata;
13220
13221 assert(conshdlr != NULL);
13222 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13223
13224 return conshdlrdata->curboundstag;
13225}
13226
13227/** gets the `curboundstag` from the last time where variable bounds were relaxed */
13229 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13230 )
13231{
13232 SCIP_CONSHDLRDATA* conshdlrdata;
13233
13234 assert(conshdlr != NULL);
13235 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13236
13237 return conshdlrdata->lastboundrelax;
13238}
13239
13240/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
13241 *
13242 * @attention This method is not intended for normal use.
13243 * These tags are maintained by the event handler for variable bound change events.
13244 * This method is used by some unittests.
13245 */
13247 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13248 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
13249 )
13250{
13251 SCIP_CONSHDLRDATA* conshdlrdata;
13252
13253 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13254 assert(conshdlrdata != NULL);
13255
13256 ++conshdlrdata->curboundstag;
13257 assert(conshdlrdata->curboundstag > 0);
13258
13259 if( boundrelax )
13260 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13261}
13262
13263/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13265 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13266 )
13267{
13268 assert(conshdlr != NULL);
13269
13270 return SCIPconshdlrGetData(conshdlr)->var2expr;
13271}
13272
13273/** processes a rowprep for cut addition and maybe report branchscores */
13275 SCIP* scip, /**< SCIP data structure */
13276 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13277 SCIP_CONS* cons, /**< nonlinear constraint */
13278 SCIP_EXPR* expr, /**< expression */
13279 SCIP_ROWPREP* rowprep, /**< cut to be added */
13280 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13281 SCIP_VAR* auxvar, /**< auxiliary variable */
13282 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13283 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13284 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13285 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13286 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13287 SCIP_RESULT* result /**< pointer to store the result */
13288 )
13289{
13290 SCIP_Real cutviol;
13291 SCIP_CONSHDLRDATA* conshdlrdata;
13292 SCIP_Real auxvarvalue = SCIP_INVALID;
13293 SCIP_Bool sepasuccess;
13294 SCIP_Real estimateval = SCIP_INVALID;
13295 SCIP_Real mincutviolation;
13296
13297 assert(nlhdlr != NULL);
13298 assert(cons != NULL);
13299 assert(expr != NULL);
13300 assert(rowprep != NULL);
13301 assert(auxvar != NULL);
13302 assert(result != NULL);
13303
13304 /* decide on minimal violation of cut */
13305 if( sol == NULL )
13306 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13307 else
13308 mincutviolation = SCIPfeastol(scip);
13309
13310 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13311 assert(conshdlrdata != NULL);
13312
13313 sepasuccess = TRUE;
13314
13315 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13316 if( cutviol > 0.0 )
13317 {
13318 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13319
13320 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13321 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13322 {
13323 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13324 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13325 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13326 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13327 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13328 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13329 *
13330 * if we are overestimating, we have z >= c'x-b >= f(x)
13331 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13332 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13333 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13334 *
13335 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13336 */
13337 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13338 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13339 {
13340 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13341 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13342 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13343 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13344 sepasuccess = FALSE;
13345 }
13346 }
13347
13348 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13349 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13350 }
13351 else
13352 {
13353 sepasuccess = FALSE;
13354 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13355 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13356 }
13357
13358 /* clean up estimator */
13359 if( sepasuccess )
13360 {
13361 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13362 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13363 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13364 SCIPprintRowprep(scip, rowprep, enfologfile); )
13365
13366 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13367 * instead, may even scale them down, that is, scale so that max coef is close to 1
13368 */
13369 if( !allowweakcuts )
13370 {
13371 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13372
13373 if( !sepasuccess )
13374 {
13375 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13376 }
13377 else
13378 {
13379 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13380 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13381 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13382 if( sepasuccess )
13383 sepasuccess = cutviol > mincutviolation;
13384 }
13385
13386 if( sepasuccess && auxvalue != SCIP_INVALID )
13387 {
13388 /* check whether cut is weak now
13389 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13390 * reconstructing estimateval from cutviol (TODO improve or remove?)
13391 */
13392 SCIP_Real auxvarcoef = 0.0;
13393 int i;
13394
13395 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13396 * it should be...
13397 */
13398 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13399 {
13400 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13401 {
13402 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13403 break;
13404 }
13405 }
13406
13407 if( auxvarcoef == 0.0 ||
13408 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13409 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13410 {
13411 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13412 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13413 sepasuccess = FALSE;
13414 }
13415 }
13416 }
13417 else
13418 {
13419 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13420
13421 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13422 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13423 */
13424 if( !branchscoresuccess )
13426
13427 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13428
13429 if( !sepasuccess )
13430 {
13431 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13432 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13433 }
13434
13435 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13436 * changed
13437 */
13438 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13439 {
13440 SCIP_Real violscore;
13441
13442#ifdef BRSCORE_ABSVIOL
13443 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13444#else
13445 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13446#endif
13447 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13448
13449 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13450 * - were fixed,
13451 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13452 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13453 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13454 * so I'm disabling the assert for now
13455 */
13456 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13457 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13458 }
13459 }
13460 }
13461
13462 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13463 if( sepasuccess )
13464 {
13465 SCIP_ROW* row;
13466
13467 if( conshdlrdata->branchdualweight > 0.0 )
13468 {
13469 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13470 * skip if gap is zero
13471 */
13472 if( auxvalue == SCIP_INVALID )
13473 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13474 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13475 {
13476 char gap[40];
13477 /* coverity[secure_coding] */
13478 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13479 strcat(SCIProwprepGetName(rowprep), gap);
13480 }
13481 }
13482
13483 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13484
13485 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13486 {
13487 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13489 }
13490 else if( !SCIPisCutApplicable(scip, row) )
13491 {
13492 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13493 }
13494 else
13495 {
13496 SCIP_Bool infeasible;
13497
13498 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13499 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13500
13501 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13502 * if we haven't found strong cuts before)
13503 */
13504 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13505
13506 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13507 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13509
13510 if( infeasible )
13511 {
13514 }
13515 else
13516 {
13519 }
13520 }
13521
13522 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13523 }
13524 else if( branchscoresuccess )
13525 {
13526 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13527 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13528
13529 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13530 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13531 */
13533 }
13534 else
13535 {
13536 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13537 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13538 " (!)" : ""); )
13539 }
13540
13541 return SCIP_OKAY;
13542}
13543
13544/** returns whether all nonlinear constraints are assumed to be convex */
13546 SCIP_CONSHDLR* conshdlr
13547 )
13548{
13549 SCIP_CONSHDLRDATA* conshdlrdata;
13550
13551 assert(conshdlr != NULL);
13552
13553 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13554 assert(conshdlrdata != NULL);
13555
13556 return conshdlrdata->assumeconvex;
13557}
13558
13559/** collects all bilinear terms for a given set of constraints
13560 *
13561 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13562 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13563 */
13565 SCIP* scip, /**< SCIP data structure */
13566 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13567 SCIP_CONS** conss, /**< nonlinear constraints */
13568 int nconss /**< total number of nonlinear constraints */
13569 )
13570{
13571 assert(conshdlr != NULL);
13572 assert(conss != NULL || nconss == 0);
13573
13574 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13575
13576 return SCIP_OKAY;
13577}
13578
13579/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13580 *
13581 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13582 */
13584 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13585 )
13586{
13587 SCIP_CONSHDLRDATA* conshdlrdata;
13588
13589 assert(conshdlr != NULL);
13590
13591 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13592 assert(conshdlrdata != NULL);
13593
13594 return conshdlrdata->nbilinterms;
13595}
13596
13597/** returns all bilinear terms that are contained in all nonlinear constraints
13598 *
13599 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13600 * @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.
13601 */
13603 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13604 )
13605{
13606 SCIP_CONSHDLRDATA* conshdlrdata;
13607
13608 assert(conshdlr != NULL);
13609
13610 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13611 assert(conshdlrdata != NULL);
13612
13613 return conshdlrdata->bilinterms;
13614}
13615
13616/** returns the index of the bilinear term representing the product of the two given variables
13617 *
13618 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13619 * @return The method returns -1 if the variables do not appear bilinearly.
13620 */
13622 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13623 SCIP_VAR* x, /**< first variable */
13624 SCIP_VAR* y /**< second variable */
13625 )
13626{
13627 SCIP_CONSHDLRDATA* conshdlrdata;
13629 int idx;
13630
13631 assert(conshdlr != NULL);
13632 assert(x != NULL);
13633 assert(y != NULL);
13634
13635 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13636 assert(conshdlrdata != NULL);
13637
13638 if( conshdlrdata->bilinhashtable == NULL )
13639 {
13640 return -1;
13641 }
13642
13643 /* ensure that x.index <= y.index */
13644 if( SCIPvarCompare(x, y) == 1 )
13645 {
13646 SCIPswapPointers((void**)&x, (void**)&y);
13647 }
13648 assert(SCIPvarCompare(x, y) < 1);
13649
13650 /* use a new entry to find the image in the bilinear hash table */
13651 entry.x = x;
13652 entry.y = y;
13653 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13654 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13655 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13656 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13657
13658 return idx;
13659}
13660
13661/** returns the bilinear term that represents the product of two given variables
13662 *
13663 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13664 * @return The method returns NULL if the variables do not appear bilinearly.
13665 */
13667 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13668 SCIP_VAR* x, /**< first variable */
13669 SCIP_VAR* y /**< second variable */
13670 )
13671{
13672 SCIP_CONSHDLRDATA* conshdlrdata;
13673 int idx;
13674
13675 assert(conshdlr != NULL);
13676 assert(x != NULL);
13677 assert(y != NULL);
13678
13679 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13680 assert(conshdlrdata != NULL);
13681
13682 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13683 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13684
13685 if( idx >= 0 )
13686 {
13687 return &conshdlrdata->bilinterms[idx];
13688 }
13689
13690 return NULL;
13691}
13692
13693/** evaluates an auxiliary expression for a bilinear term */
13695 SCIP* scip, /**< SCIP data structure */
13696 SCIP_VAR* x, /**< first variable of the bilinear term */
13697 SCIP_VAR* y, /**< second variable of the bilinear term */
13698 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13699 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13700 )
13701{
13702 assert(scip != NULL);
13703 assert(x != NULL);
13704 assert(y != NULL);
13705 assert(auxexpr != NULL);
13706 assert(auxexpr->auxvar != NULL);
13707
13708 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13709 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13710}
13711
13712/** stores the variables of a bilinear term in the data of the constraint handler */
13714 SCIP* scip, /**< SCIP data structure */
13715 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13716 SCIP_VAR* x, /**< first variable */
13717 SCIP_VAR* y, /**< second variable */
13718 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13719 int nlockspos, /**< number of positive expression locks */
13720 int nlocksneg /**< number of negative expression locks */
13721 )
13722{
13723 SCIP_CONSHDLRDATA* conshdlrdata;
13725 int idx;
13726
13727 assert(conshdlr != NULL);
13728
13729 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13730 assert(conshdlrdata != NULL);
13731
13732 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13733
13734 term = &conshdlrdata->bilinterms[idx];
13735 assert(term != NULL);
13736 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13737 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) */
13738
13739 /* store and capture auxiliary variable */
13740 if( auxvar != NULL )
13741 {
13742 term->aux.var = auxvar;
13743 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13744 }
13745
13746 return SCIP_OKAY;
13747}
13748
13749/** stores the variables of a bilinear term in the data of the constraint handler */
13751 SCIP* scip, /**< SCIP data structure */
13752 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13753 SCIP_VAR* x, /**< first variable */
13754 SCIP_VAR* y, /**< second variable */
13755 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13756 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13757 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13758 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13759 SCIP_Real cst, /**< constant of the auxiliary expression */
13760 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13761 )
13762{
13763 SCIP_CONSHDLRDATA* conshdlrdata;
13766 int idx;
13767 int nlockspos;
13768 int nlocksneg;
13769 SCIP_Bool added;
13770
13771 assert(conshdlr != NULL);
13772
13773 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13774 assert(conshdlrdata != NULL);
13775
13776 nlockspos = overestimate ? 1 : 0;
13777 nlocksneg = overestimate ? 0 : 1;
13778
13779 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13780
13781 term = &conshdlrdata->bilinterms[idx];
13782 assert(term != NULL);
13783 assert(SCIPvarCompare(term->x, term->y) < 1);
13784
13785 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13786 {
13787 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13788 /* this is the case where we are adding an implicitly defined relation for a product that has already
13789 * been explicitly defined; convert auxvar into an auxexpr */
13790
13791 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13792 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13793 return SCIP_OKAY;
13794
13795 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13796 auxvarexpr->cst = 0.0;
13797 auxvarexpr->coefs[0] = 1.0;
13798 auxvarexpr->coefs[1] = 0.0;
13799 auxvarexpr->coefs[2] = 0.0;
13800 auxvarexpr->auxvar = term->aux.var;
13801 auxvarexpr->underestimate = term->nlocksneg > 0;
13802 auxvarexpr->overestimate = term->nlockspos > 0;
13803
13804 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13805 term->aux.exprs = NULL;
13806
13807 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13808
13809 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13810 assert(added);
13811 }
13812
13813 /* create and add auxexpr */
13814 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13815 auxexpr->underestimate = !overestimate;
13816 auxexpr->overestimate = overestimate;
13817 auxexpr->auxvar = auxvar;
13818 auxexpr->coefs[0] = coefaux;
13819 if( term->x == x )
13820 {
13821 assert(term->y == y);
13822 auxexpr->coefs[1] = coefx;
13823 auxexpr->coefs[2] = coefy;
13824 }
13825 else
13826 {
13827 assert(term->x == y);
13828 assert(term->y == x);
13829 auxexpr->coefs[1] = coefy;
13830 auxexpr->coefs[2] = coefx;
13831 }
13832 auxexpr->cst = cst;
13833 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13834
13835 if( !added )
13836 {
13837 SCIPfreeBlockMemory(scip, &auxexpr);
13838 }
13839 else if( auxvar != NULL )
13840 { /* capture auxiliary variable */
13841 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13842 }
13843
13844 return SCIP_OKAY;
13845}
13846
13847/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13849 SCIP* scip, /**< SCIP data structure */
13850 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13851 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13852 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13853 void* fundata, /**< data for function evaluation (can be NULL) */
13854 SCIP_Real* xstar, /**< point to be separated */
13855 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13856 int nallvars, /**< half of the length of box */
13857 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13858 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13859 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13860 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13861 )
13862{
13863 SCIP_Real* corner;
13864 SCIP_Real* funvals;
13865 int* nonfixedpos;
13866 SCIP_Real maxfaceterror;
13867 int nvars; /* number of nonfixed variables */
13868 unsigned int ncorners;
13869 unsigned int i;
13870 int j;
13871
13872 assert(scip != NULL);
13873 assert(conshdlr != NULL);
13874 assert(function != NULL);
13875 assert(xstar != NULL);
13876 assert(box != NULL);
13877 assert(success != NULL);
13878 assert(facetcoefs != NULL);
13879 assert(facetconstant != NULL);
13880
13881 *success = FALSE;
13882
13883 /* identify fixed variables */
13884 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13885 nvars = 0;
13886 for( j = 0; j < nallvars; ++j )
13887 {
13888 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13889 continue;
13890 nonfixedpos[nvars] = j;
13891 nvars++;
13892 }
13893
13894 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13895 * if too many variables are not fixed, then we do nothing currently
13896 */
13897 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13898 {
13899 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13900 SCIPfreeBufferArray(scip, &nonfixedpos);
13901 return SCIP_OKAY;
13902 }
13903
13904 /* compute f(v^i) for each corner v^i of [l,u] */
13905 ncorners = POWEROFTWO(nvars);
13906 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13907 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13908 for( j = 0; j < nallvars; ++j )
13909 {
13910 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13911 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13912 }
13913 for( i = 0; i < ncorners; ++i )
13914 {
13915 SCIPdebugMsg(scip, "corner %u: ", i);
13916 for( j = 0; j < nvars; ++j )
13917 {
13918 int varpos = nonfixedpos[j];
13919 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13920 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13921 */
13922 if( (i >> j) & 0x1 )
13923 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13924 else
13925 corner[varpos] = box[2 * varpos ]; /* lb of var */
13926 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13927 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13928 }
13929
13930 funvals[i] = function(corner, nallvars, fundata);
13931
13932 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13933
13934 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13935 {
13936 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13937 goto CLEANUP;
13938 }
13939 }
13940
13941 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13942 BMSclearMemoryArray(facetcoefs, nallvars);
13943
13944 if( nvars == 1 )
13945 {
13946 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13947
13948 /* check whether target has been missed */
13949 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13950 {
13951 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13952 *success = FALSE;
13953 }
13954 }
13955 else if( nvars == 2 && SCIPlapackIsAvailable() )
13956 {
13957 int idx1 = nonfixedpos[0];
13958 int idx2 = nonfixedpos[1];
13959 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13960 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13961 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13962 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13963 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13964 SCIP_Real coefs[2] = { 0.0, 0.0 };
13965
13966 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13967
13968 facetcoefs[idx1] = coefs[0];
13969 facetcoefs[idx2] = coefs[1];
13970 }
13971 else
13972 {
13973 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13974 }
13975 if( !*success )
13976 {
13977 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13978 goto CLEANUP;
13979 }
13980
13981 /*
13982 * check and adjust facet with the algorithm of Rikun et al.
13983 */
13984
13985 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13986
13987 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13988 if( maxfaceterror > 0.0 )
13989 {
13990 SCIP_CONSHDLRDATA* conshdlrdata;
13991 SCIP_Real midval;
13992 SCIP_Real feastol;
13993
13995
13996 /* evaluate function in middle point to get some idea for a scaling */
13997 for( j = 0; j < nvars; ++j )
13998 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13999 midval = function(corner, nallvars, fundata);
14000 if( midval == SCIP_INVALID )
14001 midval = 1.0;
14002
14003 conshdlrdata = SCIPconshdlrGetData(conshdlr);
14004 assert(conshdlrdata != NULL);
14005
14006 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
14007 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
14008 {
14009 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
14010 *success = FALSE;
14011 goto CLEANUP;
14012 }
14013
14014 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
14015
14016 if( overestimate )
14017 *facetconstant += maxfaceterror;
14018 else
14019 *facetconstant -= maxfaceterror;
14020 }
14021
14022 /* if we made it until here, then we have a nice facet */
14023 assert(*success);
14024
14025CLEANUP:
14026 /* free allocated memory */
14027 SCIPfreeBufferArray(scip, &corner);
14028 SCIPfreeBufferArray(scip, &funvals);
14029 SCIPfreeBufferArray(scip, &nonfixedpos);
14030
14031 return SCIP_OKAY;
14032}
14033
14034/*
14035 * constraint specific interface methods
14036 */
14037
14038/** returns the expression of the given nonlinear constraint */
14040 SCIP_CONS* cons /**< constraint data */
14041 )
14042{
14043 SCIP_CONSDATA* consdata;
14044
14045 assert(cons != NULL);
14046
14048
14049 consdata = SCIPconsGetData(cons);
14050 assert(consdata != NULL);
14051
14052 return consdata->expr;
14053}
14054
14055/** gets the left hand side of a nonlinear constraint */
14057 SCIP_CONS* cons /**< constraint data */
14058 )
14059{
14060 SCIP_CONSDATA* consdata;
14061
14062 assert(cons != NULL);
14063
14065
14066 consdata = SCIPconsGetData(cons);
14067 assert(consdata != NULL);
14068
14069 return consdata->lhs;
14070}
14071
14072/** gets the right hand side of a nonlinear constraint */
14074 SCIP_CONS* cons /**< constraint data */
14075 )
14076{
14077 SCIP_CONSDATA* consdata;
14078
14079 assert(cons != NULL);
14080
14082
14083 consdata = SCIPconsGetData(cons);
14084 assert(consdata != NULL);
14085
14086 return consdata->rhs;
14087}
14088
14089/** gets the nonlinear constraint as a nonlinear row representation. */
14091 SCIP* scip, /**< SCIP data structure */
14092 SCIP_CONS* cons, /**< constraint */
14093 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14094 )
14095{
14096 SCIP_CONSDATA* consdata;
14097
14098 assert(cons != NULL);
14099 assert(nlrow != NULL);
14100
14102
14103 consdata = SCIPconsGetData(cons);
14104 assert(consdata != NULL);
14105
14106 if( consdata->nlrow == NULL )
14107 {
14108 SCIP_CALL( createNlRow(scip, cons) );
14109 }
14110 assert(consdata->nlrow != NULL);
14111 *nlrow = consdata->nlrow;
14112
14113 return SCIP_OKAY;
14114}
14115
14116/** returns the curvature of the expression of a given nonlinear constraint
14117 *
14118 * @note The curvature information is computed during CONSINITSOL.
14119 */
14121 SCIP_CONS* cons /**< constraint data */
14122 )
14123{
14124 SCIP_CONSDATA* consdata;
14125
14126 assert(cons != NULL);
14127
14129
14130 consdata = SCIPconsGetData(cons);
14131 assert(consdata != NULL);
14132
14133 return consdata->curv;
14134}
14135
14136/** checks whether expression of constraint can be represented as quadratic form
14137 *
14138 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
14139 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
14140 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
14141 */
14143 SCIP* scip, /**< SCIP data structure */
14144 SCIP_CONS* cons, /**< constraint data */
14145 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
14146 )
14147{
14148 SCIP_CONSDATA* consdata;
14149
14150 assert(scip != NULL);
14151 assert(cons != NULL);
14152 assert(isquadratic != NULL);
14153
14155
14156 consdata = SCIPconsGetData(cons);
14157 assert(consdata != NULL);
14158 assert(consdata->expr != NULL);
14159
14160 /* check whether constraint expression is quadratic in extended formulation */
14161 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
14162
14163 /* if not quadratic in non-extended formulation, then do indicate quadratic */
14164 if( *isquadratic )
14165 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
14166
14167 return SCIP_OKAY;
14168}
14169
14170/** changes left-hand-side of a nonlinear constraint
14171 *
14172 * @attention This method can only be called in the problem stage.
14173 */
14175 SCIP* scip, /**< SCIP data structure */
14176 SCIP_CONS* cons, /**< constraint data */
14177 SCIP_Real lhs /**< new left-hand-side */
14178 )
14179{
14180 SCIP_CONSDATA* consdata;
14181
14182 assert(scip != NULL);
14183 assert(cons != NULL);
14184
14186
14188 {
14189 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14190 return SCIP_INVALIDCALL;
14191 }
14192
14193 /* we should have an original constraint */
14195
14196 consdata = SCIPconsGetData(cons);
14197 assert(consdata != NULL);
14198
14199 if( consdata->lhs == lhs )
14200 return SCIP_OKAY;
14201
14202 consdata->lhs = lhs;
14203
14204 /* not sure we care about any of these flags for original constraints */
14205 consdata->ispropagated = FALSE;
14206
14207 return SCIP_OKAY;
14208}
14209
14210/** changes right-hand-side of a nonlinear constraint
14211 *
14212 * @attention This method can only be called in the problem stage.
14213 */
14215 SCIP* scip, /**< SCIP data structure */
14216 SCIP_CONS* cons, /**< constraint data */
14217 SCIP_Real rhs /**< new right-hand-side */
14218 )
14219{
14220 SCIP_CONSDATA* consdata;
14221
14222 assert(scip != NULL);
14223 assert(cons != NULL);
14224
14226
14228 {
14229 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14230 return SCIP_INVALIDCALL;
14231 }
14232
14233 /* we should have an original constraint */
14235
14236 consdata = SCIPconsGetData(cons);
14237 assert(consdata != NULL);
14238
14239 if( consdata->rhs == rhs )
14240 return SCIP_OKAY;
14241
14242 consdata->rhs = rhs;
14243
14244 /* not sure we care about any of these flags for original constraints */
14245 consdata->ispropagated = FALSE;
14246
14247 return SCIP_OKAY;
14248}
14249
14250/** changes expression of a nonlinear constraint
14251 *
14252 * @attention This method can only be called in the problem stage.
14253 */
14255 SCIP* scip, /**< SCIP data structure */
14256 SCIP_CONS* cons, /**< constraint data */
14257 SCIP_EXPR* expr /**< new expression */
14258 )
14259{
14260 SCIP_CONSHDLR* conshdlr;
14261 SCIP_CONSDATA* consdata;
14262
14263 assert(scip != NULL);
14264 assert(cons != NULL);
14265 assert(expr != NULL);
14266
14268 {
14269 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14270 return SCIP_INVALIDCALL;
14271 }
14272
14273 /* we should have an original constraint */
14275
14276 conshdlr = SCIPconsGetHdlr(cons);
14277 assert(conshdlr != NULL);
14278
14280
14281 consdata = SCIPconsGetData(cons);
14282 assert(consdata != NULL);
14283 assert(consdata->expr != NULL);
14284
14285 /* we should not have collected additional data for the expr
14286 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14287 */
14288 assert(consdata->nvarexprs == 0);
14289 assert(consdata->varexprs == NULL);
14290 assert(!consdata->catchedevents);
14291
14292 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14293
14294 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14295 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14296
14297 /* not sure we care about any of these flags for original constraints */
14298 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14299 consdata->issimplified = FALSE;
14300 consdata->ispropagated = FALSE;
14301
14302 return SCIP_OKAY;
14303}
14304
14305/** adds coef * var to nonlinear constraint
14306 *
14307 * @attention This method can only be called in the problem stage.
14308 */
14310 SCIP* scip, /**< SCIP data structure */
14311 SCIP_CONS* cons, /**< constraint data */
14312 SCIP_VAR* var, /**< variable */
14313 SCIP_Real coef /**< coefficient */
14314 )
14315{
14316 SCIP_CONSHDLR* conshdlr;
14317 SCIP_CONSDATA* consdata;
14318 SCIP_EXPR* varexpr;
14319
14320 assert(scip != NULL);
14321 assert(cons != NULL);
14322
14324 {
14325 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14326 return SCIP_INVALIDCALL;
14327 }
14328
14329 /* we should have an original constraint */
14331
14332 if( coef == 0.0 )
14333 return SCIP_OKAY;
14334
14335 conshdlr = SCIPconsGetHdlr(cons);
14336 assert(conshdlr != NULL);
14337
14339
14340 consdata = SCIPconsGetData(cons);
14341 assert(consdata != NULL);
14342 assert(consdata->expr != NULL);
14343
14344 /* we should not have collected additional data for it
14345 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14346 */
14347 assert(consdata->nvarexprs == 0);
14348 assert(consdata->varexprs == NULL);
14349 assert(!consdata->catchedevents);
14350
14351 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14352
14353 /* append to sum, if consdata->expr is sum and not used anywhere else */
14354 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14355 {
14356 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14357 }
14358 else
14359 {
14360 /* create new expression = 1 * consdata->expr + coef * var */
14361 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14362 SCIP_Real coefs[2] = { 1.0, coef };
14363
14364 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14365
14366 /* release old root expr */
14367 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14368 }
14369
14370 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14371
14372 /* not sure we care about any of these flags for original constraints */
14373 consdata->issimplified = FALSE;
14374 consdata->ispropagated = FALSE;
14375
14376 return SCIP_OKAY;
14377}
14378
14379/** adds coef * expr to nonlinear constraint
14380 *
14381 * @attention This method can only be called in the problem stage.
14382 */
14384 SCIP* scip, /**< SCIP data structure */
14385 SCIP_CONS* cons, /**< nonlinear constraint */
14386 SCIP_EXPR* expr, /**< expression */
14387 SCIP_Real coef /**< coefficient */
14388 )
14389{
14390 SCIP_CONSHDLR* conshdlr;
14391 SCIP_CONSDATA* consdata;
14392 SCIP_EXPR* exprowned;
14393
14394 assert(scip != NULL);
14395 assert(cons != NULL);
14396
14398 {
14399 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14400 return SCIP_INVALIDCALL;
14401 }
14402
14403 /* we should have an original constraint */
14405
14406 if( coef == 0.0 )
14407 return SCIP_OKAY;
14408
14409 conshdlr = SCIPconsGetHdlr(cons);
14410 assert(conshdlr != NULL);
14411
14413
14414 consdata = SCIPconsGetData(cons);
14415 assert(consdata != NULL);
14416 assert(consdata->expr != NULL);
14417
14418 /* free quadratic representation, if any is stored */
14419 SCIPfreeExprQuadratic(scip, consdata->expr);
14420
14421 /* free varexprs in consdata, in case they have been stored
14422 * (e.g., by a call to consGet(N)VarsNonlinear)
14423 */
14424 SCIP_CALL( freeVarExprs(scip, consdata) );
14425
14426 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14427 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14428
14429 /* append to sum, if consdata->expr is sum and not used anywhere else */
14430 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14431 {
14432 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14433 }
14434 else
14435 {
14436 /* create new expression = 1 * consdata->expr + coef * var */
14437 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14438 SCIP_Real coefs[2] = { 1.0, coef };
14439
14440 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14441
14442 /* release old root expr */
14443 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14444 }
14445
14446 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14447
14448 /* not sure we care about any of these flags for original constraints */
14449 consdata->issimplified = FALSE;
14450 consdata->ispropagated = FALSE;
14451
14452 return SCIP_OKAY;
14453}
14454
14455/** computes value of constraint expression in a given solution
14456 *
14457 * Stores value of constraint expression in sol in activity.
14458 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14459 */
14461 SCIP* scip, /**< SCIP data structure */
14462 SCIP_CONS* cons, /**< constraint */
14463 SCIP_SOL* sol, /**< solution */
14464 SCIP_Real* activity /**< buffer to store computed activity */
14465 )
14466{
14467 SCIP_CONSDATA* consdata;
14468
14469 assert(cons != NULL);
14470 assert(activity != NULL);
14471
14472 consdata = SCIPconsGetData(cons);
14473 assert(consdata != NULL);
14474
14475 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14476 *activity = SCIPexprGetEvalValue(consdata->expr);
14477
14478 return SCIP_OKAY;
14479}
14480
14481/** gets absolute violation of nonlinear constraint
14482 *
14483 * This function evaluates the constraints in the given solution.
14484 *
14485 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14486 */
14488 SCIP* scip, /**< SCIP data structure */
14489 SCIP_CONS* cons, /**< constraint */
14490 SCIP_SOL* sol, /**< solution to check */
14491 SCIP_Real* viol /**< buffer to store computed violation */
14492 )
14493{
14494 assert(cons != NULL);
14495 assert(viol != NULL);
14496
14497 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14498 *viol = getConsAbsViolation(cons);
14499
14500 return SCIP_OKAY;
14501}
14502
14503/** gets scaled violation of nonlinear constraint
14504 *
14505 * This function evaluates the constraints in the given solution.
14506 *
14507 * The scaling that is applied to the absolute violation of the constraint
14508 * depends on the setting of parameter constraints/nonlinear/violscale.
14509 */
14511 SCIP* scip, /**< SCIP data structure */
14512 SCIP_CONS* cons, /**< constraint */
14513 SCIP_SOL* sol, /**< solution to check */
14514 SCIP_Real* viol /**< buffer to store computed violation */
14515 )
14516{
14517 assert(cons != NULL);
14518 assert(viol != NULL);
14519
14520 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14521 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14522
14523 return SCIP_OKAY;
14524}
14525
14526/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14528 SCIP* scip, /**< SCIP data structure */
14529 SCIP_CONS* cons, /**< nonlinear constraint */
14530 SCIP_VAR** var, /**< pointer to store the variable */
14531 SCIP_Real* coef /**< pointer to store the coefficient */
14532 )
14533{
14534 SCIP_CONSDATA* consdata;
14535
14536 assert(cons != NULL);
14537 assert(var != NULL);
14538 assert(coef != NULL);
14539
14540 /* check for a linear variable that can be increased or decreased without harming feasibility */
14542
14543 consdata = SCIPconsGetData(cons);
14544 assert(consdata != NULL);
14545
14546 *var = consdata->linvardecr;
14547 *coef = consdata->linvardecrcoef;
14548}
14549
14550/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14552 SCIP* scip, /**< SCIP data structure */
14553 SCIP_CONS* cons, /**< nonlinear constraint */
14554 SCIP_VAR** var, /**< pointer to store the variable */
14555 SCIP_Real* coef /**< pointer to store the coefficient */
14556 )
14557{
14558 SCIP_CONSDATA* consdata;
14559
14560 assert(cons != NULL);
14561 assert(var != NULL);
14562 assert(coef != NULL);
14563
14564 /* check for a linear variable that can be increased or decreased without harming feasibility */
14566
14567 consdata = SCIPconsGetData(cons);
14568 assert(consdata != NULL);
14569
14570 *var = consdata->linvarincr;
14571 *coef = consdata->linvarincrcoef;
14572}
14573
14574
14575/*
14576 * Methods for Expressions in Nonlinear Constraints
14577 */
14578
14579/** returns the number of positive rounding locks of an expression */
14581 SCIP_EXPR* expr /**< expression */
14582 )
14583{
14584 assert(expr != NULL);
14586
14587 return SCIPexprGetOwnerData(expr)->nlockspos;
14588}
14589
14590/** returns the number of negative rounding locks of an expression */
14592 SCIP_EXPR* expr /**< expression */
14593 )
14594{
14595 assert(expr != NULL);
14597
14598 return SCIPexprGetOwnerData(expr)->nlocksneg;
14599}
14600
14601/** returns the variable used for linearizing a given expression (return value might be NULL)
14602 *
14603 * @note for variable expression it returns the corresponding variable
14604 */
14606 SCIP_EXPR* expr /**< expression */
14607 )
14608{
14609 SCIP_EXPR_OWNERDATA* ownerdata;
14610
14611 assert(expr != NULL);
14612
14613 ownerdata = SCIPexprGetOwnerData(expr);
14614 assert(ownerdata != NULL);
14615
14616 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14617}
14618
14619/** returns the number of enforcements for an expression */
14621 SCIP_EXPR* expr /**< expression */
14622 )
14623{
14624 assert(expr != NULL);
14626
14627 return SCIPexprGetOwnerData(expr)->nenfos;
14628}
14629
14630/** returns the data for one of the enforcements of an expression */
14632 SCIP_EXPR* expr, /**< expression */
14633 int idx, /**< position of enforcement in enfos array */
14634 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14635 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14636 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14637 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14638 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14639 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14640 )
14641{
14642 SCIP_EXPR_OWNERDATA* ownerdata;
14643
14644 assert(expr != NULL);
14645
14646 ownerdata = SCIPexprGetOwnerData(expr);
14647 assert(ownerdata != NULL);
14648 assert(idx >= 0);
14649 assert(idx < ownerdata->nenfos);
14650 assert(ownerdata->enfos[idx] != NULL);
14651 assert(nlhdlr != NULL);
14652
14653 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14654
14655 if( nlhdlrexprdata != NULL )
14656 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14657
14658 if( nlhdlrparticipation != NULL )
14659 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14660
14661 if( sepabelowusesactivity != NULL )
14662 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14663
14664 if( sepaaboveusesactivity != NULL )
14665 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14666
14667 if( auxvalue != NULL )
14668 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14669}
14670
14671/** sets the auxiliary value of expression for one of the enforcements of an expression */
14673 SCIP_EXPR* expr, /**< expression */
14674 int idx, /**< position of enforcement in enfos array */
14675 SCIP_Real auxvalue /**< the new value of auxval */
14676 )
14677{
14678 SCIP_EXPR_OWNERDATA* ownerdata;
14679
14680 assert(expr != NULL);
14681
14682 ownerdata = SCIPexprGetOwnerData(expr);
14683 assert(ownerdata != NULL);
14684
14685 assert(idx >= 0);
14686 assert(idx < ownerdata->nenfos);
14687 assert(ownerdata->enfos[idx] != NULL);
14688
14689 ownerdata->enfos[idx]->auxvalue = auxvalue;
14690}
14691
14692/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14693 *
14694 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14695 */
14697 SCIP_EXPR* expr /**< expression */
14698 )
14699{
14700 assert(expr != NULL);
14702
14703 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14704}
14705
14706/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14707 *
14708 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14709 */
14711 SCIP_EXPR* expr /**< expression */
14712 )
14713{
14714 assert(expr != NULL);
14716
14717 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14718}
14719
14720/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14721 *
14722 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14723 */
14725 SCIP_EXPR* expr /**< expression */
14726 )
14727{
14728 assert(expr != NULL);
14730
14731 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14732}
14733
14734/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14735 *
14736 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14737 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14738 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14739 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14740 * and also increments this count for all variables in the expression.
14741 *
14742 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14743 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14744 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14745 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14746 */
14748 SCIP* scip, /**< SCIP data structure */
14749 SCIP_EXPR* expr, /**< expression */
14750 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14751 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14752 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14753 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14754 )
14755{
14756 SCIP_EXPR_OWNERDATA* ownerdata;
14757
14758 assert(expr != NULL);
14759
14760 ownerdata = SCIPexprGetOwnerData(expr);
14761 assert(ownerdata != NULL);
14762
14763 /* do not store auxvar request for variable expressions */
14764 if( useauxvar && SCIPisExprVar(scip, expr) )
14765 useauxvar = FALSE;
14766
14767 if( ownerdata->nenfos >= 0 &&
14768 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14769 (ownerdata->nauxvaruses == 0 && useauxvar)
14770 ) )
14771 {
14772 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14773 * we require additional enforcement methods, that is,
14774 * - activity of expr was not used before but will be used now, or
14775 * - auxiliary variable of expr was not required before but will be used now
14776 */
14777 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14778 }
14779
14780 if( useauxvar )
14781 ++ownerdata->nauxvaruses;
14782
14783 if( useactivityforprop )
14784 ++ownerdata->nactivityusesprop;
14785
14786 if( useactivityforsepabelow || useactivityforsepaabove )
14787 ++ownerdata->nactivityusessepa;
14788
14789 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14790 * information is used in detectNlhdlr()
14791 */
14792 if( useactivityforsepabelow )
14793 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14794 if( useactivityforsepaabove )
14795 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14796
14797 if( useactivityforprop )
14798 {
14799 /* if activity will be used for propagation, then make sure there is a valid activity
14800 * this way, we can do a reversepropcall after detectNlhdlr
14801 */
14803 }
14804
14805 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14806 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14807 {
14808 SCIP_EXPRITER* it;
14809
14810 /* create and initialize iterator */
14813
14814 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14815 if( SCIPisExprVar(scip, expr) )
14816 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14817
14818 /* free iterator */
14819 SCIPfreeExpriter(&it);
14820 }
14821
14822 return SCIP_OKAY;
14823}
14824
14825/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14826 *
14827 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14828 * Assume that f(x) is associated with auxiliary variable z.
14829 *
14830 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14831 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14832 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14833 *
14834 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14835 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14836 */
14838 SCIP* scip, /**< SCIP data structure */
14839 SCIP_EXPR* expr, /**< expression */
14840 SCIP_SOL* sol, /**< solution */
14841 SCIP_Longint soltag, /**< tag of solution */
14842 SCIP_Real* viol, /**< buffer to store computed violation */
14843 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14844 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14845 )
14846{
14847 assert(scip != NULL);
14848 assert(expr != NULL);
14849 assert(viol != NULL);
14850
14851 /* make sure expression has been evaluated */
14852 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14853
14854 /* get violation from internal method */
14855 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14856
14857 return SCIP_OKAY;
14858}
14859
14860/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14861 *
14862 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14863 * Assume that f(w) is associated with auxiliary variable z.
14864 *
14865 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14866 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14867 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14868 *
14869 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14870 * both `violover` and `violunder` are set to TRUE.
14871 */
14873 SCIP* scip, /**< SCIP data structure */
14874 SCIP_EXPR* expr, /**< expression */
14875 SCIP_Real auxvalue, /**< the value of f(w) */
14876 SCIP_SOL* sol, /**< solution that has been evaluated */
14877 SCIP_Real* viol, /**< buffer to store computed violation */
14878 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14879 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14880 )
14881{
14882 assert(scip != NULL);
14883 assert(expr != NULL);
14884 assert(viol != NULL);
14885
14886 /* get violation from internal method */
14887 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14888
14889 return SCIP_OKAY;
14890}
14891
14892
14893/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14894 *
14895 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14896 * Assume that f(w) is associated with auxiliary variable z.
14897 *
14898 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14899 * the absolute violation divided by max(1,|f(w)|).
14900 *
14901 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14902 * both `violover` and `violunder` are set to TRUE.
14903 */
14905 SCIP* scip, /**< SCIP data structure */
14906 SCIP_EXPR* expr, /**< expression */
14907 SCIP_Real auxvalue, /**< the value of f(w) */
14908 SCIP_SOL* sol, /**< solution that has been evaluated */
14909 SCIP_Real* viol, /**< buffer to store computed violation */
14910 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14911 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14912 )
14913{
14914 assert(scip != NULL);
14915 assert(expr != NULL);
14916 assert(viol != NULL);
14917
14918 /* get violation from internal method */
14919 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14920
14921 if( !SCIPisInfinity(scip, *viol) )
14922 {
14923 assert(auxvalue != SCIP_INVALID);
14924 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14925 *viol /= MAX(1.0, REALABS(auxvalue));
14926 }
14927
14928 return SCIP_OKAY;
14929}
14930
14931/** returns bounds on the expression
14932 *
14933 * This gives an intersection of bounds from
14934 * - activity calculation (SCIPexprGetActivity()), if valid,
14935 * - auxiliary variable, if present,
14936 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14937 *
14938 * @note The returned interval can be empty!
14939 */
14941 SCIP* scip, /**< SCIP data structure */
14942 SCIP_EXPR* expr /**< expression */
14943 )
14944{
14945 SCIP_EXPR_OWNERDATA* ownerdata;
14946 SCIP_CONSHDLRDATA* conshdlrdata;
14947 SCIP_INTERVAL bounds;
14948
14949 assert(scip != NULL);
14950 assert(expr != NULL);
14951
14952 ownerdata = SCIPexprGetOwnerData(expr);
14953 assert(ownerdata != NULL);
14954
14955 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14956 assert(conshdlrdata != NULL);
14957
14958 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14959
14960 /* start with propbounds if they belong to current propagation */
14961 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14962 {
14963 bounds = ownerdata->propbounds;
14964 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14965 }
14966 else
14968
14969 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14970 {
14971 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14972 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14974 }
14975
14976 if( ownerdata->auxvar != NULL )
14977 {
14978 /* apply auxiliary variable bounds to bounds */
14979 SCIP_INTERVAL auxvarbounds;
14980
14981 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14982 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14983 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14984 }
14985
14986 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14987
14988 return bounds;
14989}
14990
14991/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14992 * corresponding (auxiliary) variable (if any)
14993 *
14994 * @attention this function should only be called during domain propagation in cons_nonlinear
14995 */
14997 SCIP* scip, /**< SCIP data structure */
14998 SCIP_EXPR* expr, /**< expression to be tightened */
14999 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
15000 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
15001 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
15002 )
15003{
15004 SCIP_EXPR_OWNERDATA* ownerdata;
15005 SCIP_CONSHDLRDATA* conshdlrdata;
15006
15007 assert(scip != NULL);
15008 assert(expr != NULL);
15009 assert(cutoff != NULL);
15010
15011 ownerdata = SCIPexprGetOwnerData(expr);
15012 assert(ownerdata != NULL);
15013 assert(ownerdata->conshdlr != NULL);
15014
15015 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15016 assert(conshdlrdata != NULL);
15017
15018 /* the code below assumes that current activity is valid
15019 * if it turns out that we cannot ensure that, then we should change code
15020 */
15021 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
15023
15024 *cutoff = FALSE;
15025
15026#ifdef DEBUG_PROP
15027 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
15028 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
15029 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
15030#endif
15031
15032 if( SCIPexprIsIntegral(expr) )
15033 {
15034 /* apply integrality to new bounds
15035 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
15036 */
15037 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
15038 newbounds.inf = SCIPceil(scip, newbounds.inf);
15039 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
15040 newbounds.sup = SCIPfloor(scip, newbounds.sup);
15041#ifdef DEBUG_PROP
15042 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
15043#endif
15044 }
15045
15047 {
15048 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
15049
15050 *cutoff = TRUE;
15051 return SCIP_OKAY;
15052 }
15053
15054 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
15055 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
15056 {
15057 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
15058
15059 *cutoff = TRUE;
15060 return SCIP_OKAY;
15061 }
15062
15063 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
15064 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
15065 {
15066 /* if already having propbounds in expr, then tighten newbounds by propbounds */
15067 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
15068 }
15069 else
15070 {
15071 /* first time we have propbounds for expr in this propagation rounds:
15072 * intersect with activity (though don't let it become empty if very close intervals)
15073 */
15074 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
15075 }
15076#ifdef DEBUG_PROP
15077 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
15078#endif
15079
15080 /* check if the new bounds lead to an empty interval */
15082 {
15083 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
15084
15085 *cutoff = TRUE;
15086 return SCIP_OKAY;
15087 }
15088
15089 /* if expr is not constant or variable, then store newbounds in expr->propbounds
15090 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
15091 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
15092 */
15093 if( SCIPexprGetNChildren(expr) > 0 )
15094 {
15095 ownerdata->propbounds = newbounds;
15096 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
15097 }
15098
15099 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
15100 * propagation or update of auxvar bounds
15101 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
15102 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
15103 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
15104 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
15105 * one or should we not even update propbounds to newbounds if the update is small?
15106 */
15107 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
15108 {
15109#ifdef DEBUG_PROP
15110 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);
15111#endif
15112 return SCIP_OKAY;
15113 }
15114
15115 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
15116 {
15117 /* add expression to propagation queue if not there yet and not var or constant and
15118 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
15119 */
15120#ifdef DEBUG_PROP
15121 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
15122#endif
15123 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
15124 ownerdata->inpropqueue = TRUE;
15125 }
15126
15127 /* update bounds on variable or auxiliary variable */
15128 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
15129
15130 return SCIP_OKAY;
15131}
15132
15133/** mark constraints that include this expression to be propagated again
15134 *
15135 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
15136 * a change of variable bounds, e.g., because new information on the expression is available
15137 * that could potentially lead to tighter expression activity values.
15138 *
15139 * Note, that this call marks also constraints for propagation which only share some variable
15140 * with this expression.
15141 */
15143 SCIP* scip, /**< SCIP data structure */
15144 SCIP_EXPR* expr /**< expression to propagate again */
15145 )
15146{
15147 SCIP_EXPRITER* it;
15148 SCIP_CONSDATA* consdata;
15149 SCIP_EXPR_OWNERDATA* ownerdata;
15150 int c;
15151
15152 assert(scip != NULL);
15153 assert(expr != NULL);
15154
15155 ownerdata = SCIPexprGetOwnerData(expr);
15156 assert(ownerdata != NULL);
15157
15158 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
15159
15162
15163 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
15164 {
15165 if( !SCIPisExprVar(scip, expr) )
15166 continue;
15167
15168 ownerdata = SCIPexprGetOwnerData(expr);
15169 assert(ownerdata != NULL);
15170
15171 for( c = 0; c < ownerdata->nconss; ++c )
15172 {
15173 consdata = SCIPconsGetData(ownerdata->conss[c]);
15174 assert(consdata != NULL);
15175 consdata->ispropagated = FALSE;
15176 }
15177 }
15178
15179 SCIPfreeExpriter(&it);
15180
15181 return SCIP_OKAY;
15182}
15183
15184/** adds violation-branching score to an expression
15185 *
15186 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
15187 * The expression must either be a variable expression or have an aux-variable.
15188 * In the latter case, branching on auxiliary variables must have been enabled.
15189 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
15190 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
15191 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
15192 *
15193 * @see SCIPaddExprsViolScoreNonlinear()
15194 */
15196 SCIP* scip, /**< SCIP data structure */
15197 SCIP_EXPR* expr, /**< expression where to add branching score */
15198 SCIP_Real violscore /**< violation score to add to expression */
15199 )
15200{
15201 SCIP_EXPR_OWNERDATA* ownerdata;
15202 SCIP_CONSHDLRDATA* conshdlrdata;
15203
15204 assert(scip != NULL);
15205 assert(expr != NULL);
15206 assert(violscore >= 0.0);
15207
15208 ownerdata = SCIPexprGetOwnerData(expr);
15209 assert(ownerdata != NULL);
15210
15211 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15212 assert(conshdlrdata != NULL);
15213
15214 /* if not allowing to branch on auxvars, then expr must be a var-expr */
15215 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
15216 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
15217 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
15218
15219 /* reset branching score if we are in a different enfo round */
15220 if( ownerdata->violscoretag != conshdlrdata->enforound )
15221 {
15222 ownerdata->violscoresum = violscore;
15223 ownerdata->violscoremax = violscore;
15224 ownerdata->nviolscores = 1;
15225 ownerdata->violscoretag = conshdlrdata->enforound;
15226 return;
15227 }
15228
15229 ownerdata->violscoresum += violscore;
15230 if( violscore > ownerdata->violscoremax )
15231 ownerdata->violscoremax = violscore;
15232 ++ownerdata->nviolscores;
15233}
15234
15235/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
15236 *
15237 * Each expression must either be a variable expression or have an aux-variable.
15238 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
15239 * variables present in `exprs`.
15240 */
15242 SCIP* scip, /**< SCIP data structure */
15243 SCIP_EXPR** exprs, /**< expressions where to add branching score */
15244 int nexprs, /**< number of expressions */
15245 SCIP_Real violscore, /**< violation score to add to expression */
15246 SCIP_SOL* sol, /**< current solution */
15247 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
15248 )
15249{
15250 SCIP_EXPRITER* it;
15251 SCIP_EXPR** varexprs;
15252 SCIP_EXPR* e;
15253 int nvars;
15254 int varssize;
15255 int i;
15256
15257 assert(exprs != NULL || nexprs == 0);
15258 assert(success != NULL);
15259
15260 if( nexprs == 0 )
15261 {
15262 *success = FALSE;
15263 return SCIP_OKAY;
15264 }
15265
15266 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
15267 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
15268 {
15269 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15270 return SCIP_OKAY;
15271 }
15272
15273 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15274 nvars = 0;
15275 varssize = 5;
15276 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15277
15280
15281 for( i = 0; i < nexprs; ++i )
15282 {
15283 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15284 {
15285 assert(e != NULL);
15286
15287 if( SCIPisExprVar(scip, e) )
15288 {
15289 /* add variable expression to vars array */
15290 if( varssize == nvars )
15291 {
15292 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15293 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15294 }
15295 assert(varssize > nvars);
15296
15297 varexprs[nvars++] = e;
15298 }
15299 }
15300 }
15301
15302 SCIPfreeExpriter(&it);
15303
15304 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15305
15306 SCIPfreeBufferArray(scip, &varexprs);
15307
15308 return SCIP_OKAY;
15309}
15310
15311/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15313 SCIP_EXPR* expr /**< expression */
15314 )
15315{
15316 SCIP_EXPR_OWNERDATA* ownerdata;
15317 SCIP_CONSHDLRDATA* conshdlrdata;
15318
15319 assert(expr != NULL);
15320
15321 ownerdata = SCIPexprGetOwnerData(expr);
15322 assert(ownerdata != NULL);
15323
15324 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15325 assert(conshdlrdata != NULL);
15326
15327 if( conshdlrdata->enforound != ownerdata->violscoretag )
15328 return 0.0;
15329
15330 if( ownerdata->nviolscores == 0 )
15331 return 0.0;
15332
15333 switch( conshdlrdata->branchscoreagg )
15334 {
15335 case 'a' :
15336 /* average */
15337 return ownerdata->violscoresum / ownerdata->nviolscores;
15338
15339 case 'm' :
15340 /* maximum */
15341 return ownerdata->violscoremax;
15342
15343 case 's' :
15344 /* sum */
15345 return ownerdata->violscoresum;
15346
15347 default:
15348 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15349 SCIPABORT();
15350 return SCIP_INVALID;
15351 }
15352}
15353
15354/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15355 *
15356 * @see SCIPexprGetDerivative()
15357 */
15359 SCIP* scip, /**< SCIP data structure */
15360 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15361 SCIP_VAR* var /**< variable (needs to be in the expression) */
15362 )
15363{
15364 SCIP_EXPR_OWNERDATA* ownerdata;
15365 SCIP_CONSHDLRDATA* conshdlrdata;
15366 SCIP_EXPR* varexpr;
15367
15368 assert(scip != NULL);
15369 assert(expr != NULL);
15370 assert(var != NULL);
15371
15372 /* return 0.0 for value expression */
15373 if( SCIPisExprValue(scip, expr) )
15374 {
15375 assert(SCIPexprGetDerivative(expr) == 0.0);
15376 return 0.0;
15377 }
15378
15379 /* check if an error occurred during the last SCIPevalExprGradient() call */
15380 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15381 return SCIP_INVALID;
15382
15383 ownerdata = SCIPexprGetOwnerData(expr);
15384 assert(ownerdata != NULL);
15385
15386 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15387 assert(conshdlrdata != NULL);
15388
15389 /* use variable to expressions mapping which is stored in the constraint handler data */
15390 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15391
15392 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15393 assert(varexpr != NULL);
15394 assert(SCIPisExprVar(scip, varexpr));
15395
15396 /* use difftag to decide whether the variable belongs to the expression */
15397 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15398}
15399
15400/** 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)
15401 *
15402 * @see SCIPexprGetBardot()
15403 */
15405 SCIP* scip, /**< SCIP data structure */
15406 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15407 SCIP_VAR* var /**< variable (needs to be in the expression) */
15408 )
15409{
15410 SCIP_EXPR_OWNERDATA* ownerdata;
15411 SCIP_CONSHDLRDATA* conshdlrdata;
15412 SCIP_EXPR* varexpr;
15413
15414 assert(scip != NULL);
15415 assert(expr != NULL);
15416 assert(var != NULL);
15417
15418 /* return 0.0 for value expression */
15419 if( SCIPisExprValue(scip, expr) )
15420 return 0.0;
15421
15422 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15423 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15424 return SCIP_INVALID;
15425
15426 ownerdata = SCIPexprGetOwnerData(expr);
15427 assert(ownerdata != NULL);
15428
15429 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15430 assert(conshdlrdata != NULL);
15431
15432 /* use variable to expressions mapping which is stored in the constraint handler data;
15433 * if this fails it means that we are asking for the var's component of H*u for a var
15434 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15435 */
15436 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15437
15438 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15439 assert(varexpr != NULL);
15440 assert(SCIPisExprVar(scip, varexpr));
15441
15442 /* use difftag to decide whether the variable belongs to the expression */
15443 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15444}
15445
15446/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15447 *
15448 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15449 */
15451 SCIP* scip, /**< SCIP data structure */
15452 SCIP_EXPR* expr, /**< quadratic expression */
15453 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15454 )
15455{
15456 SCIP_Real auxvalue;
15457 int nlinexprs;
15458 SCIP_Real* lincoefs;
15459 SCIP_EXPR** linexprs;
15460 int nquadexprs;
15461 int nbilinexprs;
15462 int i;
15463
15464 assert(scip != NULL);
15465 assert(expr != NULL);
15466
15467 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15468
15469 /* linear terms */
15470 for( i = 0; i < nlinexprs; ++i )
15471 {
15472 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15473 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15474 }
15475
15476 /* quadratic terms */
15477 for( i = 0; i < nquadexprs; ++i )
15478 {
15479 SCIP_EXPR* quadexprterm;
15480 SCIP_Real lincoef;
15481 SCIP_Real sqrcoef;
15482 SCIP_Real solval;
15483
15484 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15485
15486 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15487
15488 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15489 auxvalue += (lincoef + sqrcoef * solval) * solval;
15490 }
15491
15492 /* bilinear terms */
15493 for( i = 0; i < nbilinexprs; ++i )
15494 {
15495 SCIP_EXPR* expr1;
15496 SCIP_EXPR* expr2;
15497 SCIP_Real coef;
15498
15499 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15500
15504 }
15505
15506 return auxvalue;
15507}
15508
15509/**@addtogroup PublicNlhdlrInterfaceMethods
15510 * @{
15511 */
15512
15513/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15515 SCIP* scip, /**< SCIP data structure */
15516 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15517 const char* name, /**< name of nonlinear handler (must not be NULL) */
15518 const char* desc, /**< description of nonlinear handler (can be NULL) */
15519 int detectpriority, /**< detection priority of nonlinear handler */
15520 int enfopriority, /**< enforcement priority of nonlinear handler */
15521 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15522 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15523 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15524 )
15525{
15526 SCIP_CONSHDLR* conshdlr;
15527 SCIP_CONSHDLRDATA* conshdlrdata;
15528
15529 assert(scip != NULL);
15530 assert(nlhdlr != NULL);
15531 assert(detect != NULL);
15532
15533 /* find myself */
15534 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15535 if( conshdlr == NULL )
15536 {
15537 SCIPerrorMessage("nonlinear constraint handler not found");
15538 return SCIP_PLUGINNOTFOUND;
15539 }
15540
15541 /* create nlhdlr */
15542 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15543
15544 /* include into constraint handler */
15545 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15546 assert(conshdlrdata != NULL);
15547
15548 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15549
15550 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15551 ++conshdlrdata->nnlhdlrs;
15552
15553 /* sort nonlinear handlers by detection priority, in decreasing order
15554 * will happen in INIT, so only do when called late
15555 */
15556 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15557 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15558
15559 return SCIP_OKAY;
15560}
15561
15562/** get number of nonlinear handler */
15564 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15565 )
15566{
15567 SCIP_CONSHDLRDATA* conshdlrdata;
15568
15569 assert(conshdlr != NULL);
15570
15571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15572 assert(conshdlrdata != NULL);
15573
15574 return conshdlrdata->nnlhdlrs;
15575}
15576
15577/** get nonlinear handlers */
15579 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15580 )
15581{
15582 SCIP_CONSHDLRDATA* conshdlrdata;
15583
15584 assert(conshdlr != NULL);
15585
15586 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15587 assert(conshdlrdata != NULL);
15588
15589 return conshdlrdata->nlhdlrs;
15590}
15591
15592/** returns a nonlinear handler of a given name (or NULL if not found) */
15594 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15595 const char* name /**< name of nonlinear handler */
15596 )
15597{
15598 SCIP_CONSHDLRDATA* conshdlrdata;
15599 int h;
15600
15601 assert(conshdlr != NULL);
15602 assert(name != NULL);
15603
15604 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15605 assert(conshdlrdata != NULL);
15606
15607 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15608 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15609 return conshdlrdata->nlhdlrs[h];
15610
15611 return NULL;
15612}
15613
15614/** gives expression data that a given nonlinear handler stored in an expression
15615 *
15616 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15617 */
15619 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15620 SCIP_EXPR* expr /**< expression */
15621 )
15622{
15623 SCIP_EXPR_OWNERDATA* ownerdata;
15624 int e;
15625
15626 assert(nlhdlr != NULL);
15627 assert(expr != NULL);
15628
15629 ownerdata = SCIPexprGetOwnerData(expr);
15630 assert(ownerdata != NULL);
15631
15632 for( e = 0; e < ownerdata->nenfos; ++e )
15633 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15634 return ownerdata->enfos[e]->nlhdlrexprdata;
15635
15636 return NULL;
15637}
15638
15639/** @} */
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:96
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:89
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DESC
Definition cons_and.c:85
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:99
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:93
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:86
#define CONSHDLR_PROPFREQ
Definition cons_and.c:90
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:98
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:91
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:87
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:94
#define CONSHDLR_NAME
Definition cons_and.c:84
#define CONSHDLR_DELAYPROP
Definition cons_and.c:95
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:313
#define SCIPdebugAddSolVal(scip, var, val)
Definition debug.h:312
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define EPSROUND(x, eps)
Definition def.h:202
#define EPSISINT(x, eps)
Definition def.h:204
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_INVALID
Definition def.h:187
#define SCIP_INTERVAL_INFINITY
Definition def.h:189
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define MAX3(x, y, z)
Definition def.h:237
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define ABS(x)
Definition def.h:225
#define EPSFRAC(x, eps)
Definition def.h:203
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_CALL_ABORT(x)
Definition def.h:343
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define SCIPABORT()
Definition def.h:336
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
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:397
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:3210
SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
Definition expr_pow.c:3235
SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
Definition expr_trig.c:1481
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:3186
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:3449
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:423
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:882
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:606
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:1504
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition scip_sol.c:1717
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:451
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1569
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition scip_sol.c:2003
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:23715
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
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:23418
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4380
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
Definition var.c:23538
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23932
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition var.c:23650
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:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23684
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:23299
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:23522
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:24674
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24685
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
Definition var.c:23495
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17319
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4322
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:756
SCIP_RETCODE SCIPnlhdlrCollectStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, SCIP_DATATREE *datatree)
Definition nlhdlr.c:800
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