Scippy

SCIP

Solving Constraint Integer Programs

cons_nonlinear.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_nonlinear.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for nonlinear constraints specified by algebraic expressions
28 * @author Ksenia Bestuzheva
29 * @author Benjamin Mueller
30 * @author Felipe Serrano
31 * @author Stefan Vigerske
32 */
33
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36#ifdef SCIP_DEBUG
37#define ENFO_LOGGING
38#endif
39
40/* enable to get log output for enforcement */
41/* #define ENFO_LOGGING */
42/* define to get enforcement logging into file */
43/* #define ENFOLOGFILE "consexpr_enfo.log" */
44
45/* define to get more debug output from domain propagation */
46/* #define DEBUG_PROP */
47
48/*lint -e440*/
49/*lint -e441*/
50/*lint -e528*/
51/*lint -e666*/
52/*lint -e777*/
53/*lint -e866*/
54
55#include <ctype.h>
56#include "scip/cons_nonlinear.h"
57#include "scip/nlhdlr.h"
58#include "scip/expr_var.h"
59#include "scip/expr_varidx.h"
60#include "scip/expr_abs.h"
61#include "scip/expr_sum.h"
62#include "scip/expr_value.h"
63#include "scip/expr_pow.h"
64#include "scip/expr_trig.h"
65#include "scip/nlhdlr_convex.h"
66#include "scip/cons_linear.h"
67#include "scip/cons_varbound.h"
68#include "scip/cons_and.h"
70#include "scip/heur_subnlp.h"
71#include "scip/heur_trysol.h"
72#include "scip/lapack_calls.h"
73#include "scip/debug.h"
74#include "scip/dialog_default.h"
75#include "scip/scip_expr.h"
76#include "scip/symmetry_graph.h"
77#include "scip/prop_symmetry.h"
79#include "scip/pub_misc_sort.h"
80#include "scip/scip_datatree.h"
81
82/* fundamental constraint handler properties */
83#define CONSHDLR_NAME "nonlinear"
84#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
85#define CONSHDLR_ENFOPRIORITY 50 /**< priority of the constraint handler for constraint enforcing */
86#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
89#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
90
91/* optional constraint handler properties */
92#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
93#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
94#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
95
96#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
97#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
98#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
99
100#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
101#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
102
103/* properties of the nonlinear constraint handler statistics table */
104#define TABLE_NAME_NONLINEAR "cons_nonlinear"
105#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
106#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
107#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
108
109/* properties of the nonlinear handler statistics table */
110#define TABLE_NAME_NLHDLR "nlhdlr"
111#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
112#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
113#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
114
115#define DIALOG_NAME "nlhdlrs"
116#define DIALOG_DESC "display nonlinear handlers"
117#define DIALOG_ISSUBMENU FALSE
118
119#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
120#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
121#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
122#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
123
124#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
125
126#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
127
128/** translate from one value of infinity to another
129 *
130 * if val is &ge; infty1, then give infty2, else give val
131 */
132#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
133
134/** translates x to 2^x for non-negative integer x */
135#define POWEROFTWO(x) (0x1u << (x))
136
137#ifdef ENFO_LOGGING
138#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
139FILE* enfologfile = NULL;
140#else
141#define ENFOLOG(x)
142#endif
143
144/*
145 * Data structures
146 */
147
148/** enforcement data of an expression */
149typedef struct
150{
151 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
152 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
153 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
154 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
155 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
156 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
157 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
158} EXPRENFO;
159
160/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
161struct SCIP_Expr_OwnerData
162{
163 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
164
165 /* locks and monotonicity */
166 int nlockspos; /**< positive locks counter */
167 int nlocksneg; /**< negative locks counter */
168 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
169 int monotonicitysize; /**< length of monotonicity array */
170
171 /* propagation (in addition to activity that is stored in expr) */
172 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
173 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
174 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
175
176 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
177 EXPRENFO** enfos; /**< enforcements */
178 int nenfos; /**< number of enforcements, or -1 if not initialized */
179 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
180 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
181 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
182 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
183 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
184
185 /* branching */
186 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
187 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
188 int nviolscores; /**< number of violation scores stored for this expression */
189 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
190
191 /* additional data for variable expressions (TODO move into sub-struct?) */
192 SCIP_CONS** conss; /**< constraints in which this variable appears */
193 int nconss; /**< current number of constraints in conss */
194 int consssize; /**< length of conss array */
195 SCIP_Bool consssorted; /**< is the array of constraints sorted */
196
197 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
198};
199
200/** constraint data for nonlinear constraints */
201struct SCIP_ConsData
202{
203 /* data that defines the constraint: expression and sides */
204 SCIP_EXPR* expr; /**< expression that represents this constraint */
205 SCIP_Real lhs; /**< left-hand side */
206 SCIP_Real rhs; /**< right-hand side */
207
208 /* variables */
209 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
210 int nvarexprs; /**< total number of variable expressions */
211 SCIP_Bool catchedevents; /**< do we catch events on variables? */
212
213 /* constraint violation */
214 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
215 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
216 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
217 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
218
219 /* status flags */
220 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
221 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
222
223 /* locks */
224 int nlockspos; /**< number of positive locks */
225 int nlocksneg; /**< number of negative locks */
226
227 /* repair infeasible solutions */
228 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
229 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
230 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
231 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
232
233 /* miscellaneous */
234 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
235 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
236 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
237};
238
239/** constraint upgrade method */
240typedef struct
241{
242 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
243 int priority; /**< priority of upgrading method */
244 SCIP_Bool active; /**< is upgrading enabled */
246
247/** constraint handler data */
248struct SCIP_ConshdlrData
249{
250 /* nonlinear handler */
251 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
252 int nnlhdlrs; /**< number of nonlinear handlers */
253 int nlhdlrssize; /**< size of nlhdlrs array */
254 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
255 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
256 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
257
258 /* constraint upgrades */
259 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
260 int consupgradessize; /**< size of consupgrades array */
261 int nconsupgrades; /**< number of constraint upgrade methods */
262
263 /* other plugins */
264 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
265 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
266 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
267
268 /* tags and counters */
269 int auxvarid; /**< unique id for the next auxiliary variable */
270 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
271 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
272 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
273 unsigned int enforound; /**< total number of enforcement calls, including current one */
274 int lastconsindex; /**< last used consindex, plus one */
275
276 /* activity intervals and domain propagation */
277 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
278 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
279 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
280 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
281 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
282
283 /* parameters */
284 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
285 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
286 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
287 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
288 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
289 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
290 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
291 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
292 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
293 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
294 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
295 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
296 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
297 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
298 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
299 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
300 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
301 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
302 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
303 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
304 char rownotremovable; /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
305 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
306 char checkvarlocks; /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
307 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
308 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
309 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
310 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
311 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
312 SCIP_Real branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
313 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
314 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
315 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
316 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
317 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
318 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
319 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
320 SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
321 char linearizeheursol; /**< whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution) */
322 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
323
324 /* statistics */
325 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
326 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
327 SCIP_Longint ndesperatetightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing because we didn't know anything better */
328 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
329 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
330 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
331 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
332 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
333
334 /* facets of envelops of vertex-polyhedral functions */
335 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
336 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
337
338 /* hashing of bilinear terms */
339 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
340 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
341 int nbilinterms; /**< total number of bilinear terms */
342 int bilintermssize; /**< size of bilinterms array */
343 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
344
345 /* branching */
346 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
347 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
348
349 /* misc */
350 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
351 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
352 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
353};
354
355/** branching candidate with various scores */
356typedef struct
357{
358 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
359 SCIP_VAR* var; /**< variable that is branching candidate */
360 SCIP_Real auxviol; /**< aux-violation score of candidate */
361 SCIP_Real domain; /**< domain score of candidate */
362 SCIP_Real dual; /**< dual score of candidate */
363 SCIP_Real pscost; /**< pseudo-cost score of candidate */
364 SCIP_Real vartype; /**< variable type score of candidate */
365 SCIP_Real fractionality; /**< fractionality score of candidate */
366 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
367} BRANCHCAND;
368
369/*
370 * Local methods
371 */
372
373/* forward declaration */
374static
376 SCIP* scip, /**< SCIP data structure */
377 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
378 SCIP_EXPR* rootexpr, /**< expression */
379 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
380 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
381 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
382 );
383
384/** frees auxiliary variables of expression, if any */
385static
387 SCIP* scip, /**< SCIP data structure */
388 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
389 )
390{
391 SCIP_EXPR_OWNERDATA* mydata;
392
393 assert(scip != NULL);
394 assert(expr != NULL);
395
396 mydata = SCIPexprGetOwnerData(expr);
397 assert(mydata != NULL);
398
399 if( mydata->auxvar == NULL )
400 return SCIP_OKAY;
401
402 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
403
404 /* remove variable locks
405 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
406 */
407 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
408
409 /* release auxiliary variable */
410 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
411 assert(mydata->auxvar == NULL);
412
413 return SCIP_OKAY;
414}
415
416/** frees data used for enforcement of expression, that is, nonlinear handlers
417 *
418 * can also clear indicators whether expr needs enforcement methods, that is,
419 * free an associated auxiliary variable and reset the nactivityuses counts
420 */
421static
423 SCIP* scip, /**< SCIP data structure */
424 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
425 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
426 )
427{
428 SCIP_EXPR_OWNERDATA* mydata;
429 int e;
430
431 mydata = SCIPexprGetOwnerData(expr);
432 assert(mydata != NULL);
433
434 if( freeauxvar )
435 {
436 /* free auxiliary variable */
437 SCIP_CALL( freeAuxVar(scip, expr) );
438 assert(mydata->auxvar == NULL);
439
440 /* reset count on activity and auxvar usage */
441 mydata->nactivityusesprop = 0;
442 mydata->nactivityusessepa = 0;
443 mydata->nauxvaruses = 0;
444 }
445
446 /* free data stored by nonlinear handlers */
447 for( e = 0; e < mydata->nenfos; ++e )
448 {
449 SCIP_NLHDLR* nlhdlr;
450
451 assert(mydata->enfos[e] != NULL);
452
453 nlhdlr = mydata->enfos[e]->nlhdlr;
454 assert(nlhdlr != NULL);
455
456 if( mydata->enfos[e]->issepainit )
457 {
458 /* call the separation deinitialization callback of the nonlinear handler */
459 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
460 mydata->enfos[e]->issepainit = FALSE;
461 }
462
463 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
464 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
465 {
466 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
467 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
468 }
469
470 /* free enfo data */
471 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
472 }
473
474 /* free array with enfo data */
475 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
476
477 /* we need to look at this expression in detect again */
478 mydata->nenfos = -1;
479
480 return SCIP_OKAY;
481}
482
483/** callback that frees data that this conshdlr stored in an expression */
484static
486{
487 assert(scip != NULL);
488 assert(expr != NULL);
489 assert(ownerdata != NULL);
490 assert(*ownerdata != NULL);
491
492 /* expression should not be locked anymore */
493 assert((*ownerdata)->nlockspos == 0);
494 assert((*ownerdata)->nlocksneg == 0);
495
496 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
497
498 /* expression should not be enforced anymore */
499 assert((*ownerdata)->nenfos <= 0);
500 assert((*ownerdata)->auxvar == NULL);
501
502 if( SCIPisExprVar(scip, expr) )
503 {
504 SCIP_CONSHDLRDATA* conshdlrdata;
505 SCIP_VAR* var;
506
507 /* there should be no constraints left that still use this variable */
508 assert((*ownerdata)->nconss == 0);
509 /* thus, there should also be no variable event catched (via this exprhdlr) */
510 assert((*ownerdata)->filterpos == -1);
511
512 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
513
514 /* update var2expr hashmap in conshdlrdata */
515 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
516 assert(conshdlrdata != NULL);
517
518 var = SCIPgetVarExprVar(expr);
519 assert(var != NULL);
520
521 /* remove var -> expr map from hashmap if present
522 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
523 * if variable-expression stored for var is different, then also do nothing)
524 */
525 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
526 {
527 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
528 }
529 }
530
531 SCIPfreeBlockMemory(scip, ownerdata);
532
533 return SCIP_OKAY;
534}
535
536static
538{ /*lint --e{715}*/
539 assert(ownerdata != NULL);
540
541 /* print nl handlers associated to expr */
542 if( ownerdata->nenfos > 0 )
543 {
544 int i;
545 SCIPinfoMessage(scip, file, " {");
546
547 for( i = 0; i < ownerdata->nenfos; ++i )
548 {
549 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
550 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
551 SCIPinfoMessage(scip, file, "a");
552 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
553 SCIPinfoMessage(scip, file, "u");
554 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
555 SCIPinfoMessage(scip, file, "o");
556 if( i < ownerdata->nenfos-1 )
557 SCIPinfoMessage(scip, file, ", ");
558 }
559
560 SCIPinfoMessage(scip, file, "}");
561 }
562
563 /* print aux var associated to expr */
564 if( ownerdata->auxvar != NULL )
565 {
566 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
567 }
568 SCIPinfoMessage(scip, file, "\n");
569
570 return SCIP_OKAY;
571}
572
573/** possibly reevaluates and then returns the activity of the expression
574 *
575 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
576 */
577static
579{
580 SCIP_CONSHDLRDATA* conshdlrdata;
581
582 assert(scip != NULL);
583 assert(expr != NULL);
584 assert(ownerdata != NULL);
585
586 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
587 assert(conshdlrdata != NULL);
588
589 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
590 {
591 /* update activity of expression */
592 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
593
594 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
595 }
596
597 return SCIP_OKAY;
598}
599
600/** callback that creates data that this conshdlr wants to store in an expression */
601static
603{
604 assert(scip != NULL);
605 assert(expr != NULL);
606 assert(ownerdata != NULL);
607
609 (*ownerdata)->nenfos = -1;
610 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
611
612 if( SCIPisExprVar(scip, expr) )
613 {
614 SCIP_CONSHDLRDATA* conshdlrdata;
615 SCIP_VAR* var;
616
617 (*ownerdata)->filterpos = -1;
618
619 /* add to var2expr hashmap if not having expr for var yet */
620
621 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
622 assert(conshdlrdata != NULL);
623
624 var = SCIPgetVarExprVar(expr);
625
626 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
627 {
628 /* store the variable expression in the hashmap */
629 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
630 }
631 else
632 {
633 /* if expr was just created, then it shouldn't already be stored as image of var */
634 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
635 }
636 }
637 else
638 {
639 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
640 (*ownerdata)->filterpos = -2;
641 }
642
643 *ownerfree = exprownerFree;
644 *ownerprint = exprownerPrint;
645 *ownerevalactivity = exprownerEvalactivity;
646
647 return SCIP_OKAY;
648}
649
650/** creates a variable expression or retrieves from hashmap in conshdlr data */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
655 SCIP_EXPR** expr, /**< pointer where to store expression */
656 SCIP_VAR* var /**< variable to be stored */
657 )
658{
659 assert(conshdlr != NULL);
660 assert(expr != NULL);
661 assert(var != NULL);
662
663 /* get variable expression representing the given variable if there is one already */
664 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
665
666 if( *expr == NULL )
667 {
668 /* create a new variable expression; this also captures the expression */
669 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
670 assert(*expr != NULL);
671 /* exprownerCreate should have added var->expr to var2expr */
672 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
673 }
674 else
675 {
676 /* only capture already existing expr to get a consistent uses-count */
677 SCIPcaptureExpr(*expr);
678 }
679
680 return SCIP_OKAY;
681}
682
683/* map var exprs to var-expr from var2expr hashmap */
684static
686{ /*lint --e{715}*/
687 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
688
689 assert(sourcescip != NULL);
690 assert(targetscip != NULL);
691 assert(sourceexpr != NULL);
692 assert(targetexpr != NULL);
693 assert(*targetexpr == NULL);
694 assert(mapexprdata != NULL);
695
696 /* do not provide map if not variable */
697 if( !SCIPisExprVar(sourcescip, sourceexpr) )
698 return SCIP_OKAY;
699
700 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
701
702 return SCIP_OKAY;
703}
704
705/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
706static
708{ /*lint --e{715}*/
709 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
710 SCIP_VAR* var;
711
712 assert(sourcescip != NULL);
713 assert(targetscip != NULL);
714 assert(sourceexpr != NULL);
715 assert(targetexpr != NULL);
716 assert(*targetexpr == NULL);
717 assert(mapexprdata != NULL);
718
719 /* do not provide map if not variable */
720 if( !SCIPisExprVar(sourcescip, sourceexpr) )
721 return SCIP_OKAY;
722
723 var = SCIPgetVarExprVar(sourceexpr);
724 assert(var != NULL);
725
726 /* transform variable */
727 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
728 assert(var != NULL);
729
730 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
731
732 return SCIP_OKAY;
733}
734
735/** stores all variable expressions into a given constraint */
736static
738 SCIP* scip, /**< SCIP data structure */
739 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
740 SCIP_CONSDATA* consdata /**< constraint data */
741 )
742{
743 SCIP_CONSHDLRDATA* conshdlrdata;
744 int varexprssize;
745 int i;
746
747 assert(consdata != NULL);
748
749 /* skip if we have stored the variable expressions already */
750 if( consdata->varexprs != NULL )
751 return SCIP_OKAY;
752
753 assert(consdata->varexprs == NULL);
754 assert(consdata->nvarexprs == 0);
755
756 /* get an upper bound on number of variable expressions */
757 if( consdata->issimplified )
758 {
759 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
760 * so we cannot have more variable expression than the number of active variables
761 */
762 varexprssize = SCIPgetNVars(scip);
763 }
764 else
765 {
766 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
767 }
768
769 /* create array to store all variable expressions */
770 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
771
772 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
773 assert(varexprssize >= consdata->nvarexprs);
774
775 /* shrink array if there are less variables in the expression than in the problem */
776 if( varexprssize > consdata->nvarexprs )
777 {
778 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
779 }
780
781 conshdlrdata = SCIPconshdlrGetData(conshdlr);
782 assert(conshdlrdata != NULL);
783 assert(conshdlrdata->var2expr != NULL);
784
785 /* ensure that for every variable an entry exists in the var2expr hashmap
786 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
787 */
788 for( i = 0; i < consdata->nvarexprs; ++i )
789 {
790 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
791 {
792 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
793 }
794 }
795
796 return SCIP_OKAY;
797}
798
799/** frees all variable expression stored in storeVarExprs() */
800static
802 SCIP* scip, /**< SCIP data structure */
803 SCIP_CONSDATA* consdata /**< constraint data */
804 )
805{
806 int i;
807
808 assert(consdata != NULL);
809
810 /* skip if we have stored the variable expressions already */
811 if( consdata->varexprs == NULL )
812 return SCIP_OKAY;
813
814 assert(consdata->varexprs != NULL);
815 assert(consdata->nvarexprs >= 0);
816 assert(!consdata->catchedevents);
817
818 /* release variable expressions */
819 for( i = 0; i < consdata->nvarexprs; ++i )
820 {
821 assert(consdata->varexprs[i] != NULL);
822 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
823 assert(consdata->varexprs[i] == NULL);
824 }
825
826 /* free variable expressions */
827 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
828 consdata->varexprs = NULL;
829 consdata->nvarexprs = 0;
830
831 return SCIP_OKAY;
832}
833
834/** interval evaluation of variables as used in bound tightening
835 *
836 * Returns slightly relaxed local variable bounds of a variable as interval.
837 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
838 */
839static
840SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
841{
842 SCIP_INTERVAL interval;
843 SCIP_CONSHDLRDATA* conshdlrdata;
844 SCIP_Real lb;
845 SCIP_Real ub;
846
847 assert(scip != NULL);
848 assert(var != NULL);
849
850 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
851 assert(conshdlrdata != NULL);
852
853 if( conshdlrdata->globalbounds )
854 {
855 lb = SCIPvarGetLbGlobal(var);
856 ub = SCIPvarGetUbGlobal(var);
857 }
858 else
859 {
860 lb = SCIPvarGetLbLocal(var);
861 ub = SCIPvarGetUbLocal(var);
862 }
863 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
864
865 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
866 if( SCIPvarIsImpliedIntegral(var) )
867 {
868 lb = EPSROUND(lb, 0.0); /*lint !e835*/
869 ub = EPSROUND(ub, 0.0); /*lint !e835*/
870 }
871
872 /* integer variables should always have integral bounds in SCIP */
873 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
874 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
875
876 switch( conshdlrdata->varboundrelax )
877 {
878 case 'n' : /* no relaxation */
879 break;
880
881 case 'a' : /* relax by absolute value */
882 {
883 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
884 if( SCIPvarIsIntegral(var) )
885 break;
886
887 if( !SCIPisInfinity(scip, -lb) )
888 {
889 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
890 SCIP_Real bnd = floor(lb);
891 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
892 }
893
894 if( !SCIPisInfinity(scip, ub) )
895 {
896 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
897 SCIP_Real bnd = ceil(ub);
898 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
899 }
900
901 break;
902 }
903
904 case 'b' : /* relax always by absolute value */
905 {
906 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
907 if( SCIPvarIsIntegral(var) )
908 break;
909
910 if( !SCIPisInfinity(scip, -lb) )
911 lb -= conshdlrdata->varboundrelaxamount;
912
913 if( !SCIPisInfinity(scip, ub) )
914 ub += conshdlrdata->varboundrelaxamount;
915
916 break;
917 }
918
919 case 'r' : /* relax by relative value */
920 {
921 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
922 if( SCIPvarIsIntegral(var) )
923 break;
924
925 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
926 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
927 * further, do not relax beyond next integer value
928 */
929 if( !SCIPisInfinity(scip, -lb) )
930 {
931 SCIP_Real bnd = floor(lb);
932 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
933 }
934
935 if( !SCIPisInfinity(scip, ub) )
936 {
937 SCIP_Real bnd = ceil(ub);
938 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
939 }
940
941 break;
942 }
943
944 default :
945 {
946 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
947 SCIPABORT();
948 break;
949 }
950 }
951
952 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
955 assert(lb <= ub);
956
957 SCIPintervalSetBounds(&interval, lb, ub);
958
959 return interval;
960}
961
962/** compares two nonlinear constraints by its index
963 *
964 * Usable as compare operator in array sort functions.
965 */
966static
967SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
968{
969 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
970 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
971
972 assert(consdata1 != NULL);
973 assert(consdata2 != NULL);
974
975 return consdata1->consindex - consdata2->consindex;
976}
977
978/** processes variable fixing or bound change event */
979static
980SCIP_DECL_EVENTEXEC(processVarEvent)
981{ /*lint --e{715}*/
982 SCIP_EVENTTYPE eventtype;
983 SCIP_EXPR* expr;
984 SCIP_EXPR_OWNERDATA* ownerdata;
985 SCIP_Bool boundtightened = FALSE;
986
987 eventtype = SCIPeventGetType(event);
989
990 assert(eventdata != NULL);
991 expr = (SCIP_EXPR*) eventdata;
992 assert(SCIPisExprVar(scip, expr));
993
994 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
998
999 ownerdata = SCIPexprGetOwnerData(expr);
1000 assert(ownerdata != NULL);
1001 /* we only catch varevents for variables in constraints, so there should be constraints */
1002 assert(ownerdata->nconss > 0);
1003 assert(ownerdata->conss != NULL);
1004
1005 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1006 boundtightened = TRUE;
1007
1008 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1009 * however, if the boundchange is smaller than epsilon, such an event will be omitted
1010 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1011 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1012 * as a boundtightening (and usually it is, I would think)
1013 */
1014 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1015 boundtightened = TRUE;
1016
1017 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1018 * because we will round the bounds and no longer consider relaxing them
1019 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1020 * (mainly to avoid a failing assert, see github issue #70)
1021 * usually, a change to implicit-integer would result in a boundchange on the variable as well, but not if the bound was already almost integral
1022 */
1024 && ( !EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) /*lint !e835*/
1025 || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0) ) ) /*lint !e835*/
1026 boundtightened = TRUE;
1027
1028 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1029 * - propagation can only find something new if a bound was tightened
1030 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1031 * and we look at global changes (that is, we are not looking at boundchanges in probing)
1032 */
1033 if( boundtightened )
1034 {
1035 SCIP_CONSDATA* consdata;
1036 int c;
1037
1038 for( c = 0; c < ownerdata->nconss; ++c )
1039 {
1040 assert(ownerdata->conss[c] != NULL);
1041 consdata = SCIPconsGetData(ownerdata->conss[c]);
1042
1043 /* if bound tightening, then mark constraints to be propagated again
1044 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1045 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1046 * the locks don't help since they are not available separately for each constraint
1047 */
1048 consdata->ispropagated = FALSE;
1049 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1050
1051 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1053 {
1054 consdata->issimplified = FALSE;
1055 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1056 }
1057 }
1058 }
1059
1060 /* update curboundstag, lastboundrelax, and expr activity */
1061 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1062 {
1063 SCIP_CONSHDLRDATA* conshdlrdata;
1064 SCIP_INTERVAL activity;
1065
1066 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1067 assert(conshdlrdata != NULL);
1068
1069 /* increase tag on bounds */
1070 ++conshdlrdata->curboundstag;
1071 assert(conshdlrdata->curboundstag > 0);
1072
1073 /* remember also if we relaxed bounds now */
1074 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1075 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1076
1077 /* update the activity of the var-expr here immediately
1078 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1079 */
1080 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1081 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1082#ifdef DEBUG_PROP
1083 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1084#endif
1085 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1086 }
1087
1088 return SCIP_OKAY;
1089}
1090
1091/** registers event handler to catch variable events on variable
1092 *
1093 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1094 * When an event occurs, all stored constraints are notified.
1095 */
1096static
1098 SCIP* scip, /**< SCIP data structure */
1099 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1100 SCIP_EXPR* expr, /**< variable expression */
1101 SCIP_CONS* cons /**< nonlinear constraint */
1102 )
1103{
1104 SCIP_EXPR_OWNERDATA* ownerdata;
1105
1106 assert(eventhdlr != NULL);
1107 assert(expr != NULL);
1108 assert(SCIPisExprVar(scip, expr));
1109 assert(cons != NULL);
1110
1111 ownerdata = SCIPexprGetOwnerData(expr);
1112 assert(ownerdata != NULL);
1113
1114#ifndef NDEBUG
1115 /* assert that constraint does not double-catch variable */
1116 {
1117 int i;
1118 for( i = 0; i < ownerdata->nconss; ++i )
1119 assert(ownerdata->conss[i] != cons);
1120 }
1121#endif
1122
1123 /* append cons to ownerdata->conss */
1124 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1125 ownerdata->conss[ownerdata->nconss++] = cons;
1126 /* we're not capturing the constraint here to avoid circular references */
1127
1128 /* updated sorted flag */
1129 if( ownerdata->nconss <= 1 )
1130 ownerdata->consssorted = TRUE;
1131 else if( ownerdata->consssorted )
1132 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) < 0;
1133
1134 /* catch variable events, if not done so yet (first constraint) */
1135 if( ownerdata->filterpos < 0 )
1136 {
1137 SCIP_EVENTTYPE eventtype;
1138
1139 assert(ownerdata->nconss == 1);
1140
1142
1143 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1144 assert(ownerdata->filterpos >= 0);
1145 }
1146
1147 return SCIP_OKAY;
1148}
1149
1150/** catch variable events */
1151static
1153 SCIP* scip, /**< SCIP data structure */
1154 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1155 SCIP_CONS* cons /**< constraint for which to catch bound change events */
1156 )
1157{
1158 SCIP_CONSHDLRDATA* conshdlrdata;
1159 SCIP_CONSDATA* consdata;
1160 SCIP_EXPR* expr;
1161 int i;
1162
1163 assert(eventhdlr != NULL);
1164 assert(cons != NULL);
1165
1166 consdata = SCIPconsGetData(cons);
1167 assert(consdata != NULL);
1168 assert(consdata->varexprs != NULL);
1169 assert(consdata->nvarexprs >= 0);
1170
1171 /* check if we have catched variable events already */
1172 if( consdata->catchedevents )
1173 return SCIP_OKAY;
1174
1175 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1176 assert(conshdlrdata != NULL);
1177#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1178 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1179#endif
1180
1181 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1182
1183 for( i = 0; i < consdata->nvarexprs; ++i )
1184 {
1185 expr = consdata->varexprs[i];
1186
1187 assert(expr != NULL);
1188 assert(SCIPisExprVar(scip, expr));
1189
1190 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1191
1192 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1193 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1194 */
1195 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1196 {
1197 SCIP_INTERVAL activity;
1198 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1199 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1200 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1201#ifdef DEBUG_PROP
1202 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1203#endif
1204 }
1205 }
1206
1207 consdata->catchedevents = TRUE;
1208
1209 return SCIP_OKAY;
1210}
1211
1212/** unregisters event handler to catch variable events on variable
1213 *
1214 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1215 * If this was the last constraint, then the event handler is unregistered for this variable.
1216 */
1217static
1219 SCIP* scip, /**< SCIP data structure */
1220 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1221 SCIP_EXPR* expr, /**< variable expression */
1222 SCIP_CONS* cons /**< expr constraint */
1223 )
1224{
1225 SCIP_EXPR_OWNERDATA* ownerdata;
1226 int pos;
1227
1228 assert(eventhdlr != NULL);
1229 assert(expr != NULL);
1230 assert(SCIPisExprVar(scip, expr));
1231 assert(cons != NULL);
1232
1233 ownerdata = SCIPexprGetOwnerData(expr);
1234 assert(ownerdata != NULL);
1235 assert(ownerdata->nconss > 0);
1236
1237 if( ownerdata->conss[ownerdata->nconss-1] == cons )
1238 {
1239 pos = ownerdata->nconss-1;
1240 }
1241 else
1242 {
1243 if( !ownerdata->consssorted )
1244 {
1245 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1246 ownerdata->consssorted = TRUE;
1247 }
1248
1249 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1250 {
1251 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1252 return SCIP_ERROR;
1253 }
1254 assert(pos >= 0 && pos < ownerdata->nconss);
1255 }
1256 assert(ownerdata->conss[pos] == cons);
1257
1258 /* move last constraint into position of removed constraint */
1259 if( pos < ownerdata->nconss-1 )
1260 {
1261 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1262 ownerdata->consssorted = FALSE;
1263 }
1264 --ownerdata->nconss;
1265
1266 /* drop variable events if that was the last constraint */
1267 if( ownerdata->nconss == 0 )
1268 {
1269 SCIP_EVENTTYPE eventtype;
1270
1271 assert(ownerdata->filterpos >= 0);
1272
1274
1275 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1276 ownerdata->filterpos = -1;
1277 }
1278
1279 return SCIP_OKAY;
1280}
1281
1282/** drop variable events */
1283static
1285 SCIP* scip, /**< SCIP data structure */
1286 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1287 SCIP_CONS* cons /**< constraint for which to drop bound change events */
1288 )
1289{
1290 SCIP_CONSDATA* consdata;
1291 int i;
1292
1293 assert(eventhdlr != NULL);
1294 assert(cons != NULL);
1295
1296 consdata = SCIPconsGetData(cons);
1297 assert(consdata != NULL);
1298
1299 /* check if we have catched variable events already */
1300 if( !consdata->catchedevents )
1301 return SCIP_OKAY;
1302
1303 assert(consdata->varexprs != NULL);
1304 assert(consdata->nvarexprs >= 0);
1305
1306 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1307
1308 for( i = consdata->nvarexprs - 1; i >= 0; --i )
1309 {
1310 assert(consdata->varexprs[i] != NULL);
1311
1312 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1313 }
1314
1315 consdata->catchedevents = FALSE;
1316
1317 return SCIP_OKAY;
1318}
1319
1320/** creates and captures a nonlinear constraint
1321 *
1322 * @attention Use copyexpr=FALSE only if expr is already "owned" by conshdlr, that is, if expressions were created with exprownerCreate() and ownerdata passed in the last two arguments
1323 */
1324static
1326 SCIP* scip, /**< SCIP data structure */
1327 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1328 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1329 const char* name, /**< name of constraint */
1330 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1331 SCIP_Real lhs, /**< left hand side of constraint */
1332 SCIP_Real rhs, /**< right hand side of constraint */
1333 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1334 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1335 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1336 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1337 * Usually set to TRUE. */
1338 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1339 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1340 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1341 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1342 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1343 * Usually set to TRUE. */
1344 SCIP_Bool local, /**< is constraint only valid locally?
1345 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1346 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1347 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1348 * adds coefficients to this constraint. */
1349 SCIP_Bool dynamic, /**< is constraint subject to aging?
1350 * Usually set to FALSE. Set to TRUE for own cuts which
1351 * are separated as constraints. */
1352 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1353 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1354 )
1355{
1356 SCIP_CONSHDLRDATA* conshdlrdata;
1357 SCIP_CONSDATA* consdata;
1358
1359 assert(conshdlr != NULL);
1360 assert(expr != NULL);
1361
1362 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1363 assert(conshdlrdata != NULL);
1364
1365 if( local && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
1366 {
1367 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1368 return SCIP_INVALIDCALL;
1369 }
1370
1371 /* TODO we should allow for non-initial nonlinear constraints */
1372 if( !initial )
1373 {
1374 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1375 return SCIP_INVALIDCALL;
1376 }
1377
1378 if( isnan(lhs) || isnan(rhs) )
1379 {
1380 SCIPerrorMessage("%s hand side of nonlinear constraint <%s> is nan\n",
1381 isnan(lhs) ? "left" : "right", name);
1382 return SCIP_INVALIDDATA;
1383 }
1384
1385 /* create constraint data */
1387
1388 if( copyexpr )
1389 {
1390 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1391 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1392 }
1393 else
1394 {
1395 consdata->expr = expr;
1396 SCIPcaptureExpr(consdata->expr);
1397 }
1398 consdata->lhs = lhs;
1399 consdata->rhs = rhs;
1400 consdata->consindex = conshdlrdata->lastconsindex++;
1401 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1402
1403 /* create constraint */
1404 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1405 local, modifiable, dynamic, removable, FALSE) );
1406
1407 return SCIP_OKAY;
1408}
1409
1410/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1411 *
1412 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1413 * Assume that f(x) is associated with auxiliary variable z.
1414 *
1415 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1416 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1417 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1418 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1419 *
1420 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1421 */
1422static
1424 SCIP* scip, /**< SCIP data structure */
1425 SCIP_EXPR* expr, /**< expression */
1426 SCIP_SOL* sol, /**< solution that has been evaluated */
1427 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1428 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1429 )
1430{
1431 SCIP_EXPR_OWNERDATA* ownerdata;
1432 SCIP_Real auxvarvalue;
1433
1434 assert(expr != NULL);
1435
1436 ownerdata = SCIPexprGetOwnerData(expr);
1437 assert(ownerdata != NULL);
1438 assert(ownerdata->auxvar != NULL);
1439
1440 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1441 {
1442 if( violunder != NULL )
1443 *violunder = TRUE;
1444 if( violover != NULL )
1445 *violover = TRUE;
1446 return SCIPinfinity(scip);
1447 }
1448
1449 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1450
1451 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1452 {
1453 if( violunder != NULL )
1454 *violunder = FALSE;
1455 if( violover != NULL )
1456 *violover = TRUE;
1457 return auxvarvalue - SCIPexprGetEvalValue(expr);
1458 }
1459
1460 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1461 {
1462 if( violunder != NULL )
1463 *violunder = TRUE;
1464 if( violover != NULL )
1465 *violover = FALSE;
1466 return SCIPexprGetEvalValue(expr) - auxvarvalue;
1467 }
1468
1469 if( violunder != NULL )
1470 *violunder = FALSE;
1471 if( violover != NULL )
1472 *violover = FALSE;
1473 return 0.0;
1474}
1475
1476/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1477 *
1478 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1479 * Assume that f(w) is associated with auxiliary variable z.
1480 *
1481 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1482 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1483 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1484 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1485 *
1486 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1487 */
1488static
1490 SCIP* scip, /**< SCIP data structure */
1491 SCIP_EXPR* expr, /**< expression */
1492 SCIP_Real auxvalue, /**< value of f(w) */
1493 SCIP_SOL* sol, /**< solution that has been evaluated */
1494 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1495 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1496 )
1497{
1498 SCIP_EXPR_OWNERDATA* ownerdata;
1499 SCIP_Real auxvarvalue;
1500
1501 assert(expr != NULL);
1502
1503 ownerdata = SCIPexprGetOwnerData(expr);
1504 assert(ownerdata != NULL);
1505 assert(ownerdata->auxvar != NULL);
1506
1507 if( auxvalue == SCIP_INVALID )
1508 {
1509 if( violunder != NULL )
1510 *violunder = TRUE;
1511 if( violover != NULL )
1512 *violover = TRUE;
1513 return SCIPinfinity(scip);
1514 }
1515
1516 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1517
1518 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1519 {
1520 if( violunder != NULL )
1521 *violunder = FALSE;
1522 if( violover != NULL )
1523 *violover = TRUE;
1524 return auxvarvalue - auxvalue;
1525 }
1526
1527 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1528 {
1529 if( violunder != NULL )
1530 *violunder = TRUE;
1531 if( violover != NULL )
1532 *violover = FALSE;
1533 return auxvalue - auxvarvalue;
1534 }
1535
1536 if( violunder != NULL )
1537 *violunder = FALSE;
1538 if( violover != NULL )
1539 *violover = FALSE;
1540
1541 return 0.0;
1542}
1543
1544/** computes violation of a constraint */
1545static
1547 SCIP* scip, /**< SCIP data structure */
1548 SCIP_CONS* cons, /**< constraint */
1549 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1550 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1551 )
1552{
1553 SCIP_CONSDATA* consdata;
1554 SCIP_Real activity;
1555
1556 assert(scip != NULL);
1557 assert(cons != NULL);
1558
1559 consdata = SCIPconsGetData(cons);
1560 assert(consdata != NULL);
1561
1562 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1563 activity = SCIPexprGetEvalValue(consdata->expr);
1564
1565 /* consider constraint as violated if it is undefined in the current point */
1566 if( activity == SCIP_INVALID )
1567 {
1568 consdata->lhsviol = SCIPinfinity(scip);
1569 consdata->rhsviol = SCIPinfinity(scip);
1570 return SCIP_OKAY;
1571 }
1572
1573 /* compute violations */
1574 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1575 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1576
1577 return SCIP_OKAY;
1578}
1579
1580/** returns absolute violation of a constraint
1581 *
1582 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1583 */
1584static
1586 SCIP_CONS* cons /**< constraint */
1587 )
1588{
1589 SCIP_CONSDATA* consdata;
1590
1591 assert(cons != NULL);
1592
1593 consdata = SCIPconsGetData(cons);
1594 assert(consdata != NULL);
1595
1596 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1597}
1598
1599/** computes relative violation of a constraint
1600 *
1601 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1602 */
1603static
1605 SCIP* scip, /**< SCIP data structure */
1606 SCIP_CONS* cons, /**< constraint */
1607 SCIP_Real* viol, /**< buffer to store violation */
1608 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1609 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1610 )
1611{
1612 SCIP_CONSHDLR* conshdlr;
1613 SCIP_CONSHDLRDATA* conshdlrdata;
1614 SCIP_CONSDATA* consdata;
1615 SCIP_Real scale;
1616
1617 assert(cons != NULL);
1618 assert(viol != NULL);
1619
1620 conshdlr = SCIPconsGetHdlr(cons);
1621 assert(conshdlr != NULL);
1622
1623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1624 assert(conshdlrdata != NULL);
1625
1626 *viol = getConsAbsViolation(cons);
1627
1628 if( conshdlrdata->violscale == 'n' )
1629 return SCIP_OKAY;
1630
1631 if( SCIPisInfinity(scip, *viol) )
1632 return SCIP_OKAY;
1633
1634 consdata = SCIPconsGetData(cons);
1635 assert(consdata != NULL);
1636
1637 if( conshdlrdata->violscale == 'a' )
1638 {
1639 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1640
1641 /* consider value of side that is violated for scaling, too */
1642 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1643 {
1644 assert(!SCIPisInfinity(scip, -consdata->lhs));
1645 scale = REALABS(consdata->lhs);
1646 }
1647 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1648 {
1649 assert(!SCIPisInfinity(scip, consdata->rhs));
1650 scale = REALABS(consdata->rhs);
1651 }
1652
1653 *viol /= scale;
1654 return SCIP_OKAY;
1655 }
1656
1657 /* if not 'n' or 'a', then it has to be 'g' at the moment */
1658 assert(conshdlrdata->violscale == 'g');
1659 if( soltag == 0L || consdata->gradnormsoltag != soltag )
1660 {
1661 /* we need the varexprs to conveniently access the gradient */
1662 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1663
1664 /* update cached value of norm of gradient */
1665 consdata->gradnorm = 0.0;
1666
1667 /* compute gradient */
1668 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1669
1670 /* gradient evaluation error -> no scaling */
1671 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1672 {
1673 int i;
1674 for( i = 0; i < consdata->nvarexprs; ++i )
1675 {
1676 SCIP_Real deriv;
1677
1678 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1679 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1680 if( deriv == SCIP_INVALID )
1681 {
1682 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1683 consdata->gradnorm = 0.0;
1684 break;
1685 }
1686
1687 consdata->gradnorm += deriv*deriv;
1688 }
1689 }
1690 consdata->gradnorm = sqrt(consdata->gradnorm);
1691 consdata->gradnormsoltag = soltag;
1692 }
1693
1694 *viol /= MAX(1.0, consdata->gradnorm);
1695
1696 return SCIP_OKAY;
1697}
1698
1699/** returns whether constraint is currently violated
1700 *
1701 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1702 */
1703static
1705 SCIP* scip, /**< SCIP data structure */
1706 SCIP_CONS* cons /**< constraint */
1707 )
1708{
1709 return getConsAbsViolation(cons) > SCIPfeastol(scip);
1710}
1711
1712/** checks for a linear variable that can be increased or decreased without harming feasibility */
1713static
1715 SCIP* scip, /**< SCIP data structure */
1716 SCIP_CONS* cons /**< constraint */
1717 )
1718{
1719 SCIP_CONSDATA* consdata;
1720 int poslock;
1721 int neglock;
1722 int i;
1723
1724 assert(cons != NULL);
1725
1726 consdata = SCIPconsGetData(cons);
1727 assert(consdata != NULL);
1728
1729 consdata->linvarincr = NULL;
1730 consdata->linvardecr = NULL;
1731 consdata->linvarincrcoef = 0.0;
1732 consdata->linvardecrcoef = 0.0;
1733
1734 /* root expression is not a sum -> no unlocked linear variable available */
1735 if( !SCIPisExprSum(scip, consdata->expr) )
1736 return;
1737
1738 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1739 {
1740 SCIP_EXPR* child;
1741
1742 child = SCIPexprGetChildren(consdata->expr)[i];
1743 assert(child != NULL);
1744
1745 /* check whether the child is a variable expression */
1746 if( SCIPisExprVar(scip, child) )
1747 {
1748 SCIP_VAR* var = SCIPgetVarExprVar(child);
1749 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1750
1751 if( coef > 0.0 )
1752 {
1753 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1754 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1755 }
1756 else
1757 {
1758 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1759 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1760 }
1762
1763 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1764 {
1765 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1766 * if we have already one candidate, then take the one where the loss in the objective function is less
1767 */
1768 if( (consdata->linvardecr == NULL) ||
1769 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1770 {
1771 consdata->linvardecr = var;
1772 consdata->linvardecrcoef = coef;
1773 }
1774 }
1775
1776 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1777 {
1778 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1779 * if we have already one candidate, then take the one where the loss in the objective function is less
1780 */
1781 if( (consdata->linvarincr == NULL) ||
1782 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1783 {
1784 consdata->linvarincr = var;
1785 consdata->linvarincrcoef = coef;
1786 }
1787 }
1788 }
1789 }
1790
1791 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1792 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1793
1794 if( consdata->linvarincr != NULL )
1795 {
1796 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1797 }
1798 if( consdata->linvardecr != NULL )
1799 {
1800 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1801 }
1802}
1803
1804/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1805 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1806 *
1807 * The method assumes that this is always possible and that not all constraints are feasible already.
1808 */
1809static
1811 SCIP* scip, /**< SCIP data structure */
1812 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1813 SCIP_CONS** conss, /**< constraints to process */
1814 int nconss, /**< number of constraints */
1815 SCIP_SOL* sol, /**< solution to process */
1816 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1817 )
1818{
1819 SCIP_CONSHDLRDATA* conshdlrdata;
1820 SCIP_SOL* newsol;
1821 int c;
1822
1823 assert(scip != NULL);
1824 assert(conshdlr != NULL);
1825 assert(conss != NULL || nconss == 0);
1826 assert(success != NULL);
1827
1828 *success = FALSE;
1829
1830 /* don't propose new solutions if not in presolve or solving */
1832 return SCIP_OKAY;
1833
1834 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1835 assert(conshdlrdata != NULL);
1836
1837 if( sol != NULL )
1838 {
1839 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1840 }
1841 else
1842 {
1843 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1844 }
1845 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1846 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1847 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1848
1849 for( c = 0; c < nconss; ++c )
1850 {
1851 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1852 SCIP_Real viol = 0.0;
1853 SCIP_Real delta;
1854 SCIP_Real gap;
1855
1856 assert(consdata != NULL);
1857
1858 /* get absolute violation and sign */
1859 if( consdata->lhsviol > SCIPfeastol(scip) )
1860 viol = consdata->lhsviol; /* lhs - activity */
1861 else if( consdata->rhsviol > SCIPfeastol(scip) )
1862 viol = -consdata->rhsviol; /* rhs - activity */
1863 else
1864 continue; /* constraint is satisfied */
1865
1866 if( consdata->linvarincr != NULL &&
1867 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1868 {
1869 SCIP_VAR* var = consdata->linvarincr;
1870
1871 /* compute how much we would like to increase var */
1872 delta = viol / consdata->linvarincrcoef;
1873 assert(delta > 0.0);
1874
1875 /* if var has an upper bound, may need to reduce delta */
1877 {
1878 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1879 delta = MIN(MAX(0.0, gap), delta);
1880 }
1881 if( SCIPisPositive(scip, delta) )
1882 {
1883 /* if variable is integral, round delta up so that it will still have an integer value */
1884 if( SCIPvarIsIntegral(var) )
1885 delta = SCIPceil(scip, delta);
1886
1887 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1888 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1889 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1890
1891 /* adjust constraint violation, if satisfied go on to next constraint */
1892 viol -= consdata->linvarincrcoef * delta;
1893 if( SCIPisZero(scip, viol) )
1894 continue;
1895 }
1896 }
1897
1898 assert(viol != 0.0);
1899 if( consdata->linvardecr != NULL &&
1900 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1901 {
1902 SCIP_VAR* var = consdata->linvardecr;
1903
1904 /* compute how much we would like to decrease var */
1905 delta = viol / consdata->linvardecrcoef;
1906 assert(delta < 0.0);
1907
1908 /* if var has a lower bound, may need to reduce delta */
1910 {
1911 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1912 delta = MAX(MIN(0.0, gap), delta);
1913 }
1914 if( SCIPisNegative(scip, delta) )
1915 {
1916 /* if variable is integral, round delta down so that it will still have an integer value */
1917 if( SCIPvarIsIntegral(var) )
1918 delta = SCIPfloor(scip, delta);
1919 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1920 /*lint --e{613} */
1921 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1922 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1923
1924 /* adjust constraint violation, if satisfied go on to next constraint */
1925 viol -= consdata->linvardecrcoef * delta;
1926 if( SCIPisZero(scip, viol) )
1927 continue;
1928 }
1929 }
1930
1931 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1932 break;
1933 }
1934
1935 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1936 * then pass it to the trysol heuristic
1937 */
1939 {
1940 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1941
1942 assert(conshdlrdata->trysolheur != NULL);
1943 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1944
1945 *success = TRUE;
1946 }
1947
1948 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1949
1950 return SCIP_OKAY;
1951}
1952
1953/** notify nonlinear handlers to add linearization in new solution that has been found
1954 *
1955 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1956 *
1957 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1958 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1959 * cut that is valid and supporting in the given solution.
1960 * For example, for convex constraints, we achieve this by linearizing.
1961 * For SOC, we also linearize, but on a a convex reformulation.
1962 *
1963 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1964 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1965 */
1966static
1968 SCIP* scip, /**< SCIP data structure */
1969 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1970 SCIP_CONS** conss, /**< constraints */
1971 int nconss, /**< number of constraints */
1972 SCIP_SOL* sol, /**< reference point where to estimate */
1973 SCIP_Bool solisbest /**< whether solution is best */
1974 )
1975{
1976 SCIP_CONSDATA* consdata;
1977 SCIP_Longint soltag;
1978 SCIP_EXPRITER* it;
1979 SCIP_EXPR* expr;
1980 int c, e;
1981
1982 assert(scip != NULL);
1983 assert(conshdlr != NULL);
1984 assert(conss != NULL || nconss == 0);
1985
1986 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1987
1988 /* TODO probably we just evaluated all expressions when checking the sol before it was added
1989 * would be nice to recognize this and skip reevaluating
1990 */
1991 soltag = SCIPgetExprNewSoltag(scip);
1992
1996
1997 for( c = 0; c < nconss; ++c )
1998 {
1999 /* skip constraints that are not enabled or deleted or have separation disabled */
2000 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2001 continue;
2002 assert(SCIPconsIsActive(conss[c]));
2003
2004 consdata = SCIPconsGetData(conss[c]);
2005 assert(consdata != NULL);
2006
2007 ENFOLOG(
2008 {
2009 int i;
2010 SCIPinfoMessage(scip, enfologfile, " constraint ");
2011 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2012 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2013 for( i = 0; i < consdata->nvarexprs; ++i )
2014 {
2015 SCIP_VAR* var;
2016 var = SCIPgetVarExprVar(consdata->varexprs[i]);
2017 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2018 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2019 }
2020 })
2021
2022 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2023 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2024
2025 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2026 {
2027 SCIP_EXPR_OWNERDATA* ownerdata;
2028
2029 ownerdata = SCIPexprGetOwnerData(expr);
2030 assert(ownerdata != NULL);
2031
2032 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2033 assert(SCIPexprGetEvalTag(expr) == soltag);
2034 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2035 if( ownerdata->auxvar != NULL )
2036 {
2037 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2038 }
2039
2040 /* let nonlinear handler generate cuts by calling the sollinearize callback */
2041 for( e = 0; e < ownerdata->nenfos; ++e )
2042 {
2043 /* call sollinearize callback, if implemented by nlhdlr */
2044 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2045 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2046 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2047 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2048 }
2049 }
2050 }
2051
2052 SCIPfreeExpriter(&it);
2053
2054 return SCIP_OKAY;
2055}
2056
2057/** processes the event that a new primal solution has been found */
2058static
2059SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2060{
2061 SCIP_CONSHDLR* conshdlr;
2062 SCIP_CONSHDLRDATA* conshdlrdata;
2063 SCIP_SOL* sol;
2064
2065 assert(scip != NULL);
2066 assert(event != NULL);
2067 assert(eventdata != NULL);
2068 assert(eventhdlr != NULL);
2070
2071 conshdlr = (SCIP_CONSHDLR*)eventdata;
2072
2073 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2074 return SCIP_OKAY;
2075
2076 sol = SCIPeventGetSol(event);
2077 assert(sol != NULL);
2078
2079 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2080 assert(conshdlrdata != NULL);
2081
2082 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2083 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2084 * from the tree, but postprocessed via proposeFeasibleSolution
2085 */
2086 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2087 return SCIP_OKAY;
2088
2089 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2090
2092
2093 return SCIP_OKAY;
2094}
2095
2096/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2097 *
2098 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2099 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2100 *
2101 * Nothing will happen if SCIP is not in presolve or solve.
2102 */
2103static
2105 SCIP* scip, /**< SCIP data structure */
2106 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2107 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2108 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2109 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2110 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2111 )
2112{
2113 SCIP_VAR* var;
2114 SCIP_Bool tightenedlb;
2115 SCIP_Bool tightenedub;
2116 SCIP_Bool force;
2117
2118 assert(scip != NULL);
2119 assert(conshdlr != NULL);
2120 assert(expr != NULL);
2121 assert(cutoff != NULL);
2122
2123 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2125
2126 *cutoff = FALSE;
2127
2128 var = SCIPgetExprAuxVarNonlinear(expr);
2129 if( var == NULL )
2130 return SCIP_OKAY;
2131
2132 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2133 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2134
2135 /* try to tighten lower bound of (auxiliary) variable */
2136 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2137 if( tightenedlb )
2138 {
2139 if( ntightenings != NULL )
2140 ++*ntightenings;
2141 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2142 }
2143 if( *cutoff )
2144 {
2145 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2146 return SCIP_OKAY;
2147 }
2148
2149 /* try to tighten upper bound of (auxiliary) variable */
2150 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2151 if( tightenedub )
2152 {
2153 if( ntightenings != NULL )
2154 ++*ntightenings;
2155 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2156 }
2157 if( *cutoff )
2158 {
2159 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2160 return SCIP_OKAY;
2161 }
2162
2163 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2164 * that seems unnecessary and we could easily undo this here, e.g.,
2165 * if( tightenedlb ) expr->activity.inf = bounds.inf
2166 */
2167
2168 return SCIP_OKAY;
2169}
2170
2171/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2172 * and tries to tighten the bounds of the auxiliary variables accordingly
2173 */
2174static
2176 SCIP* scip, /**< SCIP data structure */
2177 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2178 SCIP_EXPR* rootexpr, /**< expression */
2179 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2180 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2181 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2182 )
2183{
2184 SCIP_EXPRITER* it;
2185 SCIP_EXPR* expr;
2186 SCIP_EXPR_OWNERDATA* ownerdata;
2187 SCIP_CONSHDLRDATA* conshdlrdata;
2188
2189 assert(scip != NULL);
2190 assert(rootexpr != NULL);
2191
2192 if( infeasible != NULL )
2193 *infeasible = FALSE;
2194 if( ntightenings != NULL )
2195 *ntightenings = 0;
2196
2197 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2198 assert(conshdlrdata != NULL);
2199
2200 /* if value is valid and empty, then we cannot improve, so do nothing */
2201 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2202 {
2203 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2204
2205 if( infeasible != NULL )
2206 *infeasible = TRUE;
2207
2208 /* just update tag to curboundstag */
2209 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2210
2211 return SCIP_OKAY;
2212 }
2213
2214 /* if value is up-to-date, then nothing to do */
2215 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2216 {
2217 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2218
2219 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2220
2221 return SCIP_OKAY;
2222 }
2223
2224 ownerdata = SCIPexprGetOwnerData(rootexpr);
2225 assert(ownerdata != NULL);
2226
2227 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2228 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2229 * during detect, we are in some in-between state where we may want to eval activity
2230 * on exprs that we did not notify about their activity usage
2231 */
2232 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2233 {
2234#ifdef DEBUG_PROP
2235 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2236#endif
2237 SCIPABORT();
2238 return SCIP_OKAY;
2239 }
2240
2244
2245 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2246 {
2247 switch( SCIPexpriterGetStageDFS(it) )
2248 {
2250 {
2251 /* skip child if it has been evaluated already */
2252 SCIP_EXPR* child;
2253
2254 child = SCIPexpriterGetChildExprDFS(it);
2255 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2256 {
2258 *infeasible = TRUE;
2259
2260 expr = SCIPexpriterSkipDFS(it);
2261 continue;
2262 }
2263
2264 break;
2265 }
2266
2268 {
2269 SCIP_INTERVAL activity;
2270
2271 /* we should not have entered this expression if its activity was already up to date */
2272 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2273
2274 ownerdata = SCIPexprGetOwnerData(expr);
2275 assert(ownerdata != NULL);
2276
2277 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2278 * so we can assume that the activity is up to date for all these variables
2279 * UNLESS we changed the method used to evaluate activity of variable expressions
2280 * or we currently use global bounds (varevents are catched for local bound changes only)
2281 */
2282 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2283 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2284 {
2285#ifndef NDEBUG
2286 SCIP_INTERVAL exprhdlrinterval;
2287
2288 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2289 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2290 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2291#endif
2292#ifdef DEBUG_PROP
2293 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2294#endif
2295 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2296
2297 break;
2298 }
2299
2300 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2301 {
2302 /* start with entire activity if current one is invalid */
2304 }
2306 {
2307 /* If already empty, then don't try to compute even better activity.
2308 * If cons_nonlinear were alone, then we should have noted that we are infeasible
2309 * so an assert(infeasible == NULL || *infeasible) should work here.
2310 * However, after reporting a cutoff due to expr->activity being empty,
2311 * SCIP may wander to a different node and call propagation again.
2312 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2313 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2314 * we will still have expr->activity being empty, but will have forgotten
2315 * that we found infeasibility here before (!2221#note_134120).
2316 * Therefore we just set *infeasibility=TRUE here and stop.
2317 */
2318 if( infeasible != NULL )
2319 *infeasible = TRUE;
2320 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2321 break;
2322 }
2323 else
2324 {
2325 /* start with current activity, since it is valid */
2326 activity = SCIPexprGetActivity(expr);
2327 }
2328
2329 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2330 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2331 {
2332#ifdef DEBUG_PROP
2333 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2334#endif
2335 break;
2336 }
2337
2338#ifdef DEBUG_PROP
2339 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2340 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2341 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2342#endif
2343
2344 /* run interval eval of nonlinear handlers or expression handler */
2345 if( ownerdata->nenfos > 0 )
2346 {
2347 SCIP_NLHDLR* nlhdlr;
2348 SCIP_INTERVAL nlhdlrinterval;
2349 int e;
2350
2351 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2352 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2353 {
2354 /* skip nlhdlr if it does not want to participate in activity computation */
2355 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2356 continue;
2357
2358 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2359 assert(nlhdlr != NULL);
2360
2361 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2362 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2363 continue;
2364
2365 /* let nlhdlr evaluate current expression */
2366 nlhdlrinterval = activity;
2367 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2368 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2369#ifdef DEBUG_PROP
2370 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2371#endif
2372
2373 /* update activity by intersecting with computed activity */
2374 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2375#ifdef DEBUG_PROP
2376 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2377#endif
2378 }
2379 }
2380 else
2381 {
2382 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2383 SCIP_INTERVAL exprhdlrinterval = activity;
2384 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2385#ifdef DEBUG_PROP
2386 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2387#endif
2388
2389 /* update expr->activity by intersecting with computed activity */
2390 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2391#ifdef DEBUG_PROP
2392 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2393#endif
2394 }
2395
2396 /* if expression is integral, then we try to tighten the interval bounds a bit
2397 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2398 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2399 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2400 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2401 * (constants should be ok, too)
2402 */
2403 if( SCIPexprIsIntegral(expr) &&
2404 conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2405 {
2406 if( activity.inf > -SCIP_INTERVAL_INFINITY )
2407 activity.inf = SCIPceil(scip, activity.inf);
2408 if( activity.sup < SCIP_INTERVAL_INFINITY )
2409 activity.sup = SCIPfloor(scip, activity.sup);
2410#ifdef DEBUG_PROP
2411 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2412#endif
2413 }
2414
2415 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2416 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2417 */
2418 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2419 {
2420 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2421 SCIPintervalSetEmpty(&activity);
2422 }
2423
2424 /* now finally store activity in expr */
2425 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2426
2428 {
2429 if( infeasible != NULL )
2430 *infeasible = TRUE;
2431 }
2432 else if( tightenauxvars && ownerdata->auxvar != NULL )
2433 {
2434 SCIP_Bool tighteninfeasible;
2435
2436 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2437 if( tighteninfeasible )
2438 {
2439 if( infeasible != NULL )
2440 *infeasible = TRUE;
2441 SCIPintervalSetEmpty(&activity);
2442 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2443 }
2444 }
2445
2446 break;
2447 }
2448
2449 default:
2450 /* you should never be here */
2451 SCIPerrorMessage("unexpected iterator stage\n");
2452 SCIPABORT();
2453 break;
2454 }
2455
2456 expr = SCIPexpriterGetNext(it);
2457 }
2458
2459 SCIPfreeExpriter(&it);
2460
2461 return SCIP_OKAY;
2462}
2463
2464/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2465 *
2466 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2467 *
2468 * If `subsetsufficient` is FALSE, then we require
2469 * - a change from an unbounded interval to a bounded one, or
2470 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2471 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2472 */
2473static
2475 SCIP* scip, /**< SCIP data structure */
2476 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2477 SCIP_INTERVAL newinterval, /**< new interval */
2478 SCIP_INTERVAL oldinterval /**< old interval */
2479 )
2480{
2481 assert(scip != NULL);
2482 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2483 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2484
2485 if( subsetsufficient )
2486 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2487 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2488
2489 /* check whether lower bound of interval becomes finite */
2490 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2491 return TRUE;
2492
2493 /* check whether upper bound of interval becomes finite */
2494 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2495 return TRUE;
2496
2497 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2498 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2499 return TRUE;
2500
2501 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2502 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2503 return TRUE;
2504
2505 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2506 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2507 return TRUE;
2508
2509 return FALSE;
2510}
2511
2512/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2513 *
2514 * The expression will be traversed in breadth first search by using this queue.
2515 *
2516 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2517 * forwardPropExpr() before calling this function.
2518 *
2519 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2520 */
2521static
2523 SCIP* scip, /**< SCIP data structure */
2524 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2525 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2526 int* ntightenings /**< buffer to store the number of (variable) tightenings */
2527 )
2528{
2529 SCIP_CONSHDLRDATA* conshdlrdata;
2530 SCIP_EXPR* expr;
2531 SCIP_EXPR_OWNERDATA* ownerdata;
2532
2533 assert(infeasible != NULL);
2534 assert(ntightenings != NULL);
2535
2536 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2537 assert(conshdlrdata != NULL);
2538
2539 *ntightenings = 0;
2540
2541 /* main loop that calls reverse propagation for expressions on the queue
2542 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2543 */
2544 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2545 {
2546 SCIP_INTERVAL propbounds;
2547 int e;
2548
2549 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2550 assert(expr != NULL);
2551
2552 ownerdata = SCIPexprGetOwnerData(expr);
2553 assert(ownerdata != NULL);
2554
2555 assert(ownerdata->inpropqueue);
2556 /* mark that the expression is not in the queue anymore */
2557 ownerdata->inpropqueue = FALSE;
2558
2559 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2560 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2561 */
2562 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2563 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2564 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2565
2566 /* this intersects propbounds with activity and auxvar bounds
2567 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2568 * auxvar bounds separately, so disabling this for now
2569 */
2570#ifdef SCIP_DISABLED_CODE
2571 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2573 {
2574 *infeasible = TRUE;
2575 break;
2576 }
2577#else
2578 propbounds = ownerdata->propbounds;
2579#endif
2580
2581 if( ownerdata->nenfos > 0 )
2582 {
2583 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2584 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2585 {
2586 SCIP_NLHDLR* nlhdlr;
2587 int nreds;
2588
2589 /* skip nlhdlr if it does not want to participate in activity computation */
2590 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2591 continue;
2592
2593 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2594 assert(nlhdlr != NULL);
2595
2596 /* call the reverseprop of the nlhdlr */
2597#ifdef SCIP_DEBUG
2598 SCIPdebugMsg(scip, "call reverse propagation for ");
2599 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2600 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2601#endif
2602
2603 nreds = 0;
2604 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2605 assert(nreds >= 0);
2606 *ntightenings += nreds;
2607 }
2608 }
2610 {
2611 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2612 SCIP_INTERVAL* childrenbounds;
2613 int c;
2614
2615#ifdef SCIP_DEBUG
2616 SCIPdebugMsg(scip, "call reverse propagation for ");
2617 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2618 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2619#endif
2620
2621 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2622 * been initialized in detectNlhdlr yet (nenfos < 0)
2623 */
2624 assert(ownerdata->nenfos < 0);
2625
2626 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2627 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2628 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2629
2630 /* call the reverseprop of the exprhdlr */
2631 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2632
2633 if( !*infeasible )
2634 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2635 {
2636 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2637 }
2638
2639 SCIPfreeBufferArray(scip, &childrenbounds);
2640 }
2641 }
2642
2643 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2644 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2645 {
2646 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2647 assert(expr != NULL);
2648
2649 ownerdata = SCIPexprGetOwnerData(expr);
2650 assert(ownerdata != NULL);
2651
2652 /* mark that the expression is not in the queue anymore */
2653 ownerdata->inpropqueue = FALSE;
2654 }
2655
2656 return SCIP_OKAY;
2657}
2658
2659/** calls domain propagation for a given set of constraints
2660 *
2661 * The algorithm alternates calls of forward and reverse propagation.
2662 * Forward propagation ensures that activity of expressions is up to date.
2663 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2664 * [lhs,rhs] interval as starting point.
2665 *
2666 * The propagation algorithm works as follows:
2667 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2668 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2669 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2670 * provide tighter bounds
2671 * 3. apply reverse propagation to all collected expressions; don't explore
2672 * sub-expressions which have not changed since the beginning of the propagation loop
2673 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2674 *
2675 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2676 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2677 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2678 *
2679 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2680 * e.g., try less to propagate on convex constraints?
2681 */
2682static
2684 SCIP* scip, /**< SCIP data structure */
2685 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2686 SCIP_CONS** conss, /**< constraints to propagate */
2687 int nconss, /**< total number of constraints */
2688 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2689 SCIP_RESULT* result, /**< pointer to store the result */
2690 int* nchgbds /**< buffer to add the number of changed bounds */
2691 )
2692{
2693 SCIP_CONSHDLRDATA* conshdlrdata;
2694 SCIP_CONSDATA* consdata;
2695 SCIP_EXPR_OWNERDATA* ownerdata;
2696 SCIP_Bool cutoff = FALSE;
2697 SCIP_INTERVAL conssides;
2698 int ntightenings;
2699 int roundnr;
2700 SCIP_EXPRITER* revpropcollectit = NULL;
2701 int i;
2702
2703 assert(scip != NULL);
2704 assert(conshdlr != NULL);
2705 assert(conss != NULL);
2706 assert(nconss >= 0);
2707 assert(result != NULL);
2708 assert(nchgbds != NULL);
2709 assert(*nchgbds >= 0);
2710
2711 /* no constraints to propagate */
2712 if( nconss == 0 )
2713 {
2714 *result = SCIP_DIDNOTRUN;
2715 return SCIP_OKAY;
2716 }
2717
2718 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2719 assert(conshdlrdata != NULL);
2720#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2721 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2722#endif
2723 assert(!conshdlrdata->globalbounds);
2724
2725 *result = SCIP_DIDNOTFIND;
2726 roundnr = 0;
2727
2728 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2729 conshdlrdata->forceboundtightening = force;
2730
2731 /* invalidate all propbounds (probably not needed) */
2732 ++conshdlrdata->curpropboundstag;
2733
2734 /* create iterator that we will use if we need to look at all auxvars */
2735 if( conshdlrdata->propauxvars )
2736 {
2737 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2738 }
2739
2740 /* main propagation loop */
2741 do
2742 {
2743 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2744
2745 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2746
2747 /* apply forward propagation (update expression activities)
2748 * and add promising root expressions into queue for reversepropagation
2749 */
2750 for( i = 0; i < nconss; ++i )
2751 {
2752 consdata = SCIPconsGetData(conss[i]);
2753 assert(consdata != NULL);
2754
2755 /* skip deleted, non-active, or propagation-disabled constraints */
2756 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2757 continue;
2758
2759 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2760 * activity didn't change
2761 */
2762 if( consdata->ispropagated )
2763 continue;
2764
2765 /* update activities in expression */
2766 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2767 SCIPdebugPrintCons(scip, conss[i], NULL);
2768
2769 ntightenings = 0;
2770 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2771 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2772
2773 if( cutoff )
2774 {
2775 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2776 *result = SCIP_CUTOFF;
2777 break;
2778 }
2779
2780 ownerdata = SCIPexprGetOwnerData(consdata->expr);
2781
2782 /* TODO for a constraint that only has an auxvar for consdata->expr (e.g., convex quadratic), we could also just do the if(TRUE)-branch */
2783 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2784 {
2785 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2786 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2787 * so taking auxvar bounds is enough)
2788 */
2789 if( ownerdata->auxvar == NULL )
2790 {
2791 /* relax sides by SCIPepsilon() and handle infinite sides */
2792 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2793 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2794 SCIPintervalSetBounds(&conssides, lhs, rhs);
2795 }
2796 else
2797 {
2798 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2799 }
2800 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2801 }
2802 else
2803 {
2804 /* check whether bounds of any auxvar used in constraint provides a tightening
2805 * (for the root expression, bounds of auxvar are initially set to constraint sides)
2806 * but skip exprs that have an auxvar, but do not participate in propagation
2807 */
2808 SCIP_EXPR* expr;
2809
2810 assert(revpropcollectit != NULL);
2811 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2812 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2813 {
2814 ownerdata = SCIPexprGetOwnerData(expr);
2815 assert(ownerdata != NULL);
2816
2817 if( ownerdata->auxvar == NULL )
2818 continue;
2819
2820 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2821 continue;
2822
2823 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2824 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2825 }
2826 }
2827
2828 if( cutoff )
2829 {
2830 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2831 *result = SCIP_CUTOFF;
2832 break;
2833 }
2834
2835 assert(ntightenings >= 0);
2836 if( ntightenings > 0 )
2837 {
2838 *nchgbds += ntightenings;
2839 *result = SCIP_REDUCEDDOM;
2840 }
2841
2842 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2843 consdata->ispropagated = TRUE;
2844 }
2845
2846 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2847 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2848 assert(ntightenings >= 0);
2849 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2850
2851 if( cutoff )
2852 {
2853 SCIPdebugMsg(scip, " -> cutoff\n");
2854 *result = SCIP_CUTOFF;
2855 break;
2856 }
2857
2858 if( ntightenings > 0 )
2859 {
2860 *nchgbds += ntightenings;
2861 *result = SCIP_REDUCEDDOM;
2862 }
2863 }
2864 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2865
2866 if( conshdlrdata->propauxvars )
2867 {
2868 SCIPfreeExpriter(&revpropcollectit);
2869 }
2870
2871 conshdlrdata->forceboundtightening = FALSE;
2872
2873 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2874 ++conshdlrdata->curpropboundstag;
2875
2876 return SCIP_OKAY;
2877}
2878
2879/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2880 *
2881 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2882 *
2883 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2884 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2885 */
2886static
2888 SCIP* scip, /**< SCIP data structure */
2889 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2890 SCIP_CONS** conss, /**< constraints to propagate */
2891 int nconss, /**< total number of constraints */
2892 SCIP_RESULT* result, /**< pointer to store the result */
2893 int* nchgbds /**< buffer to add the number of changed bounds */
2894 )
2895{
2896 SCIP_CONSDATA* consdata;
2897 SCIP_EXPRITER* it;
2898 SCIP_EXPR* expr;
2899 SCIP_EXPR_OWNERDATA* ownerdata;
2900 SCIP_Bool cutoff = FALSE;
2901 int ntightenings;
2902 int c;
2903 int e;
2904
2905 assert(scip != NULL);
2906 assert(conshdlr != NULL);
2907 assert(conss != NULL);
2908 assert(nconss >= 0);
2909 assert(result != NULL);
2910 assert(nchgbds != NULL);
2911 assert(*nchgbds >= 0);
2912
2913#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2914 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2915#endif
2916 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2917 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2918
2919 *result = SCIP_DIDNOTFIND;
2920
2923
2924 for( c = 0; c < nconss && !cutoff; ++c )
2925 {
2926 /* skip deleted, non-active, or propagation-disabled constraints */
2927 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2928 continue;
2929
2930 consdata = SCIPconsGetData(conss[c]);
2931 assert(consdata != NULL);
2932
2933 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2934 {
2935 ownerdata = SCIPexprGetOwnerData(expr);
2936 assert(ownerdata != NULL);
2937
2938 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2939 * this will propagate the current activity
2940 */
2941 for( e = 0; e < ownerdata->nenfos; ++e )
2942 {
2943 SCIP_NLHDLR* nlhdlr;
2944 assert(ownerdata->enfos[e] != NULL);
2945
2946 nlhdlr = ownerdata->enfos[e]->nlhdlr;
2947 assert(nlhdlr != NULL);
2948 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2949 continue;
2950
2951 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2952 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2953 ntightenings = 0;
2954 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2955 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2956
2957 if( cutoff )
2958 {
2959 /* stop everything if we detected infeasibility */
2960 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2961 *result = SCIP_CUTOFF;
2962 break;
2963 }
2964
2965 assert(ntightenings >= 0);
2966 if( ntightenings > 0 )
2967 {
2968 *nchgbds += ntightenings;
2969 *result = SCIP_REDUCEDDOM;
2970 }
2971 }
2972 }
2973 }
2974
2975 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2976 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2977 assert(ntightenings >= 0);
2978
2979 if( cutoff )
2980 {
2981 SCIPdebugMsg(scip, " -> cutoff\n");
2982 *result = SCIP_CUTOFF;
2983 }
2984 else if( ntightenings > 0 )
2985 {
2986 *nchgbds += ntightenings;
2987 *result = SCIP_REDUCEDDOM;
2988 }
2989
2990 SCIPfreeExpriter(&it);
2991
2992 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2993 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2994
2995 return SCIP_OKAY;
2996}
2997
2998/** propagates variable locks through expression and adds locks to variables */
2999static
3001 SCIP* scip, /**< SCIP data structure */
3002 SCIP_EXPR* expr, /**< expression */
3003 int nlockspos, /**< number of positive locks */
3004 int nlocksneg /**< number of negative locks */
3005 )
3006{
3007 SCIP_EXPR_OWNERDATA* ownerdata;
3008 SCIP_EXPRITER* it;
3009 SCIP_EXPRITER_USERDATA ituserdata;
3010
3011 assert(expr != NULL);
3012
3013 /* if no locks, then nothing to propagate */
3014 if( nlockspos == 0 && nlocksneg == 0 )
3015 return SCIP_OKAY;
3016
3020 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3021
3022 /* store locks in root node */
3023 ituserdata.intvals[0] = nlockspos;
3024 ituserdata.intvals[1] = nlocksneg;
3025 SCIPexpriterSetCurrentUserData(it, ituserdata);
3026
3027 while( !SCIPexpriterIsEnd(it) )
3028 {
3029 /* collect locks */
3030 ituserdata = SCIPexpriterGetCurrentUserData(it);
3031 nlockspos = ituserdata.intvals[0];
3032 nlocksneg = ituserdata.intvals[1];
3033
3034 ownerdata = SCIPexprGetOwnerData(expr);
3035
3036 switch( SCIPexpriterGetStageDFS(it) )
3037 {
3039 {
3040 if( SCIPisExprVar(scip, expr) )
3041 {
3042 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3043 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3044 }
3045
3046 /* add locks to expression */
3047 ownerdata->nlockspos += nlockspos;
3048 ownerdata->nlocksneg += nlocksneg;
3049
3050 /* add monotonicity information if expression has been locked for the first time */
3051 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3053 {
3054 int i;
3055
3056 assert(ownerdata->monotonicity == NULL);
3057 assert(ownerdata->monotonicitysize == 0);
3058
3059 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3060 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3061
3062 /* store the monotonicity for each child */
3063 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3064 {
3065 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3066 }
3067 }
3068 break;
3069 }
3070
3072 {
3073 /* remove monotonicity information if expression has been unlocked */
3074 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3075 {
3076 assert(ownerdata->monotonicitysize > 0);
3077 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3078 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3079
3080 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3081 ownerdata->monotonicitysize = 0;
3082 }
3083 break;
3084 }
3085
3087 {
3088 SCIP_MONOTONE monotonicity;
3089
3090 /* get monotonicity of child */
3091 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3092 * SCIPcallExprMonotonicity
3093 */
3094 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3095
3096 /* compute resulting locks of the child expression */
3097 switch( monotonicity )
3098 {
3099 case SCIP_MONOTONE_INC:
3100 ituserdata.intvals[0] = nlockspos;
3101 ituserdata.intvals[1] = nlocksneg;
3102 break;
3103 case SCIP_MONOTONE_DEC:
3104 ituserdata.intvals[0] = nlocksneg;
3105 ituserdata.intvals[1] = nlockspos;
3106 break;
3108 ituserdata.intvals[0] = nlockspos + nlocksneg;
3109 ituserdata.intvals[1] = nlockspos + nlocksneg;
3110 break;
3112 ituserdata.intvals[0] = 0;
3113 ituserdata.intvals[1] = 0;
3114 break;
3115 }
3116 /* set locks in child expression */
3117 SCIPexpriterSetChildUserData(it, ituserdata);
3118
3119 break;
3120 }
3121
3122 default :
3123 /* you should never be here */
3124 SCIPABORT();
3125 break;
3126 }
3127
3128 expr = SCIPexpriterGetNext(it);
3129 }
3130
3131 SCIPfreeExpriter(&it);
3132
3133 return SCIP_OKAY;
3134}
3135
3136/** main function for adding locks to expressions and variables
3137 *
3138 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3139 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3140 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3141 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3142 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3143 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3144 * which implies that updating the monotonicity information during the next locking of this expression does not
3145 * break existing locks.
3146 *
3147 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3148 * locks from an expression and repropagating them after the structural changes have been applied.
3149 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3150 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3151 */
3152static
3154 SCIP* scip, /**< SCIP data structure */
3155 SCIP_CONS* cons, /**< nonlinear constraint */
3156 int nlockspos, /**< number of positive rounding locks */
3157 int nlocksneg /**< number of negative rounding locks */
3158 )
3159{
3160 SCIP_CONSDATA* consdata;
3161
3162 assert(cons != NULL);
3163
3164 if( nlockspos == 0 && nlocksneg == 0 )
3165 return SCIP_OKAY;
3166
3167 consdata = SCIPconsGetData(cons);
3168 assert(consdata != NULL);
3169
3170 /* no constraint sides -> nothing to lock */
3171 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3172 return SCIP_OKAY;
3173
3174 /* remember locks */
3175 consdata->nlockspos += nlockspos;
3176 consdata->nlocksneg += nlocksneg;
3177
3178 assert(consdata->nlockspos >= 0);
3179 assert(consdata->nlocksneg >= 0);
3180
3181 /* compute locks for lock propagation */
3182 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3183 {
3184 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg) );
3185 }
3186 else if( !SCIPisInfinity(scip, consdata->rhs) )
3187 {
3188 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg) );
3189 }
3190 else
3191 {
3192 assert(!SCIPisInfinity(scip, -consdata->lhs));
3193 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos) );
3194 }
3195
3196 return SCIP_OKAY;
3197}
3198
3199/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3200static
3202 SCIP* scip, /**< SCIP data structure */
3203 SCIP_CONS* cons /**< nonlinear constraint */
3204 )
3205{
3206 SCIP_CONSDATA* consdata;
3207
3208 assert(scip != NULL);
3209 assert(cons != NULL);
3210
3211 consdata = SCIPconsGetData(cons);
3212 assert(consdata != NULL);
3213 assert(consdata->expr != NULL);
3214
3215 if( consdata->nlrow != NULL )
3216 {
3217 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3218 }
3219
3220 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3221 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3222 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3223
3224 if( SCIPisExprSum(scip, consdata->expr) )
3225 {
3226 /* if root is a sum, then split into linear and nonlinear terms */
3227 SCIP_EXPR* nonlinpart;
3228 SCIP_EXPR* child;
3229 SCIP_Real* coefs;
3230 int i;
3231
3232 coefs = SCIPgetCoefsExprSum(consdata->expr);
3233
3234 /* constant term of sum */
3235 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3236
3237 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3238 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3239
3240 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3241 {
3242 child = SCIPexprGetChildren(consdata->expr)[i];
3243 if( SCIPisExprVar(scip, child) )
3244 {
3245 /* linear term */
3246 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3247 }
3248 else
3249 {
3250 /* nonlinear term */
3251 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3252 }
3253 }
3254
3255 if( SCIPexprGetNChildren(nonlinpart) > 0 )
3256 {
3257 /* add expression to nlrow (this will make a copy) */
3258 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3259 }
3260 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3261 }
3262 else
3263 {
3264 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3265 }
3266
3267 return SCIP_OKAY;
3268}
3269
3270/** compares enfodata by enforcement priority of nonlinear handler
3271 *
3272 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3273 */
3274static
3276{
3277 SCIP_NLHDLR* h1;
3278 SCIP_NLHDLR* h2;
3279
3280 assert(elem1 != NULL);
3281 assert(elem2 != NULL);
3282
3283 h1 = ((EXPRENFO*)elem1)->nlhdlr;
3284 h2 = ((EXPRENFO*)elem2)->nlhdlr;
3285
3286 assert(h1 != NULL);
3287 assert(h2 != NULL);
3288
3291
3294
3295 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3296}
3297
3298/** install nlhdlrs in one expression */
3299static
3301 SCIP* scip, /**< SCIP data structure */
3302 SCIP_EXPR* expr, /**< expression for which to run detection routines */
3303 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3304 )
3305{
3306 SCIP_EXPR_OWNERDATA* ownerdata;
3307 SCIP_CONSHDLRDATA* conshdlrdata;
3308 SCIP_NLHDLR_METHOD enforcemethodsallowed;
3309 SCIP_NLHDLR_METHOD enforcemethods;
3310 SCIP_NLHDLR_METHOD enforcemethodsnew;
3311 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3312 SCIP_NLHDLR_METHOD nlhdlrparticipating;
3313 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3314 int enfossize; /* allocated length of expr->enfos array */
3315 int h;
3316
3317 assert(expr != NULL);
3318
3319 ownerdata = SCIPexprGetOwnerData(expr);
3320 assert(ownerdata != NULL);
3321
3322 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3323 assert(conshdlrdata != NULL);
3324 assert(conshdlrdata->auxvarid >= 0);
3325 assert(!conshdlrdata->indetect);
3326
3327 /* there should be no enforcer yet and detection should not even have considered expr yet */
3328 assert(ownerdata->nenfos < 0);
3329 assert(ownerdata->enfos == NULL);
3330
3331 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3332 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3333 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3334 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3335 * - if no one uses activity, then do not need activity methods
3336 */
3337 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3338 if( ownerdata->nauxvaruses == 0 )
3339 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3340 else
3341 {
3342 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3343 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3344 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3345 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3346 }
3347 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3348 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3349
3350 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3351 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3352
3353 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3354 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3355
3356 ownerdata->nenfos = 0;
3357 enfossize = 2;
3358 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3359 conshdlrdata->indetect = TRUE;
3360
3361 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3362 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3363 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3364 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3365 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3366
3367 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3368 {
3369 SCIP_NLHDLR* nlhdlr;
3370
3371 nlhdlr = conshdlrdata->nlhdlrs[h];
3372 assert(nlhdlr != NULL);
3373
3374 /* skip disabled nlhdlrs */
3375 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3376 continue;
3377
3378 /* call detect routine of nlhdlr */
3379 nlhdlrexprdata = NULL;
3380 enforcemethodsnew = enforcemethods;
3381 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3382 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3383 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3384 /* coverity[var_deref_model] */
3385 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3386
3387 /* nlhdlr might have claimed more than needed: clean up sepa flags */
3388 nlhdlrparticipating &= enforcemethodsallowed;
3389
3390 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3391 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3392
3393 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3394 * They are also cleaned up here to ensure that only the needed methods are claimed.
3395 */
3396 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3397
3398 /* nlhdlr needs to participate for the methods it is enforcing */
3399 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3400
3401 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3402 {
3403 /* nlhdlr might not have detected anything, or all set flags might have been removed by
3404 * clean up; in the latter case, we may need to free nlhdlrexprdata */
3405
3406 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3407 if( nlhdlrexprdata != NULL )
3408 {
3409 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3410 }
3411 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3412 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3413
3414 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3415
3416 continue;
3417 }
3418
3419 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3420 SCIPnlhdlrGetName(nlhdlr),
3421 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3422 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3423 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3424
3425 /* store nlhdlr and its data */
3426 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3427 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3428 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3429 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3430 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3431 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3432 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3433 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3434 ownerdata->nenfos++;
3435
3436 /* update enforcement flags */
3437 enforcemethods = enforcemethodsnew;
3438 }
3439
3440 conshdlrdata->indetect = FALSE;
3441
3442 /* stop if an enforcement method is missing but we are already in solving stage
3443 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3444 */
3445 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3446 {
3447 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3448 return SCIP_ERROR;
3449 }
3450
3451 assert(ownerdata->nenfos > 0);
3452
3453 /* sort nonlinear handlers by enforcement priority, in decreasing order */
3454 if( ownerdata->nenfos > 1 )
3455 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3456
3457 /* resize enfos array to be nenfos long */
3458 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3459
3460 return SCIP_OKAY;
3461}
3462
3463/** detect nlhdlrs that can handle the expressions */
3464static
3466 SCIP* scip, /**< SCIP data structure */
3467 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3468 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3469 int nconss /**< total number of constraints */
3470 )
3471{
3472 SCIP_CONSHDLRDATA* conshdlrdata;
3473 SCIP_CONSDATA* consdata;
3474 SCIP_EXPR* expr;
3475 SCIP_EXPR_OWNERDATA* ownerdata;
3476 SCIP_EXPRITER* it;
3477 int i;
3478
3479 assert(conss != NULL || nconss == 0);
3480 assert(nconss >= 0);
3481 assert(SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVING && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3482
3483 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3484 assert(conshdlrdata != NULL);
3485
3488
3490 {
3491 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3492 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3493 */
3495 conshdlrdata->globalbounds = TRUE;
3496 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3497 }
3498
3499 for( i = 0; i < nconss; ++i )
3500 {
3501 assert(conss != NULL && conss[i] != NULL);
3502
3503 consdata = SCIPconsGetData(conss[i]);
3504 assert(consdata != NULL);
3505 assert(consdata->expr != NULL);
3506
3507 /* if a constraint is separated, we currently need it to be initial, too
3508 * this is because INITLP will create the auxiliary variables that are used for any separation
3509 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3510 */
3511 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3512
3513 ownerdata = SCIPexprGetOwnerData(consdata->expr);
3514 assert(ownerdata != NULL);
3515
3516 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3517 * then we would normally skip to run DETECT again
3518 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3519 * thus, if expr is the root expression, we rerun DETECT
3520 */
3521 if( ownerdata->nenfos > 0 )
3522 {
3523 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3524 assert(ownerdata->nenfos < 0);
3525 }
3526
3527 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3528 * this way we can treat the root expression like any other expression when enforcing via separation
3529 * if constraint will be propagated, then register activity usage of root expression
3530 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3531 */
3532 conshdlrdata->indetect = TRUE;
3535 SCIPconsIsPropagated(conss[i]),
3536 FALSE, FALSE) );
3537 conshdlrdata->indetect = FALSE;
3538
3539 /* presolveSingleLockedVars() may need the activity of product expressions in a sum expr that is in the root expr of a nonlinear constraint with only one finite side
3540 * if this presolver may be run in the current presolve round (presoltiming=exhaustive could be added as additional criterion),
3541 * then we ensure that a routine will be present to compute this activity (SCIPregisterExprUsageNonlinear actually updates activity already)
3542 */
3543 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd'
3544 && (SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs)) && SCIPisExprSum(scip, consdata->expr) )
3545 {
3546 int c;
3547 for( c = 0; c < SCIPexprGetNChildren(consdata->expr); ++c )
3548 {
3549 expr = SCIPexprGetChildren(consdata->expr)[c];
3550 if( SCIPisExprProduct(scip, expr) )
3551 {
3553 }
3554 }
3555 }
3556
3557 /* compute integrality information for all subexpressions */
3558 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3559
3560 /* run detectNlhdlr on all expr where required */
3561 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3562 {
3563 ownerdata = SCIPexprGetOwnerData(expr);
3564 assert(ownerdata != NULL);
3565
3566 /* skip exprs that we already looked at */
3567 if( ownerdata->nenfos >= 0 )
3568 continue;
3569
3570 /* if there is use of the auxvar, then someone requires that
3571 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3572 * thus, we need to find nlhdlrs that separate or estimate
3573 * if there is use of the activity, then there is someone requiring that
3574 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3575 * thus, we need to find nlhdlrs that do interval-evaluation
3576 */
3577 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3578 {
3579 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3580
3581 assert(ownerdata->nenfos >= 0);
3582 }
3583 else
3584 {
3585 /* remember that we looked at this expression during detectNlhdlrs
3586 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3587 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3588 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3589 */
3590 ownerdata->nenfos = 0;
3591 }
3592 }
3593
3594 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3595 if( SCIPconsIsPropagated(conss[i]) )
3596 consdata->ispropagated = FALSE;
3597 }
3598
3600 {
3601 /* ensure that the local bounds are used again when reevaluating the expressions later;
3602 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3603 */
3605 conshdlrdata->globalbounds = FALSE;
3606 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3607 }
3608 else
3609 {
3610 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3612 }
3613
3614 SCIPfreeExpriter(&it);
3615
3616 return SCIP_OKAY;
3617}
3618
3619/** initializes (pre)solving data of constraints
3620 *
3621 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3622 * not be modified.
3623 * In particular, this function
3624 * - runs the detection method of nlhldrs
3625 * - looks for unlocked linear variables
3626 * - checks curvature (if not in presolve)
3627 * - creates and add row to NLP (if not in presolve)
3628 *
3629 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3630 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3631 */
3632static
3634 SCIP* scip, /**< SCIP data structure */
3635 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3636 SCIP_CONS** conss, /**< constraints */
3637 int nconss /**< number of constraints */
3638 )
3639{
3640 int c;
3641
3642 for( c = 0; c < nconss; ++c )
3643 {
3644 /* check for a linear variable that can be increase or decreased without harming feasibility */
3645 findUnlockedLinearVar(scip, conss[c]);
3646
3648 {
3649 SCIP_CONSDATA* consdata;
3650 SCIP_Bool success = FALSE;
3651
3652 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3653 assert(consdata != NULL);
3654 assert(consdata->expr != NULL);
3655
3656 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3657 {
3658 /* call the curvature detection algorithm of the convex nonlinear handler
3659 * Check only for those curvature that may result in a convex inequality, i.e.,
3660 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3661 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3662 */
3663 if( !SCIPisInfinity(scip, -consdata->lhs) )
3664 {
3665 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3666 if( success )
3667 consdata->curv = SCIP_EXPRCURV_CONCAVE;
3668 }
3669 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3670 {
3671 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3672 if( success )
3673 consdata->curv = SCIP_EXPRCURV_CONVEX;
3674 }
3675 }
3676 else
3677 {
3678 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3679 {
3680 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3681 consdata->curv = SCIP_EXPRCURV_LINEAR;
3682 }
3683 else
3684 {
3685 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3686 }
3687 }
3688 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3689
3690 /* add nlrow representation to NLP, if NLP had been constructed */
3691 if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3692 {
3693 if( consdata->nlrow == NULL )
3694 {
3695 SCIP_CALL( createNlRow(scip, conss[c]) );
3696 assert(consdata->nlrow != NULL);
3697 }
3698 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3699 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3700 }
3701 }
3702 }
3703
3704 /* register non linear handlers */
3705 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3706
3707 return SCIP_OKAY;
3708}
3709
3710/** deinitializes (pre)solving data of constraints
3711 *
3712 * This removes the initialization data created in initSolve().
3713 *
3714 * This function can be called in presolve and solve.
3715 *
3716 * TODO At the moment, it should not be called for a constraint if there are other constraints
3717 * that use the same expressions but still require their nlhdlr.
3718 * We should probably only decrement the auxvar and activity usage for the root expr and then
3719 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3720 */
3721static
3723 SCIP* scip, /**< SCIP data structure */
3724 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3725 SCIP_CONS** conss, /**< constraints */
3726 int nconss /**< number of constraints */
3727 )
3728{
3729 SCIP_EXPRITER* it;
3730 SCIP_EXPR* expr;
3731 SCIP_CONSDATA* consdata;
3732 SCIP_Bool rootactivityvalid;
3733 int c;
3734
3738
3739 /* call deinitialization callbacks of expression and nonlinear handlers
3740 * free nonlinear handlers information from expressions
3741 * remove auxiliary variables and nactivityuses counts from expressions
3742 */
3743 for( c = 0; c < nconss; ++c )
3744 {
3745 assert(conss != NULL);
3746 assert(conss[c] != NULL);
3747
3748 consdata = SCIPconsGetData(conss[c]);
3749 assert(consdata != NULL);
3750 assert(consdata->expr != NULL);
3751
3752 /* check and remember whether activity in root is valid */
3753 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3754
3755 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3756 {
3757 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3758
3759 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3760 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3761
3762 /* remove quadratic info */
3764
3765 if( rootactivityvalid )
3766 {
3767 /* ensure activity is valid if consdata->expr activity is valid
3768 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3769 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3770 * so this childs activity would be invalid, which can generate confusion
3771 */
3773 }
3774 }
3775
3776 if( consdata->nlrow != NULL )
3777 {
3778 /* remove row from NLP, if still in solving
3779 * if we are in exitsolve, the whole NLP will be freed anyway
3780 */
3782 {
3783 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3784 }
3785
3786 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3787 }
3788
3789 /* forget about linear variables that can be increased or decreased without harming feasibility */
3790 consdata->linvardecr = NULL;
3791 consdata->linvarincr = NULL;
3792
3793 /* forget about curvature */
3794 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3795 }
3796
3797 SCIPfreeExpriter(&it);
3798
3799 return SCIP_OKAY;
3800}
3801
3802/** helper method to decide whether a given expression is product of at least two binary variables */
3803static
3805 SCIP* scip, /**< SCIP data structure */
3806 SCIP_EXPR* expr /**< expression */
3807 )
3808{
3809 int i;
3810
3811 assert(expr != NULL);
3812
3813 /* check whether the expression is a product */
3814 if( !SCIPisExprProduct(scip, expr) )
3815 return FALSE;
3816
3817 /* don't consider products with a coefficient != 1 and products with a single child
3818 * simplification will take care of this expression later
3819 */
3820 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3821 return FALSE;
3822
3823 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3824 {
3825 SCIP_EXPR* child;
3826 SCIP_VAR* var;
3827
3828 child = SCIPexprGetChildren(expr)[i];
3829 assert(child != NULL);
3830
3831 if( !SCIPisExprVar(scip, child) )
3832 return FALSE;
3833
3834 var = SCIPgetVarExprVar(child);
3835
3836 /* check whether variable is binary, in any feasible solution
3837 * we need to forbid weakly implied binary variables because cons_and wouldn't ensure that the
3838 * product condition holds in any feasible solution (i.e., when vars may not be at bounds) in this case,
3839 * which would lead to accepting solutions that are not feasible in the original (non-reformulated) cons
3840 */
3842 return FALSE;
3843 }
3844
3845 return TRUE;
3846}
3847
3848/** helper method to collect all bilinear binary product terms */
3849static
3851 SCIP* scip, /**< SCIP data structure */
3852 SCIP_EXPR* sumexpr, /**< sum expression */
3853 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3854 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3855 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3856 int* nterms /**< pointer to store the total number of bilinear binary terms */
3857 )
3858{
3859 int i;
3860
3861 assert(sumexpr != NULL);
3862 assert(SCIPisExprSum(scip, sumexpr));
3863 assert(xs != NULL);
3864 assert(ys != NULL);
3865 assert(childidxs != NULL);
3866 assert(nterms != NULL);
3867
3868 *nterms = 0;
3869
3870 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3871 {
3872 SCIP_EXPR* child;
3873
3874 child = SCIPexprGetChildren(sumexpr)[i];
3875 assert(child != NULL);
3876
3877 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3878 {
3881
3882 assert(x != NULL);
3883 assert(y != NULL);
3884
3885 if( x != y )
3886 {
3887 xs[*nterms] = x;
3888 ys[*nterms] = y;
3889 childidxs[*nterms] = i;
3890 ++(*nterms);
3891 }
3892 }
3893 }
3894
3895 return SCIP_OKAY;
3896}
3897
3898/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3899static
3901 SCIP* scip, /**< SCIP data structure */
3902 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3903 SCIP_CONS* cons, /**< constraint */
3904 SCIP_VAR* facvar, /**< variable that has been factorized */
3905 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3906 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3907 int nvars, /**< total number of variables in sum_j c_ij x_j */
3908 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3909 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3910 )
3911{
3912 SCIP_VAR* auxvar;
3913 SCIP_CONS* newcons;
3914 SCIP_Real minact = 0.0;
3915 SCIP_Real maxact = 0.0;
3917 char name [SCIP_MAXSTRLEN];
3918 int i;
3919
3920 assert(facvar != NULL);
3921 assert(vars != NULL);
3922 assert(nvars > 1);
3923 assert(newexpr != NULL);
3924
3925 /* compute minimum and maximum activity of sum_j c_ij x_j */
3926 /* TODO could compute minact and maxact for facvar=0 and facvar=1 separately, taking implied bounds into account, allowing for possibly tighter big-M's below */
3927 for( i = 0; i < nvars; ++i )
3928 {
3929 minact += MIN(coefs[i], 0.0);
3930 maxact += MAX(coefs[i], 0.0);
3931 assert(SCIPvarIsIntegral(vars[i]));
3933
3934 if( impltype != SCIP_IMPLINTTYPE_NONE && !SCIPisIntegral(scip, coefs[i]) )
3935 impltype = SCIP_IMPLINTTYPE_NONE;
3936 }
3937 assert(minact <= maxact);
3938
3939 /* create and add auxiliary variable */
3940 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3941 SCIP_CALL( SCIPcreateVarImpl(scip, &auxvar, name, minact, maxact, 0.0, SCIP_VARTYPE_CONTINUOUS, impltype,
3942 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
3943 SCIP_CALL( SCIPaddVar(scip, auxvar) );
3944
3945#ifdef WITH_DEBUG_SOLUTION
3946 if( SCIPdebugIsMainscip(scip) )
3947 {
3948 SCIP_Real debugsolval; /* value of auxvar in debug solution */
3949 SCIP_Real val;
3950
3951 /* compute value of new variable in debug solution */
3952 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
3953 debugsolval = 0.0;
3954 for( i = 0; i < nvars; ++i )
3955 {
3956 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
3957 debugsolval += coefs[i] * val;
3958 }
3959
3960 /* now multiply by x_i (facvar) */
3961 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
3962 debugsolval *= val;
3963
3964 /* store debug solution value of auxiliary variable */
3965 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
3966 }
3967#endif
3968
3969 /* create and add z - maxact x <= 0 */
3970 if( !SCIPisZero(scip, maxact) )
3971 {
3972 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3973 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3974 SCIP_CALL( SCIPaddCons(scip, newcons) );
3975 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3976 if( naddconss != NULL )
3977 ++(*naddconss);
3978 }
3979
3980 /* create and add 0 <= z - minact x */
3981 if( !SCIPisZero(scip, minact) )
3982 {
3983 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3984 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3985 SCIP_CALL( SCIPaddCons(scip, newcons) );
3986 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3987 if( naddconss != NULL )
3988 ++(*naddconss);
3989 }
3990
3991 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3993 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3994 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3995 if( !SCIPisZero(scip, minact) )
3996 {
3997 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3998 }
3999 SCIP_CALL( SCIPaddCons(scip, newcons) );
4000 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4001 if( naddconss != NULL )
4002 ++(*naddconss);
4003
4004 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4005 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4006 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4007 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4008 if( !SCIPisZero(scip, maxact) )
4009 {
4010 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4011 }
4012 SCIP_CALL( SCIPaddCons(scip, newcons) );
4013 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4014 if( naddconss != NULL )
4015 ++(*naddconss);
4016
4017 /* create variable expression */
4018 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4019
4020 /* release auxvar */
4021 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4022
4023 return SCIP_OKAY;
4024}
4025
4026/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4027static
4029 SCIP* scip, /**< SCIP data structure */
4030 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4031 SCIP_CONS* cons, /**< constraint */
4032 SCIP_EXPR* sumexpr, /**< expression */
4033 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4034 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4035 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4036 )
4037{
4038 SCIP_EXPR** exprs = NULL;
4039 SCIP_VAR** tmpvars = NULL;
4040 SCIP_VAR** vars = NULL;
4041 SCIP_VAR** xs = NULL;
4042 SCIP_VAR** ys = NULL;
4043 SCIP_Real* exprcoefs = NULL;
4044 SCIP_Real* tmpcoefs = NULL;
4045 SCIP_Real* sumcoefs;
4046 SCIP_Bool* isused = NULL;
4047 int* childidxs = NULL;
4048 int* count = NULL;
4049 int nchildren;
4050 int nexprs = 0;
4051 int nterms;
4052 int nvars;
4053 int ntotalvars;
4054 int i;
4055
4056 assert(sumexpr != NULL);
4057 assert(minterms > 1);
4058 assert(newexpr != NULL);
4059
4060 *newexpr = NULL;
4061
4062 /* check whether sumexpr is indeed a sum */
4063 if( !SCIPisExprSum(scip, sumexpr) )
4064 return SCIP_OKAY;
4065
4066 nchildren = SCIPexprGetNChildren(sumexpr);
4067 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4068 nvars = SCIPgetNVars(scip);
4069 ntotalvars = SCIPgetNTotalVars(scip);
4070
4071 /* check whether there are enough terms available */
4072 if( nchildren < minterms )
4073 return SCIP_OKAY;
4074
4075 /* allocate memory */
4076 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4077 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4078 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4079
4080 /* collect all bilinear binary product terms */
4081 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4082
4083 /* check whether there are enough terms available */
4084 if( nterms < minterms )
4085 goto TERMINATE;
4086
4087 /* store how often each variable appears in a bilinear binary product */
4089 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4090 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4091
4092 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4093 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4094 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4095 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4096
4097 for( i = 0; i < nterms; ++i )
4098 {
4099 int xidx;
4100 int yidx;
4101
4102 assert(xs[i] != NULL);
4103 assert(ys[i] != NULL);
4104
4105 xidx = SCIPvarGetIndex(xs[i]);
4106 assert(xidx < ntotalvars);
4107 yidx = SCIPvarGetIndex(ys[i]);
4108 assert(yidx < ntotalvars);
4109
4110 ++count[xidx];
4111 ++count[yidx];
4112
4113 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4114 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4115 }
4116
4117 /* sort variables; don't change order of count array because it depends on problem indices */
4118 {
4119 int* tmpcount;
4120
4121 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4122 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4123 SCIPfreeBufferArray(scip, &tmpcount);
4124 }
4125
4126 for( i = 0; i < nvars; ++i )
4127 {
4128 SCIP_VAR* facvar = vars[i];
4129 int ntmpvars = 0;
4130 int j;
4131
4132 /* skip candidate if there are not enough terms left */
4133 if( count[SCIPvarGetIndex(vars[i])] < minterms )
4134 continue;
4135
4136 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4137
4138 /* collect variables for x_i * sum_j c_ij x_j */
4139 for( j = 0; j < nterms; ++j )
4140 {
4141 int childidx = childidxs[j];
4142 assert(childidx >= 0 && childidx < nchildren);
4143
4144 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4145 {
4146 SCIP_Real coef;
4147 int xidx;
4148 int yidx;
4149
4150 coef = sumcoefs[childidx];
4151 assert(coef != 0.0);
4152
4153 /* collect corresponding variable */
4154 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4155 tmpcoefs[ntmpvars] = coef;
4156 ++ntmpvars;
4157
4158 /* update counters */
4159 xidx = SCIPvarGetIndex(xs[j]);
4160 assert(xidx < ntotalvars);
4161 yidx = SCIPvarGetIndex(ys[j]);
4162 assert(yidx < ntotalvars);
4163 --count[xidx];
4164 --count[yidx];
4165 assert(count[xidx] >= 0);
4166 assert(count[yidx] >= 0);
4167
4168 /* mark term to be used */
4169 isused[childidx] = TRUE;
4170 }
4171 }
4172 assert(ntmpvars >= minterms);
4173 assert(SCIPvarGetIndex(facvar) < ntotalvars);
4174 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4175
4176 /* create required constraints and store the generated expression */
4177 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4178 exprcoefs[nexprs] = 1.0;
4179 ++nexprs;
4180 }
4181
4182 /* factorization was only successful if at least one expression has been generated */
4183 if( nexprs > 0 )
4184 {
4185 int nexprsold = nexprs;
4186
4187 /* add all children of the sum that have not been used */
4188 for( i = 0; i < nchildren; ++i )
4189 {
4190 if( !isused[i] )
4191 {
4192 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4193 exprcoefs[nexprs] = sumcoefs[i];
4194 ++nexprs;
4195 }
4196 }
4197
4198 /* create a new sum expression */
4199 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4200
4201 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4202 for( i = 0; i < nexprsold; ++i )
4203 {
4204 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4205 }
4206 }
4207
4208TERMINATE:
4209 /* free memory */
4210 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4211 SCIPfreeBufferArrayNull(scip, &tmpvars);
4212 SCIPfreeBufferArrayNull(scip, &exprcoefs);
4215 SCIPfreeBufferArrayNull(scip, &isused);
4217 SCIPfreeBufferArray(scip, &childidxs);
4220
4221 return SCIP_OKAY;
4222}
4223
4224/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4225static
4227 SCIP* scip, /**< SCIP data structure */
4228 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4229 SCIP_EXPR* prodexpr, /**< product expression */
4230 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4231 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4232 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4233 )
4234{
4235 SCIP_VAR** vars;
4236 SCIP_CONS* cons;
4237 SCIP_Real* coefs;
4238 SCIP_VAR* w;
4239 char* name;
4240 int nchildren;
4241 int i;
4242
4243 assert(conshdlr != NULL);
4244 assert(prodexpr != NULL);
4245 assert(SCIPisExprProduct(scip, prodexpr));
4246 assert(newexpr != NULL);
4247
4248 nchildren = SCIPexprGetNChildren(prodexpr);
4249 assert(nchildren >= 2);
4250
4251 /* memory to store the variables of the variable expressions (+1 for w) and their name */
4252 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4253 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4254 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4255
4256 /* prepare the names of the variable and the constraints */
4257 /* coverity[secure_coding] */
4258 strcpy(name, "binreform");
4259 for( i = 0; i < nchildren; ++i )
4260 {
4261 vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4262 coefs[i] = 1.0;
4263 assert(vars[i] != NULL);
4264 (void) strcat(name, "_");
4265 (void) strcat(name, SCIPvarGetName(vars[i]));
4266
4267 assert(SCIPvarIsBinary(vars[i]) && SCIPvarGetImplType(vars[i]) != SCIP_IMPLINTTYPE_WEAK);
4268 }
4269
4270 /* create and add variable */
4271 SCIP_CALL( SCIPcreateVarImpl(scip, &w, name, 0.0, 1.0, 0.0,
4273 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
4275 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4276
4277#ifdef WITH_DEBUG_SOLUTION
4278 if( SCIPdebugIsMainscip(scip) )
4279 {
4280 SCIP_Real debugsolval; /* value of auxvar in debug solution */
4281 SCIP_Real val;
4282
4283 /* compute value of new variable in debug solution (\prod_i vars[i]) */
4284 debugsolval = 1.0;
4285 for( i = 0; i < nchildren; ++i )
4286 {
4287 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
4288 debugsolval *= val;
4289 }
4290
4291 /* store debug solution value of auxiliary variable */
4292 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
4293 }
4294#endif
4295
4296 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4297 if( nchildren == 2 && !empathy4and )
4298 {
4299 SCIP_VAR* x = vars[0];
4300 SCIP_VAR* y = vars[1];
4301
4302 assert(x != NULL);
4303 assert(y != NULL);
4304 assert(x != y);
4305
4306 /* create and add x - w >= 0 */
4307 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4308 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4309 SCIP_CALL( SCIPaddCons(scip, cons) );
4310 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4311
4312 /* create and add y - w >= 0 */
4313 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4314 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4315 SCIP_CALL( SCIPaddCons(scip, cons) );
4316 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4317
4318 /* create and add x + y - w <= 1 */
4319 vars[2] = w;
4320 coefs[2] = -1.0;
4321 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4322 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4323 SCIP_CALL( SCIPaddCons(scip, cons) );
4324 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4325
4326 /* update number of added constraints */
4327 if( naddconss != NULL )
4328 *naddconss += 3;
4329 }
4330 else
4331 {
4332 /* create, add, and release AND constraint */
4333 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4334 SCIP_CALL( SCIPaddCons(scip, cons) );
4335 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4336 SCIPdebugMsg(scip, " create AND constraint\n");
4337
4338 /* update number of added constraints */
4339 if( naddconss != NULL )
4340 *naddconss += 1;
4341 }
4342
4343 /* create variable expression */
4344 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4345
4346 /* release created variable */
4348
4349 /* free memory */
4350 SCIPfreeBufferArray(scip, &name);
4351 SCIPfreeBufferArray(scip, &coefs);
4352 SCIPfreeBufferArray(scip, &vars);
4353
4354 return SCIP_OKAY;
4355}
4356
4357/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4358static
4360 SCIP* scip, /**< SCIP data structure */
4361 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4362 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4363 SCIP_EXPR* prodexpr, /**< product expression */
4364 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4365 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4366 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4367 )
4368{
4369 SCIP_CONSHDLRDATA* conshdlrdata;
4370 int nchildren;
4371
4372 assert(prodexpr != NULL);
4373 assert(newexpr != NULL);
4374
4375 *newexpr = NULL;
4376
4377 /* only consider products of binary variables */
4378 if( !isBinaryProduct(scip, prodexpr) )
4379 return SCIP_OKAY;
4380
4381 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4382 assert(conshdlrdata != NULL);
4383 nchildren = SCIPexprGetNChildren(prodexpr);
4384 assert(nchildren >= 2);
4385
4386 /* check whether there is already an expression that represents the product */
4387 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4388 {
4389 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4390 assert(*newexpr != NULL);
4391
4392 /* capture expression */
4393 SCIPcaptureExpr(*newexpr);
4394 }
4395 else
4396 {
4397 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4398
4399 if( nchildren == 2 )
4400 {
4401 SCIP_CLIQUE** xcliques;
4402 SCIP_VAR* x;
4403 SCIP_VAR* y;
4404 SCIP_Bool found_clique = FALSE;
4405 int c;
4406
4407 /* get variables from the product expression */
4408 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4409 assert(x != NULL);
4410 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4411 assert(y != NULL);
4412 assert(x != y);
4413
4414 /* first try to find a clique containing both variables */
4415 xcliques = SCIPvarGetCliques(x, TRUE);
4416
4417 /* look in cliques containing x */
4418 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4419 {
4420 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4421 {
4422 /* create zero value expression */
4423 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4424
4425 if( nchgcoefs != NULL )
4426 *nchgcoefs += 1;
4427
4428 found_clique = TRUE;
4429 break;
4430 }
4431
4432 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4433 {
4434 /* create variable expression for x */
4435 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4436
4437 if( nchgcoefs != NULL )
4438 *nchgcoefs += 2;
4439
4440 found_clique = TRUE;
4441 break;
4442 }
4443 }
4444
4445 if( !found_clique )
4446 {
4447 xcliques = SCIPvarGetCliques(x, FALSE);
4448
4449 /* look in cliques containing complement of x */
4450 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4451 {
4452 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4453 {
4454 /* create variable expression for y */
4455 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4456
4457 if( nchgcoefs != NULL )
4458 *nchgcoefs += 1;
4459
4460 found_clique = TRUE;
4461 break;
4462 }
4463
4464 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4465 {
4466 /* create sum expression */
4467 SCIP_EXPR* sum_children[2];
4468 SCIP_Real sum_coefs[2];
4469 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4470 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4471 sum_coefs[0] = 1.0;
4472 sum_coefs[1] = 1.0;
4473 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4474
4475 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4476 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4477
4478 if( nchgcoefs != NULL )
4479 *nchgcoefs += 3;
4480
4481 found_clique = TRUE;
4482 break;
4483 }
4484 }
4485 }
4486
4487 /* if the variables are not in a clique, do standard linearization */
4488 if( !found_clique )
4489 {
4490 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4491 }
4492 }
4493 else
4494 {
4495 /* linearize binary product using an AND constraint because nchildren > 2 */
4496 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4497 }
4498
4499 /* hash variable expression */
4500 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4501 }
4502
4503 return SCIP_OKAY;
4504}
4505
4506/** helper function to replace binary products in a given constraint */
4507static
4509 SCIP* scip, /**< SCIP data structure */
4510 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4511 SCIP_CONS* cons, /**< constraint */
4512 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4513 SCIP_EXPRITER* it, /**< expression iterator */
4514 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4515 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4516 )
4517{
4518 SCIP_CONSHDLRDATA* conshdlrdata;
4519 SCIP_CONSDATA* consdata;
4520 SCIP_EXPR* expr;
4521
4522 assert(conshdlr != NULL);
4523 assert(cons != NULL);
4524 assert(exprmap != NULL);
4525 assert(it != NULL);
4526
4527 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4528 assert(conshdlrdata != NULL);
4529
4530 consdata = SCIPconsGetData(cons);
4531 assert(consdata != NULL);
4532 assert(consdata->expr != NULL);
4533
4534 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4535
4536 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4537 {
4538 SCIP_EXPR* newexpr = NULL;
4539 SCIP_EXPR* childexpr;
4540 int childexpridx;
4541
4542 childexpridx = SCIPexpriterGetChildIdxDFS(it);
4543 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4544 childexpr = SCIPexpriterGetChildExprDFS(it);
4545 assert(childexpr != NULL);
4546
4547 /* try to factorize variables in a sum expression that contains several products of binary variables */
4548 if( conshdlrdata->reformbinprodsfac > 1 )
4549 {
4550 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4551 }
4552
4553 /* try to create an expression that represents a product of binary variables */
4554 if( newexpr == NULL )
4555 {
4556 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4557 }
4558
4559 if( newexpr != NULL )
4560 {
4561 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4562
4563 /* replace product expression */
4564 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4565
4566 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4567 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4568
4569 /* mark the constraint to not be simplified anymore */
4570 consdata->issimplified = FALSE;
4571 }
4572 }
4573
4574 return SCIP_OKAY;
4575}
4576
4577/** reformulates products of binary variables during presolving in the following way:
4578 *
4579 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4580 * Each term \f$x_i x_j\f$ is reformulated with the help of an extra (implicit integer) variable \f$z_{ij}\f$ in {0,1}:
4581 * \f[
4582 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4583 * \f]
4584 *
4585 * Before reformulating \f$x_i x_j\f$ in this way, it is checked whether there is a clique that contains \f$x_i\f$ and \f$x_j\f$.
4586 * These cliques allow for a better reformulation. There are four cases:
4587 *
4588 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4589 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4590 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4591 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4592 *
4593 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4594 *
4595 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4596 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4597 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4598 * Such a lower sum is reformulated with only one extra variable w_i:
4599 * \f{align}{
4600 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4601 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4602 * \text{minact}\, x_i & \leq w_i, \\
4603 * w_i &\leq \text{maxact}\, x_i, \\
4604 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4605 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4606 * \f}
4607 * We mark \f$w_i\f$ to be implicit integer if all \f$Q_{ij}\f$ are integer. After each replacement of a lower sum, it
4608 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4609 * of terms are prioritized.
4610 */
4611static
4613 SCIP* scip, /**< SCIP data structure */
4614 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4615 SCIP_CONS** conss, /**< constraints */
4616 int nconss, /**< total number of constraints */
4617 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4618 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4619 )
4620{
4621 SCIP_CONSHDLRDATA* conshdlrdata;
4622 SCIP_HASHMAP* exprmap;
4623 SCIP_EXPRITER* it;
4624 int c;
4625
4626 assert(conshdlr != NULL);
4627
4628 /* no nonlinear constraints or binary variables -> skip */
4629 if( nconss == 0 || SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip) == 0 )
4630 return SCIP_OKAY;
4631 assert(conss != NULL);
4632
4633 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4634 assert(conshdlrdata != NULL);
4635
4636 /* create expression hash map */
4638
4639 /* create expression iterator */
4643
4644 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4645
4646 for( c = 0; c < nconss; ++c )
4647 {
4648 SCIP_CONSDATA* consdata;
4649 SCIP_EXPR* newexpr = NULL;
4650
4651 assert(conss[c] != NULL);
4652
4653 consdata = SCIPconsGetData(conss[c]);
4654 assert(consdata != NULL);
4655
4656 /* try to reformulate the root expression */
4657 if( conshdlrdata->reformbinprodsfac > 1 )
4658 {
4659 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4660 }
4661
4662 /* release the root node if another expression has been found */
4663 if( newexpr != NULL )
4664 {
4665 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4666 consdata->expr = newexpr;
4667
4668 /* mark constraint to be not simplified anymore */
4669 consdata->issimplified = FALSE;
4670 }
4671
4672 /* replace each product of binary variables separately */
4673 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4674 }
4675
4676 /* free memory */
4677 SCIPhashmapFree(&exprmap);
4678 SCIPfreeExpriter(&it);
4679
4680 return SCIP_OKAY;
4681}
4682
4683/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4684 *
4685 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4686 * Then scale by -1 if
4687 * - \f$n_+ < n_-\f$, or
4688 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4689 */
4690static
4692 SCIP* scip, /**< SCIP data structure */
4693 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4694 SCIP_CONS* cons, /**< nonlinear constraint */
4695 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4696 )
4697{
4698 SCIP_CONSDATA* consdata;
4699 int i;
4700
4701 assert(cons != NULL);
4702
4703 consdata = SCIPconsGetData(cons);
4704 assert(consdata != NULL);
4705
4706 if( SCIPisExprSum(scip, consdata->expr) )
4707 {
4708 SCIP_Real* coefs;
4709 SCIP_Real constant;
4710 int nchildren;
4711 int counter = 0;
4712
4713 coefs = SCIPgetCoefsExprSum(consdata->expr);
4714 constant = SCIPgetConstantExprSum(consdata->expr);
4715 nchildren = SCIPexprGetNChildren(consdata->expr);
4716
4717 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4718 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4719 {
4720 SCIP_EXPR* expr;
4721 expr = consdata->expr;
4722
4723 consdata->expr = SCIPexprGetChildren(expr)[0];
4724 assert(!SCIPisExprSum(scip, consdata->expr));
4725
4726 SCIPcaptureExpr(consdata->expr);
4727
4728 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4729 consdata->lhs = -consdata->lhs;
4730 consdata->rhs = -consdata->rhs;
4731
4732 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4733 *changed = TRUE;
4734 return SCIP_OKAY;
4735 }
4736
4737 /* compute n_+ - n_i */
4738 for( i = 0; i < nchildren; ++i )
4739 counter += coefs[i] > 0 ? 1 : -1;
4740
4741 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4742 {
4743 SCIP_EXPR* expr;
4744 SCIP_Real* newcoefs;
4745
4746 /* allocate memory */
4747 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4748
4749 for( i = 0; i < nchildren; ++i )
4750 newcoefs[i] = -coefs[i];
4751
4752 /* create a new sum expression */
4753 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4754
4755 /* replace expression in constraint data and scale sides */
4756 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4757 consdata->expr = expr;
4758 SCIPswapReals(&consdata->lhs, &consdata->rhs);
4759 consdata->lhs = -consdata->lhs;
4760 consdata->rhs = -consdata->rhs;
4761
4762 /* free memory */
4763 SCIPfreeBufferArray(scip, &newcoefs);
4764
4765 *changed = TRUE;
4766 }
4767 }
4768
4769 return SCIP_OKAY;
4770}
4771
4772/** forbid multiaggrations of variables that appear nonlinear in constraints */
4773static
4775 SCIP* scip, /**< SCIP data structure */
4776 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4777 SCIP_CONS** conss, /**< constraints */
4778 int nconss /**< number of constraints */
4779 )
4780{
4781 SCIP_EXPRITER* it;
4782 SCIP_CONSDATA* consdata;
4783 SCIP_EXPR* expr;
4784 int c;
4785
4786 assert(scip != NULL);
4787 assert(conshdlr != NULL);
4788
4789 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4790 return SCIP_OKAY;
4791
4794
4795 for( c = 0; c < nconss; ++c )
4796 {
4797 consdata = SCIPconsGetData(conss[c]);
4798 assert(consdata != NULL);
4799
4800 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4801 * i.e., skip children of sum that are variables
4802 */
4803 if( SCIPisExprSum(scip, consdata->expr) )
4804 {
4805 int i;
4806 SCIP_EXPR* child;
4807 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4808 {
4809 child = SCIPexprGetChildren(consdata->expr)[i];
4810
4811 /* skip variable expression, as they correspond to a linear term */
4812 if( SCIPisExprVar(scip, child) )
4813 continue;
4814
4815 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4816 if( SCIPisExprVar(scip, expr) )
4817 {
4819 }
4820 }
4821 }
4822 else
4823 {
4824 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4825 if( SCIPisExprVar(scip, expr) )
4826 {
4828 }
4829 }
4830 }
4831
4832 SCIPfreeExpriter(&it);
4833
4834 return SCIP_OKAY;
4835}
4836
4837/** simplifies expressions and replaces common subexpressions for a set of constraints
4838 * @todo put the constant to the constraint sides
4839 */
4840static
4842 SCIP* scip, /**< SCIP data structure */
4843 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4844 SCIP_CONS** conss, /**< constraints */
4845 int nconss, /**< total number of constraints */
4846 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4847 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4848 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4849 int* naddconss, /**< counter to add number of added constraints, or NULL */
4850 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4851 )
4852{
4853 SCIP_CONSHDLRDATA* conshdlrdata;
4854 SCIP_CONSDATA* consdata;
4855 int* nlockspos;
4856 int* nlocksneg;
4857 SCIP_Bool havechange;
4858 int i;
4859
4860 assert(scip != NULL);
4861 assert(conshdlr != NULL);
4862 assert(conss != NULL);
4863 assert(nconss > 0);
4864 assert(infeasible != NULL);
4865
4866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4867 assert(conshdlrdata != NULL);
4868
4869 /* update number of canonicalize calls */
4870 ++(conshdlrdata->ncanonicalizecalls);
4871
4872 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4873
4874 *infeasible = FALSE;
4875
4876 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4877 havechange = conshdlrdata->ncanonicalizecalls == 1;
4878
4879 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4880 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4881
4882 /* allocate memory for storing locks of each constraint */
4883 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4884 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4885
4886 /* unlock all constraints */
4887 for( i = 0; i < nconss; ++i )
4888 {
4889 assert(conss[i] != NULL);
4890
4891 consdata = SCIPconsGetData(conss[i]);
4892 assert(consdata != NULL);
4893
4894 /* remember locks */
4895 nlockspos[i] = consdata->nlockspos;
4896 nlocksneg[i] = consdata->nlocksneg;
4897
4898 /* remove locks */
4899 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4900 assert(consdata->nlockspos == 0);
4901 assert(consdata->nlocksneg == 0);
4902 }
4903
4904#ifndef NDEBUG
4905 /* check whether all locks of each expression have been removed */
4906 for( i = 0; i < nconss; ++i )
4907 {
4908 SCIP_EXPR* expr;
4909 SCIP_EXPRITER* it;
4910
4912
4913 consdata = SCIPconsGetData(conss[i]);
4914 assert(consdata != NULL);
4915
4917 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4918 {
4919 assert(expr != NULL);
4920 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4921 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4922 }
4923 SCIPfreeExpriter(&it);
4924 }
4925#endif
4926
4927 /* reformulate products of binary variables */
4928 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4929 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4930 {
4931 int tmpnaddconss = 0;
4932 int tmpnchgcoefs = 0;
4933
4934 /* call this function before simplification because expressions might not be simplified after reformulating
4935 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4936 */
4937 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4938
4939 /* update counters */
4940 if( naddconss != NULL )
4941 *naddconss += tmpnaddconss;
4942 if( nchgcoefs != NULL )
4943 *nchgcoefs += tmpnchgcoefs;
4944
4945 /* check whether at least one expression has changed */
4946 if( tmpnaddconss + tmpnchgcoefs > 0 )
4947 havechange = TRUE;
4948 }
4949
4950 for( i = 0; i < nconss; ++i )
4951 {
4952 consdata = SCIPconsGetData(conss[i]);
4953 assert(consdata != NULL);
4954
4955 /* call simplify for each expression */
4956 if( !consdata->issimplified && consdata->expr != NULL )
4957 {
4958 SCIP_EXPR* simplified;
4959 SCIP_Bool changed;
4960
4961 changed = FALSE;
4962 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4963 consdata->issimplified = TRUE;
4964
4965 if( changed )
4966 havechange = TRUE;
4967
4968 /* If root expression changed, then we need to take care updating the locks as well (the consdata is the one holding consdata->expr "as a child").
4969 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4970 */
4971 if( simplified != consdata->expr )
4972 {
4973 assert(changed);
4974
4975 /* release old expression */
4976 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4977
4978 /* store simplified expression */
4979 consdata->expr = simplified;
4980 }
4981 else
4982 {
4983 /* The simplify captures simplified in any case, also if nothing has changed.
4984 * Therefore, we have to release it here.
4985 */
4986 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4987 }
4988
4989 if( *infeasible )
4990 break;
4991
4992 /* scale constraint sides */
4993 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4994
4995 if( changed )
4996 havechange = TRUE;
4997
4998 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4999 if( SCIPisExprValue(scip, consdata->expr) )
5000 {
5001 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5002 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5003 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5004 {
5005 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5006 SCIPdebugPrintCons(scip, conss[i], NULL);
5007 *infeasible = TRUE;
5008 break;
5009 }
5010 else
5011 {
5012 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5013 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5014 if( ndelconss != NULL )
5015 ++*ndelconss;
5016 havechange = TRUE;
5017 }
5018 }
5019 }
5020 }
5021
5022 /* replace common subexpressions */
5023 if( havechange && !*infeasible )
5024 {
5025 SCIP_CONS** consssorted;
5026 SCIP_EXPR** rootexprs;
5027 SCIP_Bool replacedroot;
5028
5029 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5030 for( i = 0; i < nconss; ++i )
5031 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5032
5033 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5034
5035 /* update pointer to root expr in constraints, if any has changed
5036 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5037 */
5038 if( replacedroot )
5039 for( i = 0; i < nconss; ++i )
5040 SCIPconsGetData(conss[i])->expr = rootexprs[i];
5041
5042 SCIPfreeBufferArray(scip, &rootexprs);
5043
5044 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5045 * been changed after simplification; now we completely recollect all variable expression and variable events
5046 */
5047
5048 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5049 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5050 */
5051 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5052 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5053
5054 for( i = nconss-1; i >= 0; --i )
5055 {
5056 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5057 if( SCIPconsIsDeleted(consssorted[i]) )
5058 continue;
5059
5060 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5061 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5062 }
5063 for( i = 0; i < nconss; ++i )
5064 {
5065 if( SCIPconsIsDeleted(consssorted[i]) )
5066 continue;
5067
5068 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5069 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5070 }
5071
5072 SCIPfreeBufferArray(scip, &consssorted);
5073
5074 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5075 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5076 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5077 */
5078 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5079 }
5080
5081 /* restore locks */
5082 for( i = 0; i < nconss; ++i )
5083 {
5084 if( SCIPconsIsDeleted(conss[i]) )
5085 continue;
5086
5087 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5088 }
5089
5090 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5091 * TODO can we skip this in presoltiming fast?
5092 */
5093 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5094 {
5095 /* reset one of the number of detections counter to count only current presolving round */
5096 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5097 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5098
5099 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5100 }
5101
5102 /* free allocated memory */
5103 SCIPfreeBufferArray(scip, &nlocksneg);
5104 SCIPfreeBufferArray(scip, &nlockspos);
5105
5106 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5107
5108 return SCIP_OKAY;
5109}
5110
5111/** merges constraints that have the same root expression */
5112static
5114 SCIP* scip, /**< SCIP data structure */
5115 SCIP_CONS** conss, /**< constraints to process */
5116 int nconss, /**< number of constraints */
5117 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5118 )
5119{
5120 SCIP_HASHMAP* expr2cons;
5121 SCIP_Bool* updatelocks;
5122 int* nlockspos;
5123 int* nlocksneg;
5124 int c;
5125
5126 assert(success != NULL);
5127
5128 *success = FALSE;
5129
5130 /* not enough constraints available */
5131 if( nconss <= 1 )
5132 return SCIP_OKAY;
5133
5134 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5135 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5136 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5137 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5138
5139 for( c = 0; c < nconss; ++c )
5140 {
5141 SCIP_CONSDATA* consdata;
5142
5143 /* ignore deleted constraints */
5144 if( SCIPconsIsDeleted(conss[c]) )
5145 continue;
5146
5147 consdata = SCIPconsGetData(conss[c]);
5148 assert(consdata != NULL);
5149
5150 /* add expression to the hash map if not seen so far */
5151 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5152 {
5153 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5154 }
5155 else
5156 {
5157 SCIP_CONSDATA* imgconsdata;
5158 int idx;
5159
5160 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5161 assert(idx >= 0 && idx < nconss);
5162
5163 imgconsdata = SCIPconsGetData(conss[idx]);
5164 assert(imgconsdata != NULL);
5165 assert(imgconsdata->expr == consdata->expr);
5166
5167 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5168 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5169
5170 /* check whether locks need to be updated */
5171 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5172 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5173 {
5174 nlockspos[idx] = imgconsdata->nlockspos;
5175 nlocksneg[idx] = imgconsdata->nlocksneg;
5176 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5177 updatelocks[idx] = TRUE;
5178 }
5179
5180 /* update constraint sides */
5181 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5182 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5183
5184 /* delete constraint */
5185 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5186 *success = TRUE;
5187 }
5188 }
5189
5190 /* restore locks of updated constraints */
5191 if( *success )
5192 {
5193 for( c = 0; c < nconss; ++c )
5194 {
5195 if( updatelocks[c] )
5196 {
5197 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5198 }
5199 }
5200 }
5201
5202 /* free memory */
5203 SCIPfreeBufferArray(scip, &nlocksneg);
5204 SCIPfreeBufferArray(scip, &nlockspos);
5205 SCIPfreeBufferArray(scip, &updatelocks);
5206 SCIPhashmapFree(&expr2cons);
5207
5208 return SCIP_OKAY;
5209}
5210
5211/** interval evaluation of variables as used in redundancy check
5212 *
5213 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5214 */
5215static
5216SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5217{ /*lint --e{715}*/
5218 SCIP_CONSHDLRDATA* conshdlrdata;
5219 SCIP_INTERVAL interval;
5220 SCIP_Real lb;
5221 SCIP_Real ub;
5222
5223 assert(scip != NULL);
5224 assert(var != NULL);
5225
5226 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5227 assert(conshdlrdata != NULL);
5228
5229 if( conshdlrdata->globalbounds )
5230 {
5231 lb = SCIPvarGetLbGlobal(var);
5232 ub = SCIPvarGetUbGlobal(var);
5233 }
5234 else
5235 {
5236 lb = SCIPvarGetLbLocal(var);
5237 ub = SCIPvarGetUbLocal(var);
5238 }
5239 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5240
5241 /* relax variable bounds, if there are bounds and variable is not fixed
5242 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5243 */
5244 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5245 {
5246 if( !SCIPisInfinity(scip, -lb) )
5247 lb -= SCIPfeastol(scip);
5248
5249 if( !SCIPisInfinity(scip, ub) )
5250 ub += SCIPfeastol(scip);
5251 }
5252
5253 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5256 assert(lb <= ub);
5257
5258 SCIPintervalSetBounds(&interval, lb, ub);
5259
5260 return interval;
5261}
5262
5263/** removes constraints that are always feasible or very simple
5264 *
5265 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5266 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5267 * might violate variable bounds by up to feastol, too.
5268 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5269 *
5270 * Also removes constraints of the form lhs &le; variable &le; rhs.
5271 *
5272 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5273 *
5274 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5275 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5276 * would appear as if the constraint is redundant.
5277 */
5278static
5280 SCIP* scip, /**< SCIP data structure */
5281 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5282 SCIP_CONS** conss, /**< constraints to propagate */
5283 int nconss, /**< total number of constraints */
5284 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5285 int* ndelconss, /**< buffer to add the number of deleted constraints */
5286 int* nchgbds /**< buffer to add the number of variable bound tightenings */
5287 )
5288{
5289 SCIP_CONSHDLRDATA* conshdlrdata;
5290 SCIP_CONSDATA* consdata;
5291 SCIP_INTERVAL activity;
5292 SCIP_INTERVAL sides;
5293 int i;
5294
5295 assert(scip != NULL);
5296 assert(conshdlr != NULL);
5297 assert(conss != NULL);
5298 assert(nconss >= 0);
5299 assert(cutoff != NULL);
5300 assert(ndelconss != NULL);
5301 assert(nchgbds != NULL);
5302
5303 /* no constraints to check */
5304 if( nconss == 0 )
5305 return SCIP_OKAY;
5306
5307 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5308 assert(conshdlrdata != NULL);
5309
5310 /* increase curboundstag and set lastvaractivitymethodchange
5311 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5312 * for the redundancy check differently than for domain propagation
5313 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5314 */
5315 ++conshdlrdata->curboundstag;
5316 assert(conshdlrdata->curboundstag > 0);
5317 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5318 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5319 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5320
5321 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5322
5323 *cutoff = FALSE;
5324 for( i = 0; i < nconss; ++i )
5325 {
5326 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5327 continue;
5328
5329 consdata = SCIPconsGetData(conss[i]);
5330 assert(consdata != NULL);
5331
5332 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5333 if( SCIPisExprValue(scip, consdata->expr) )
5334 {
5335 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5336
5337 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5338 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5339 {
5340 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5341 *cutoff = TRUE;
5342
5343 goto TERMINATE;
5344 }
5345
5346 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5347
5348 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5349 ++*ndelconss;
5350
5351 continue;
5352 }
5353
5354 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5355 if( SCIPisExprVar(scip, consdata->expr) )
5356 {
5357 SCIP_VAR* var;
5358 SCIP_Bool tightened;
5359
5360 var = SCIPgetVarExprVar(consdata->expr);
5361 assert(var != NULL);
5362
5363 SCIPdebugMsg(scip, "variable constraint <%s> can be made redundant: <%s>[%g,%g] in [%g,%g]\n", SCIPconsGetName(conss[i]), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), consdata->lhs, consdata->rhs);
5364
5365 /* ensure that variable bounds are within constraint sides */
5366 if( !SCIPisInfinity(scip, -consdata->lhs) )
5367 {
5368 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5369
5370 if( tightened )
5371 ++*nchgbds;
5372
5373 if( *cutoff )
5374 goto TERMINATE;
5375 }
5376
5377 if( !SCIPisInfinity(scip, consdata->rhs) )
5378 {
5379 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5380
5381 if( tightened )
5382 ++*nchgbds;
5383
5384 if( *cutoff )
5385 goto TERMINATE;
5386 }
5387
5388 /* delete the (now) redundant constraint locally */
5389 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5390 ++*ndelconss;
5391
5392 continue;
5393 }
5394
5395 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5396 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5397 * variable bounds by up to feastol
5398 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5399 */
5400 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5401 SCIPdebugPrintCons(scip, conss[i], NULL);
5402
5403 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5404 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5405
5406 /* it is unlikely that we detect infeasibility by doing forward propagation */
5407 if( *cutoff )
5408 {
5409 SCIPdebugMsg(scip, " -> cutoff\n");
5410 goto TERMINATE;
5411 }
5412
5413 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5414 activity = SCIPexprGetActivity(consdata->expr);
5415
5416 /* relax sides by feastol
5417 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5418 */
5419 SCIPintervalSetBounds(&sides,
5420 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5421 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5422
5423 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5424 {
5425 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5426
5427 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5428 ++*ndelconss;
5429
5430 continue;
5431 }
5432
5433 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5434 }
5435
5436TERMINATE:
5437 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5438 ++conshdlrdata->curboundstag;
5439 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5440 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5441 conshdlrdata->intevalvar = intEvalVarBoundTightening;
5442
5443 return SCIP_OKAY;
5444}
5445
5446/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5447static
5449 SCIP* scip, /**< SCIP data structure */
5450 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5451 SCIP_CONS* cons, /**< source constraint to try to convert */
5452 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5453 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5454 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5455 )
5456{
5457 SCIP_CONSHDLRDATA* conshdlrdata;
5458 SCIP_CONSDATA* consdata;
5459 SCIP_CONS** upgdconss;
5460 int upgdconsssize;
5461 int nupgdconss_;
5462 int i;
5463
5464 assert(scip != NULL);
5465 assert(conshdlr != NULL);
5466 assert(cons != NULL);
5467 assert(!SCIPconsIsModifiable(cons));
5468 assert(upgraded != NULL);
5469 assert(nupgdconss != NULL);
5470 assert(naddconss != NULL);
5471
5472 *upgraded = FALSE;
5473
5474 nupgdconss_ = 0;
5475
5476 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5477 assert(conshdlrdata != NULL);
5478
5479 /* if there are no upgrade methods, we can stop */
5480 if( conshdlrdata->nconsupgrades == 0 )
5481 return SCIP_OKAY;
5482
5483 upgdconsssize = 2;
5484 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5485
5486 /* call the upgrading methods */
5487 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5489
5490 consdata = SCIPconsGetData(cons);
5491 assert(consdata != NULL);
5492
5493 /* try all upgrading methods in priority order in case the upgrading step is enable */
5494 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5495 {
5496 if( !conshdlrdata->consupgrades[i]->active )
5497 continue;
5498
5499 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5500
5501 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5502
5503 while( nupgdconss_ < 0 )
5504 {
5505 /* upgrade function requires more memory: resize upgdconss and call again */
5506 assert(-nupgdconss_ > upgdconsssize);
5507 upgdconsssize = -nupgdconss_;
5508 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5509
5510 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5511
5512 assert(nupgdconss_ != 0);
5513 }
5514
5515 if( nupgdconss_ > 0 )
5516 {
5517 /* got upgrade */
5518 int j;
5519
5520 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5521
5522 /* add the upgraded constraints to the problem and forget them */
5523 for( j = 0; j < nupgdconss_; ++j )
5524 {
5525 SCIPdebugMsgPrint(scip, "\t");
5526 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5527
5528 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5529 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5530 }
5531
5532 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5533 *nupgdconss += 1;
5534 *naddconss += nupgdconss_ - 1;
5535 *upgraded = TRUE;
5536
5537 /* delete upgraded constraint */
5538 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5539 SCIP_CALL( SCIPdelCons(scip, cons) );
5540
5541 break;
5542 }
5543 }
5544
5545 SCIPfreeBufferArray(scip, &upgdconss);
5546
5547 return SCIP_OKAY;
5548}
5549
5550/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5551 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5552 * variable bounds, and is not binary
5553 */
5554static
5556 SCIP* scip, /**< SCIP data structure */
5557 SCIP_EXPR* expr /**< variable expression */
5558 )
5559{
5560 SCIP_VAR* var;
5561 SCIP_EXPR_OWNERDATA* ownerdata;
5562
5563 assert(SCIPisExprVar(scip, expr));
5564
5565 var = SCIPgetVarExprVar(expr);
5566 assert(var != NULL);
5567
5568 ownerdata = SCIPexprGetOwnerData(expr);
5569 assert(ownerdata != NULL);
5570
5571 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5572 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5573 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5577}
5578
5579/** removes all variable expressions that are contained in a given expression from a hash map */
5580static
5582 SCIP* scip, /**< SCIP data structure */
5583 SCIP_EXPR* expr, /**< expression */
5584 SCIP_EXPRITER* it, /**< expression iterator */
5585 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5586 )
5587{
5588 SCIP_EXPR* e;
5589
5590 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5591 {
5592 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5593 {
5594 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5595 }
5596 }
5597
5598 return SCIP_OKAY;
5599}
5600
5601/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5602 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5603 *
5604 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5605 * Otherwise, a bound disjunction constraint is added.
5606 *
5607 * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) &le; rhs (done in prop_dualfix?)
5608 */
5609static
5611 SCIP* scip, /**< SCIP data structure */
5612 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5613 SCIP_CONS* cons, /**< nonlinear constraint */
5614 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5615 int* naddconss, /**< pointer to store the total number of added constraints */
5616 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5617 )
5618{
5619 SCIP_CONSHDLRDATA* conshdlrdata;
5620 SCIP_CONSDATA* consdata;
5621 SCIP_EXPR** singlelocked;
5622 SCIP_HASHMAP* exprcands;
5623 SCIP_Bool hasbounddisj;
5624 SCIP_Bool haslhs;
5625 SCIP_Bool hasrhs;
5626 int nsinglelocked = 0;
5627 int i;
5628
5629 assert(conshdlr != NULL);
5630 assert(cons != NULL);
5631 assert(nchgvartypes != NULL);
5632 assert(naddconss != NULL);
5633 assert(infeasible != NULL);
5634
5635 *nchgvartypes = 0;
5636 *naddconss = 0;
5637 *infeasible = FALSE;
5638
5639 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5640 assert(conshdlrdata != NULL);
5641 consdata = SCIPconsGetData(cons);
5642 assert(consdata != NULL);
5643
5644 /* only consider constraints with one finite side */
5645 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5646 return SCIP_OKAY;
5647
5648 /* only consider sum expressions */
5649 if( !SCIPisExprSum(scip, consdata->expr) )
5650 return SCIP_OKAY;
5651
5652 /* remember which side is finite */
5653 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5654 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5655
5656 /* allocate memory */
5657 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5658 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5659
5660 /* check all variable expressions for single locked variables */
5661 for( i = 0; i < consdata->nvarexprs; ++i )
5662 {
5663 assert(consdata->varexprs[i] != NULL);
5664
5665 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5666 {
5667 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5668 singlelocked[nsinglelocked++] = consdata->varexprs[i];
5669 }
5670 }
5671 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5672
5673 if( nsinglelocked > 0 )
5674 {
5675 SCIP_EXPR** children;
5676 SCIP_EXPRITER* it;
5677 int nchildren;
5678
5679 children = SCIPexprGetChildren(consdata->expr);
5680 nchildren = SCIPexprGetNChildren(consdata->expr);
5681
5682 /* create iterator */
5686
5687 for( i = 0; i < nchildren; ++i )
5688 {
5689 SCIP_EXPR* child;
5690 SCIP_Real coef;
5691
5692 child = children[i];
5693 assert(child != NULL);
5694 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5695
5696 /* ignore linear terms */
5697 if( SCIPisExprVar(scip, child) )
5698 continue;
5699
5700 /* consider products coef * prod_j f_j(x)
5701 * - if f_j(x) is a single variable, ignore it
5702 * - if f_j(x) = x^(2k), then keep it if product is concave when fixing all other factor;
5703 * since x^(2k) >= 0, it suffices to check that the activity of the whole product is non-negative if haslhs or non-positive if hasrhs
5704 * - remove all other variable expressions from exprcand
5705 */
5706 if( SCIPisExprProduct(scip, child) )
5707 {
5708 int j;
5709 SCIP_INTERVAL productactivity;
5710 SCIP_Bool keepevenpower;
5711
5712 /* activity has been ensured to be uptodate (or at least still valid) by
5713 * call to SCIPregisterExprUsageNonlinear() in detectNlhdlrs() in canonicalize
5714 */
5715 productactivity = SCIPexprGetActivity(child);
5716
5717 /* check whether variables in even-powered factor terms can be restricted to bounds (as in SCIPisExprPower() below) */
5718 keepevenpower = (haslhs && productactivity.inf >= 0.0) || (hasrhs && productactivity.sup <= 0.0);
5719
5720 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5721 {
5722 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5723 assert(grandchild != NULL);
5724
5725 /* if grandchild is x^(2k), then do not remove x from exprcands */
5726 if( keepevenpower && SCIPisExprPower(scip, grandchild) && SCIPisExprVar(scip, SCIPexprGetChildren(grandchild)[0]) )
5727 {
5728 SCIP_Real exponent = SCIPgetExponentExprPow(grandchild);
5729
5730 if( exponent > 1.0 && fmod(exponent, 2.0) == 0.0 )
5731 continue;
5732 }
5733
5734 if( !SCIPisExprVar(scip, grandchild) )
5735 {
5736 /* mark all variable expressions that are contained in the expression */
5737 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5738 }
5739 }
5740 }
5741 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5742 * for an integer k >= 1
5743 */
5744 else if( SCIPisExprPower(scip, child) )
5745 {
5746 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5747 SCIP_Real exponent = SCIPgetExponentExprPow(child);
5748 SCIP_Bool valid;
5749
5750 /* check for even integral exponent */
5751 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5752
5753 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5754 {
5755 /* mark all variable expressions that are contained in the expression */
5756 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5757 }
5758 }
5759 /* all other cases cannot be handled */
5760 else
5761 {
5762 /* mark all variable expressions that are contained in the expression */
5763 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5764 }
5765 }
5766
5767 /* free expression iterator */
5768 SCIPfreeExpriter(&it);
5769 }
5770
5771 /* check whether the bound disjunction constraint handler is available */
5772 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5773
5774 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5775 for( i = 0; i < nsinglelocked; ++i )
5776 {
5777 /* only consider expressions that are still contained in the exprcands map */
5778 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5779 {
5780 SCIP_CONS* newcons;
5781 SCIP_VAR* vars[2];
5782 SCIP_BOUNDTYPE boundtypes[2];
5783 SCIP_Real bounds[2];
5784 char name[SCIP_MAXSTRLEN];
5785 SCIP_VAR* var;
5786
5787 var = SCIPgetVarExprVar(singlelocked[i]);
5788 assert(var != NULL);
5789 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5791
5792 /* try to change the variable type to binary */
5793 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5794 {
5796 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5797 ++(*nchgvartypes);
5798
5799 if( *infeasible )
5800 {
5801 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5802 break;
5803 }
5804 }
5805 /* add bound disjunction constraint if bounds of the variable are finite */
5806 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5807 {
5808 vars[0] = var;
5809 vars[1] = var;
5810 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5811 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5812 bounds[0] = SCIPvarGetUbGlobal(var);
5813 bounds[1] = SCIPvarGetLbGlobal(var);
5814
5815 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5816
5817 /* create, add, and release bound disjunction constraint */
5818 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5819 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5821 SCIP_CALL( SCIPaddCons(scip, newcons) );
5822 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5823 ++(*naddconss);
5824 }
5825 }
5826 }
5827
5828 /* free memory */
5829 SCIPfreeBufferArray(scip, &singlelocked);
5830 SCIPhashmapFree(&exprcands);
5831
5832 return SCIP_OKAY;
5833}
5834
5835/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5836static
5838 SCIP* scip, /**< SCIP data structure */
5839 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5840 SCIP_CONS** conss, /**< nonlinear constraints */
5841 int nconss, /**< total number of nonlinear constraints */
5842 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5843 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5844 )
5845{
5846 int c;
5847
5848 assert(scip != NULL);
5849 assert(conshdlr != NULL);
5850 assert(conss != NULL || nconss == 0);
5851 assert(nchgvartypes != NULL);
5852 assert(infeasible != NULL);
5853
5854 *infeasible = FALSE;
5855
5856 /* nothing can be done on purley continuous problem */
5858 return SCIP_OKAY;
5859
5860 /* no continuous var can be made implicit-integer if there are no continuous variables */
5861 if( SCIPgetNContVars(scip) == 0 )
5862 return SCIP_OKAY;
5863
5864 for( c = 0; c < nconss; ++c )
5865 {
5866 SCIP_CONSDATA* consdata;
5867 SCIP_EXPR** children;
5868 int nchildren;
5869 SCIP_Real* coefs;
5870 SCIP_EXPR* cand = NULL;
5871 SCIP_Real candcoef = 0.0;
5872 int i;
5873 SCIP_IMPLINTTYPE impltype;
5874
5875 assert(conss != NULL && conss[c] != NULL);
5876
5877 consdata = SCIPconsGetData(conss[c]);
5878 assert(consdata != NULL);
5879
5880 /* the constraint must be an equality constraint */
5881 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5882 continue;
5883
5884 /* the root expression needs to be a sum expression */
5885 if( !SCIPisExprSum(scip, consdata->expr) )
5886 continue;
5887
5888 children = SCIPexprGetChildren(consdata->expr);
5889 nchildren = SCIPexprGetNChildren(consdata->expr);
5890
5891 /* the sum expression must have at least two children
5892 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5893 */
5894 if( nchildren <= 1 )
5895 continue;
5896
5897 coefs = SCIPgetCoefsExprSum(consdata->expr);
5898
5899 /* find first continuous variable and get value of its coefficient */
5900 for( i = 0; i < nchildren; ++i )
5901 {
5902 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5903 continue;
5904
5905 candcoef = coefs[i];
5906 assert(candcoef != 0.0);
5907
5908 /* lhs/rhs - constant divided by candcoef must be integral
5909 * if not, break with cand == NULL, so give up
5910 */
5911 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5912 cand = children[i];
5913
5914 break;
5915 }
5916
5917 /* no suitable continuous variable found */
5918 if( cand == NULL )
5919 continue;
5920
5921 impltype = SCIP_IMPLINTTYPE_STRONG;
5922
5923 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5924 for( i = 0; i < nchildren; ++i )
5925 {
5926 if( children[i] == cand )
5927 continue;
5928
5929 impltype = MIN(impltype, SCIPexprGetIntegrality(children[i]));
5930 /* child i must be integral */
5931 if( impltype == SCIP_IMPLINTTYPE_NONE )
5932 {
5933 cand = NULL;
5934 break;
5935 }
5936
5937 /* coefficient of child i must be integral if diving by candcoef */
5938 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5939 {
5940 cand = NULL;
5941 break;
5942 }
5943 }
5944
5945 if( cand == NULL )
5946 continue;
5947
5948 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5950
5951 /* change variable type */
5952 assert(impltype != SCIP_IMPLINTTYPE_NONE);
5953
5954 SCIP_CALL( SCIPchgVarImplType(scip, SCIPgetVarExprVar(cand), impltype, infeasible) );
5955 ++(*nchgvartypes);
5956
5957 if( *infeasible )
5958 return SCIP_OKAY;
5959
5960 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5961 SCIPexprSetIntegrality(cand, impltype);
5962 }
5963
5964 return SCIP_OKAY;
5965}
5966
5967/** creates auxiliary variable for a given expression
5968 *
5969 * @note for a variable expression it does nothing
5970 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5971 */
5972static
5974 SCIP* scip, /**< SCIP data structure */
5975 SCIP_EXPR* expr /**< expression */
5976 )
5977{
5978 SCIP_EXPR_OWNERDATA* ownerdata;
5979 SCIP_CONSHDLRDATA* conshdlrdata;
5980 SCIP_IMPLINTTYPE impltype;
5981 SCIP_INTERVAL activity;
5982 char name[SCIP_MAXSTRLEN];
5983
5984 assert(scip != NULL);
5985 assert(expr != NULL);
5986
5987 ownerdata = SCIPexprGetOwnerData(expr);
5988 assert(ownerdata != NULL);
5989 assert(ownerdata->nauxvaruses > 0);
5990
5991 /* if we already have auxvar, then do nothing */
5992 if( ownerdata->auxvar != NULL )
5993 return SCIP_OKAY;
5994
5995 /* if expression is a variable-expression, then do nothing */
5996 if( SCIPisExprVar(scip, expr) )
5997 return SCIP_OKAY;
5998
6000 {
6001 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6002 return SCIP_INVALIDCALL;
6003 }
6004
6005 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6006 assert(conshdlrdata != NULL);
6007 assert(conshdlrdata->auxvarid >= 0);
6008
6009 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6010 * but it usually indicates a missing simplify
6011 * if we find situations where we need to have an auxvar for a constant, then remove this assert
6012 */
6013 assert(!SCIPisExprValue(scip, expr));
6014
6015 /* create and capture auxiliary variable */
6016 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6017 ++conshdlrdata->auxvarid;
6018
6019 /* type of auxiliary variable depends on integrality information of the expression */
6020 impltype = SCIPexprGetIntegrality(expr);
6021
6022 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6023 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6024 {
6025 activity = SCIPexprGetActivity(expr);
6026 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6027 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6028 * and abort in debug mode only
6029 */
6031 {
6032 SCIPABORT();
6034 }
6035 }
6036 else
6038
6039 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6040 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6041 */
6042 if( SCIPgetDepth(scip) == 0 )
6043 {
6044 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name,
6045 MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0,
6046 SCIP_VARTYPE_CONTINUOUS, impltype,
6047 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6048 }
6049 else
6050 {
6051 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
6052 SCIP_VARTYPE_CONTINUOUS, impltype,
6053 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
6054 }
6055
6056 /* mark the auxiliary variable to be added for the relaxation only
6057 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6058 * or to copy the variable to a subscip
6059 */
6060 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6061
6062 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6063
6064 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6065
6066 /* add variable locks in both directions
6067 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6068 * but then we need to also update the auxvars locks when the expr locks change
6069 */
6070 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6071
6072#ifdef WITH_DEBUG_SOLUTION
6073 if( SCIPdebugIsMainscip(scip) )
6074 {
6075 /* store debug solution value of auxiliary variable
6076 * assumes that expression has been evaluated in debug solution before
6077 */
6078 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6079 }
6080#endif
6081
6082 if( SCIPgetDepth(scip) > 0 )
6083 {
6084 /* initialize local bounds to (locally valid) activity */
6085 SCIP_Bool cutoff;
6086 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6087 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6088 }
6089
6090 return SCIP_OKAY;
6091}
6092
6093/** initializes separation for constraint
6094 *
6095 * - ensures that activities are up to date in all expressions
6096 * - creates auxiliary variables where required
6097 * - calls propExprDomains() to possibly tighten auxvar bounds
6098 * - calls separation initialization callback of nlhdlrs
6099 */
6100static
6102 SCIP* scip, /**< SCIP data structure */
6103 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6104 SCIP_CONS** conss, /**< constraints */
6105 int nconss, /**< number of constraints */
6106 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6107 )
6108{
6109 SCIP_CONSDATA* consdata;
6110 SCIP_CONSHDLRDATA* conshdlrdata;
6111 SCIP_EXPRITER* it;
6112 SCIP_EXPR* expr;
6113 SCIP_RESULT result;
6114 SCIP_VAR* auxvar;
6115 int nreductions = 0;
6116 int c, e;
6117
6118 assert(scip != NULL);
6119 assert(conshdlr != NULL);
6120 assert(conss != NULL || nconss == 0);
6121 assert(nconss >= 0);
6122 assert(infeasible != NULL);
6123
6124 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6125 assert(conshdlrdata != NULL);
6126
6127 /* start with new propbounds (just to be sure, should not be needed) */
6128 ++conshdlrdata->curpropboundstag;
6129
6132
6133 /* first ensure activities are up to date and create auxvars */
6134 *infeasible = FALSE;
6135 for( c = 0; c < nconss; ++c )
6136 {
6137 assert(conss != NULL);
6138 assert(conss[c] != NULL);
6139
6140 consdata = SCIPconsGetData(conss[c]);
6141 assert(consdata != NULL);
6142 assert(consdata->expr != NULL);
6143
6144#ifdef WITH_DEBUG_SOLUTION
6145 if( SCIPdebugIsMainscip(scip) )
6146 {
6147 SCIP_SOL* debugsol;
6148
6149 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6150
6151 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6152 {
6153 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6154 * in createAuxVar()
6155 */
6156 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6157 }
6158 }
6159#endif
6160
6161 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6162 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6163
6164 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6165 {
6166 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6167 {
6168 SCIP_CALL( createAuxVar(scip, expr) );
6169 }
6170 }
6171
6172 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6173 if( auxvar != NULL )
6174 {
6175 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6176 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6177 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6178 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6179 if( *infeasible )
6180 {
6181 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6182 break;
6183 }
6184
6185 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6186 if( *infeasible )
6187 {
6188 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6189 break;
6190 }
6191 }
6192 }
6193
6194 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6195 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6196 * (e.g., log(x*y), which becomes log(w), w=x*y
6197 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6198 */
6199 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6200 if( result == SCIP_CUTOFF )
6201 *infeasible = TRUE;
6202
6203 /* now call initsepa of nlhdlrs
6204 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6205 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6206 */
6208 for( c = 0; c < nconss && !*infeasible; ++c )
6209 {
6210 assert(conss != NULL);
6211 assert(conss[c] != NULL);
6212
6213 consdata = SCIPconsGetData(conss[c]);
6214 assert(consdata != NULL);
6215 assert(consdata->expr != NULL);
6216
6217 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6218 {
6219 SCIP_EXPR_OWNERDATA* ownerdata;
6220
6221 ownerdata = SCIPexprGetOwnerData(expr);
6222 assert(ownerdata != NULL);
6223
6224 if( ownerdata->nauxvaruses == 0 )
6225 continue;
6226
6227 for( e = 0; e < ownerdata->nenfos; ++e )
6228 {
6229 SCIP_NLHDLR* nlhdlr;
6230 SCIP_Bool underestimate;
6231 SCIP_Bool overestimate;
6232 assert(ownerdata->enfos[e] != NULL);
6233
6234 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6235 * which participated in a previous initSepa() call
6236 */
6237 if( ownerdata->enfos[e]->issepainit )
6238 continue;
6239
6240 /* only call initsepa if it will actually separate */
6241 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6242 continue;
6243
6244 nlhdlr = ownerdata->enfos[e]->nlhdlr;
6245 assert(nlhdlr != NULL);
6246
6247 /* only init sepa if there is an initsepa callback */
6248 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6249 continue;
6250
6251 /* check whether expression needs to be under- or overestimated */
6252 overestimate = ownerdata->nlocksneg > 0;
6253 underestimate = ownerdata->nlockspos > 0;
6254 assert(underestimate || overestimate);
6255
6256 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6257
6258 /* call the separation initialization callback of the nonlinear handler */
6259 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6260 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6261 ownerdata->enfos[e]->issepainit = TRUE;
6262
6263 if( *infeasible )
6264 {
6265 /* stop everything if we detected infeasibility */
6266 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6267 break;
6268 }
6269 }
6270 }
6271 }
6272
6273 SCIPfreeExpriter(&it);
6274
6275 return SCIP_OKAY;
6276}
6277
6278/** returns whether we are ok to branch on auxiliary variables
6279 *
6280 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6281 */
6282static
6284 SCIP* scip, /**< SCIP data structure */
6285 SCIP_CONSHDLR* conshdlr /**< constraint handler */
6286 )
6287{
6288 SCIP_CONSHDLRDATA* conshdlrdata;
6289
6290 assert(conshdlr != NULL);
6291
6292 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6293 assert(conshdlrdata != NULL);
6294
6295 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6296}
6297
6298/** gets weight of variable when splitting violation score onto several variables in an expression */
6299static
6301 SCIP* scip, /**< SCIP data structure */
6302 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6303 SCIP_VAR* var, /**< variable */
6304 SCIP_SOL* sol /**< current solution */
6305 )
6306{
6307 SCIP_CONSHDLRDATA* conshdlrdata;
6308
6309 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6310 assert(conshdlrdata != NULL);
6311
6312 switch( conshdlrdata->branchviolsplit )
6313 {
6314 case 'u' : /* uniform: everyone gets the same score */
6315 return 1.0;
6316
6317 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6318 {
6319 SCIP_Real weight;
6320 weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6321 return MAX(0.05, weight);
6322 }
6323
6324 case 'd' : /* domain width */
6325 return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6326
6327 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6328 {
6329 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6330 assert(width > 0.0);
6331 if( width > 10.0 )
6332 return 10.0*log10(width);
6333 if( width < 0.1 )
6334 return 0.1/(-log10(width));
6335 return width;
6336 }
6337
6338 default :
6339 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6340 SCIPABORT();
6341 return SCIP_INVALID;
6342 }
6343}
6344
6345/** adds violation-branching score to a set of expressions, thereby distributing the score
6346 *
6347 * Each expression must either be a variable expression or have an aux-variable.
6348 *
6349 * If unbounded variables are present, each unbounded var gets an even score.
6350 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6351 */
6352static
6354 SCIP* scip, /**< SCIP data structure */
6355 SCIP_EXPR** exprs, /**< expressions where to add branching score */
6356 int nexprs, /**< number of expressions */
6357 SCIP_Real violscore, /**< violation-branching score to add to expression */
6358 SCIP_SOL* sol, /**< current solution */
6359 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6360 )
6361{
6362 SCIP_CONSHDLR* conshdlr;
6363 SCIP_VAR* var;
6364 SCIP_Real weight;
6365 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6366 int nunbounded = 0; /* number of candidates with unbounded domain */
6367 int i;
6368
6369 assert(exprs != NULL);
6370 assert(nexprs >= 0);
6371 assert(success != NULL);
6372
6373 if( nexprs == 1 )
6374 {
6375 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6376 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6378 *success = TRUE;
6379 return;
6380 }
6381
6382 if( nexprs == 0 )
6383 {
6384 *success = FALSE;
6385 return;
6386 }
6387
6388 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6389
6390 for( i = 0; i < nexprs; ++i )
6391 {
6392 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6393 assert(var != NULL);
6394
6396 ++nunbounded;
6397 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6398 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6399 }
6400
6401 *success = FALSE;
6402 for( i = 0; i < nexprs; ++i )
6403 {
6404 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6405 assert(var != NULL);
6406
6407 if( nunbounded > 0 )
6408 {
6410 {
6411 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6412 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6413 100.0/nunbounded, violscore,
6415 *success = TRUE;
6416 }
6417 }
6418 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6419 {
6420 assert(weightsum > 0.0);
6421
6422 weight = getViolSplitWeight(scip, conshdlr, var, sol);
6423 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6424 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6425 100*weight / weightsum, violscore,
6427 *success = TRUE;
6428 }
6429 else
6430 {
6431 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6433 }
6434 }
6435}
6436
6437/** adds violation-branching score to children of expression for given auxiliary variables
6438 *
6439 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6440 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6441 *
6442 * @note This method may modify the given auxvars array by means of sorting.
6443 */
6444static
6446 SCIP* scip, /**< SCIP data structure */
6447 SCIP_EXPR* expr, /**< expression where to start searching */
6448 SCIP_Real violscore, /**< violation score to add to expression */
6449 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6450 int nauxvars, /**< number of auxiliary variables */
6451 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6452 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6453 )
6454{
6455 SCIP_EXPRITER* it;
6456 SCIP_VAR* auxvar;
6457 SCIP_EXPR** exprs;
6458 int nexprs;
6459 int pos;
6460
6461 assert(scip != NULL);
6462 assert(expr != NULL);
6463 assert(auxvars != NULL);
6464 assert(success != NULL);
6465
6466 /* sort variables to make lookup below faster */
6467 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6468
6471
6472 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6473 nexprs = 0;
6474
6475 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6476 {
6477 auxvar = SCIPgetExprAuxVarNonlinear(expr);
6478 if( auxvar == NULL )
6479 continue;
6480
6481 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6482 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6483 {
6484 assert(auxvars[pos] == auxvar);
6485
6486 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6487 exprs[nexprs++] = expr;
6488
6489 if( nexprs == nauxvars )
6490 break;
6491 }
6492 }
6493
6494 SCIPfreeExpriter(&it);
6495
6496 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6497
6498 SCIPfreeBufferArray(scip, &exprs);
6499
6500 return SCIP_OKAY;
6501}
6502
6503/** registers all unfixed variables in violated constraints as branching candidates */
6504static
6506 SCIP* scip, /**< SCIP data structure */
6507 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6508 SCIP_CONS** conss, /**< constraints */
6509 int nconss, /**< number of constraints */
6510 int* nnotify /**< counter for number of notifications performed */
6511 )
6512{
6513 SCIP_CONSDATA* consdata;
6514 SCIP_VAR* var;
6515 int c;
6516 int i;
6517
6518 assert(conshdlr != NULL);
6519 assert(conss != NULL || nconss == 0);
6520 assert(nnotify != NULL);
6521
6522 *nnotify = 0;
6523
6524 for( c = 0; c < nconss; ++c )
6525 {
6526 assert(conss != NULL && conss[c] != NULL);
6527
6528 consdata = SCIPconsGetData(conss[c]);
6529 assert(consdata != NULL);
6530
6531 /* consider only violated constraints */
6532 if( !isConsViolated(scip, conss[c]) )
6533 continue;
6534
6535 /* register all variables that have not been fixed yet */
6536 assert(consdata->varexprs != NULL);
6537 for( i = 0; i < consdata->nvarexprs; ++i )
6538 {
6539 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6540 assert(var != NULL);
6541
6543 {
6545 ++(*nnotify);
6546 }
6547 }
6548 }
6549
6550 return SCIP_OKAY;
6551}
6552
6553/** registers all variables in violated constraints with branching scores as external branching candidates */
6554static
6556 SCIP* scip, /**< SCIP data structure */
6557 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6558 SCIP_CONS** conss, /**< constraints */
6559 int nconss, /**< number of constraints */
6560 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6561 )
6562{
6563 SCIP_CONSDATA* consdata;
6564 SCIP_EXPRITER* it = NULL;
6565 int c;
6566
6567 assert(conshdlr != NULL);
6568 assert(success != NULL);
6569
6570 *success = FALSE;
6571
6572 if( branchAuxNonlinear(scip, conshdlr) )
6573 {
6576 }
6577
6578 /* register external branching candidates */
6579 for( c = 0; c < nconss; ++c )
6580 {
6581 assert(conss != NULL && conss[c] != NULL);
6582
6583 consdata = SCIPconsGetData(conss[c]);
6584 assert(consdata != NULL);
6585 assert(consdata->varexprs != NULL);
6586
6587 /* consider only violated constraints */
6588 if( !isConsViolated(scip, conss[c]) )
6589 continue;
6590
6591 if( !branchAuxNonlinear(scip, conshdlr) )
6592 {
6593 int i;
6594
6595 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6596 * only, so we can loop over variable expressions
6597 */
6598 for( i = 0; i < consdata->nvarexprs; ++i )
6599 {
6600 SCIP_Real violscore;
6601 SCIP_Real lb;
6602 SCIP_Real ub;
6603 SCIP_VAR* var;
6604
6605 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6606
6607 /* skip variable expressions that do not have a violation score */
6608 if( violscore == 0.0 )
6609 continue;
6610
6611 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6612 assert(var != NULL);
6613
6614 lb = SCIPvarGetLbLocal(var);
6615 ub = SCIPvarGetUbLocal(var);
6616
6617 /* consider variable for branching if it has not been fixed yet */
6618 if( !SCIPisEQ(scip, lb, ub) )
6619 {
6620 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6622 *success = TRUE;
6623 }
6624 else
6625 {
6626 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6627 }
6628
6629 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6630 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6631 */
6632 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6633 }
6634 }
6635 else
6636 {
6637 SCIP_EXPR* expr;
6638 SCIP_VAR* var;
6639 SCIP_Real lb;
6640 SCIP_Real ub;
6641 SCIP_Real violscore;
6642
6643 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6644 {
6645 violscore = SCIPgetExprViolScoreNonlinear(expr);
6646 if( violscore == 0.0 )
6647 continue;
6648
6649 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6650 * variable, so this expression should either be an original variable or have an auxiliary variable
6651 */
6652 var = SCIPgetExprAuxVarNonlinear(expr);
6653 assert(var != NULL);
6654
6655 lb = SCIPvarGetLbLocal(var);
6656 ub = SCIPvarGetUbLocal(var);
6657
6658 /* consider variable for branching if it has not been fixed yet */
6659 if( !SCIPisEQ(scip, lb, ub) )
6660 {
6661 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6662
6664 *success = TRUE;
6665 }
6666 else
6667 {
6668 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6669 }
6670 }
6671 }
6672 }
6673
6674 if( it != NULL )
6675 SCIPfreeExpriter(&it);
6676
6677 return SCIP_OKAY;
6678}
6679
6680/** collect branching candidates from violated constraints
6681 *
6682 * Fills array with expressions that serve as branching candidates.
6683 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6684 * branching candidate.
6685 *
6686 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6687 * through variable-expressions only.
6688 */
6689static
6691 SCIP* scip, /**< SCIP data structure */
6692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6693 SCIP_CONS** conss, /**< constraints to process */
6694 int nconss, /**< number of constraints */
6695 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6696 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6697 SCIP_Longint soltag, /**< tag of solution */
6698 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6699 int* ncands /**< number of candidates found */
6700 )
6701{
6702 SCIP_CONSHDLRDATA* conshdlrdata;
6703 SCIP_CONSDATA* consdata;
6704 SCIP_EXPRITER* it = NULL;
6705 int c;
6706 int attempt;
6707 SCIP_VAR* var;
6708
6709 assert(scip != NULL);
6710 assert(conshdlr != NULL);
6711 assert(cands != NULL);
6712 assert(ncands != NULL);
6713
6714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6715 assert(conshdlrdata != NULL);
6716
6717 if( branchAuxNonlinear(scip, conshdlr) )
6718 {
6721 }
6722
6723 *ncands = 0;
6724 for( attempt = 0; attempt < 2; ++attempt )
6725 {
6726 /* collect branching candidates from violated constraints
6727 * in the first attempt, consider only constraints with large violation
6728 * in the second attempt, consider all remaining violated constraints
6729 */
6730 for( c = 0; c < nconss; ++c )
6731 {
6732 SCIP_Real consviol;
6733
6734 assert(conss != NULL && conss[c] != NULL);
6735
6736 /* consider only violated constraints */
6737 if( !isConsViolated(scip, conss[c]) )
6738 continue;
6739
6740 consdata = SCIPconsGetData(conss[c]);
6741 assert(consdata != NULL);
6742 assert(consdata->varexprs != NULL);
6743
6744 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6745
6746 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6747 continue;
6748 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6749 continue;
6750
6751 if( !branchAuxNonlinear(scip, conshdlr) )
6752 {
6753 int i;
6754
6755 /* if not branching on auxvars, then violation-branching scores will be available for original variables
6756 * only, so we can loop over variable expressions
6757 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6758 * variable, therefore we invalidate the score of a variable after processing it.
6759 */
6760 for( i = 0; i < consdata->nvarexprs; ++i )
6761 {
6762 SCIP_Real lb;
6763 SCIP_Real ub;
6764
6765 /* skip variable expressions that do not have a valid violation score */
6766 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6767 continue;
6768
6769 var = SCIPgetVarExprVar(consdata->varexprs[i]);
6770 assert(var != NULL);
6771
6772 lb = SCIPvarGetLbLocal(var);
6773 ub = SCIPvarGetUbLocal(var);
6774
6775 /* skip already fixed variable */
6776 if( SCIPisEQ(scip, lb, ub) )
6777 {
6778 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6779 continue;
6780 }
6781
6782 assert(*ncands + 1 < SCIPgetNVars(scip));
6783 cands[*ncands].expr = consdata->varexprs[i];
6784 cands[*ncands].var = var;
6785 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6786 cands[*ncands].fractionality = 0.0;
6787 ++(*ncands);
6788
6789 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6790 * several times as external branching candidate */
6791 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6792 }
6793 }
6794 else
6795 {
6796 SCIP_EXPR* expr;
6797 SCIP_Real lb;
6798 SCIP_Real ub;
6799
6800 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6801 {
6802 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6803 continue;
6804
6805 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6806 * variables, so this expression should either be an original variable or have an auxiliary variable
6807 */
6808 var = SCIPgetExprAuxVarNonlinear(expr);
6809 assert(var != NULL);
6810
6811 lb = SCIPvarGetLbLocal(var);
6812 ub = SCIPvarGetUbLocal(var);
6813
6814 /* skip already fixed variable */
6815 if( SCIPisEQ(scip, lb, ub) )
6816 {
6817 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6818 continue;
6819 }
6820
6821 assert(*ncands + 1 < SCIPgetNVars(scip));
6822 cands[*ncands].expr = expr;
6823 cands[*ncands].var = var;
6824 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6825 cands[*ncands].fractionality = 0.0;
6826 ++(*ncands);
6827 }
6828 }
6829 }
6830
6831 /* if we have branching candidates, then we don't need another attempt */
6832 if( *ncands > 0 )
6833 break;
6834 }
6835
6836 if( it != NULL )
6837 SCIPfreeExpriter(&it);
6838
6839 return SCIP_OKAY;
6840}
6841
6842/** computes a branching score for a variable that reflects how important branching on this variable would be for
6843 * improving the dual bound from the LP relaxation
6844 *
6845 * Assume the Lagrangian for the current LP is something of the form
6846 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6847 * where x are the original variables, z the auxiliary variables,
6848 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6849 *
6850 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6851 * If we could have used not only an estimator, but the actual function f(x), then this would
6852 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6853 * Using a lot of handwaving, we claim that
6854 * lambda_i * (f(x) - a_i'x + b_i)
6855 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6856 * If an estimator depended on local bounds, then it could be improved by branching.
6857 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6858 *
6859 * To score a variable, we then sum the values lambda_i * (f(x) - a_i'x + b_i) for all rows in which the variable appears.
6860 * To scale, we divide by the LP objective value (if >1).
6861 *
6862 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6863 * these are affected by the bounds on original variables indirectly (through forward-propagation)
6864 *
6865 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6866 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6867 * would also be branching candidates
6868 */
6869static
6871 SCIP* scip, /**< SCIP data structure */
6872 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6873 SCIP_VAR* var /**< variable */
6874 )
6875{
6876 SCIP_COL* col;
6877 SCIP_ROW** rows;
6878 int nrows;
6879 int r;
6880 SCIP_Real dualscore;
6881
6882 assert(scip != NULL);
6883 assert(conshdlr != NULL);
6884 assert(var != NULL);
6885
6886 /* if LP not solved, then the dual branching score is not available */
6888 return 0.0;
6889
6890 /* if var is not in the LP, then the dual branching score is not available */
6892 return 0.0;
6893
6894 col = SCIPvarGetCol(var);
6895 assert(col != NULL);
6896
6897 if( !SCIPcolIsInLP(col) )
6898 return 0.0;
6899
6900 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6901 rows = SCIPcolGetRows(col);
6902
6903 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6904
6905 /* aggregate duals from all rows from consexpr with non-zero dual
6906 * TODO: this is a quick-and-dirty implementation, and not used by default
6907 * in the long run, this should be either removed or replaced by a proper implementation
6908 */
6909 dualscore = 0.0;
6910 for( r = 0; r < nrows; ++r )
6911 {
6912 SCIP_Real estimategap;
6913 const char* estimategapstr;
6914
6915 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6916 * these would typically be local, unless they are created at the root node
6917 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6918 if( !SCIProwIsLocal(rows[r]) )
6919 continue;
6920 */
6921 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6922 continue;
6923 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6924 continue;
6925
6926 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6927 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6928 continue;
6929 estimategap = atof(estimategapstr + 13);
6930 assert(estimategap >= 0.0);
6931 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6932 estimategap = SCIPgetHugeValue(scip);
6933
6934 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6935 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6936
6937 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6938 }
6939
6940 /* divide by optimal value of LP for scaling */
6941 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6942
6943 return dualscore;
6944}
6945
6946/** computes branching scores (including weighted score) for a set of candidates
6947 *
6948 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6949 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6950 *
6951 * For each score, compute the maximum over all candidates.
6952 *
6953 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6954 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6955 * score of all candidates.
6956 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6957 *
6958 * For example:
6959 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6960 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6961 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6962 * - Then the weighted scores for x will be (2.0 * 10.0/12.0 + 3.0 * 5.0/5.0) / (2.0 + 3.0) = 0.9333.
6963 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6964 */
6965static
6967 SCIP* scip, /**< SCIP data structure */
6968 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6969 BRANCHCAND* cands, /**< branching candidates */
6970 int ncands, /**< number of candidates */
6971 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6972 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6973 )
6974{
6975 SCIP_CONSHDLRDATA* conshdlrdata;
6976 BRANCHCAND maxscore;
6977 int c;
6978
6979 assert(scip != NULL);
6980 assert(conshdlr != NULL);
6981 assert(cands != NULL);
6982 assert(ncands > 0);
6983
6984 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6985 assert(conshdlrdata != NULL);
6986
6987 /* initialize counts to 0 */
6988 memset(&maxscore, 0, sizeof(BRANCHCAND));
6989
6990 for( c = 0; c < ncands; ++c )
6991 {
6992 if( conshdlrdata->branchviolweight > 0.0 )
6993 {
6994 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6995 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6996 }
6997
6998 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarIsNonimpliedIntegral(cands[c].var) )
6999 {
7000 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
7001 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
7002 */
7003 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
7004
7005 if( considerfracnl && cands[c].fractionality == 0.0 )
7006 {
7007 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
7008 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
7009 */
7010 SCIP_Real solval;
7011 SCIP_Real rounded;
7012
7013 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7014 rounded = SCIPround(scip, solval);
7015
7016 cands[c].fractionality = REALABS(solval - rounded);
7017 }
7018
7019 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
7020 }
7021 else
7022 cands[c].fractionality = 0.0;
7023
7024 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
7025 {
7026 SCIP_Real domainwidth;
7027 SCIP_VAR* var;
7028
7029 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7030 assert(var != NULL);
7031
7032 /* get domain width, taking infinity at 1e20 on purpose */
7033 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
7034
7035 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7036 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7037 * the idea is to penalize very large and very small domains
7038 */
7039 if( domainwidth >= 1.0 )
7040 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7041 else
7042 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7043
7044 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7045 }
7046 else
7047 cands[c].domain = 0.0;
7048
7049 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
7050 {
7051 SCIP_VAR* var;
7052
7053 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7054 assert(var != NULL);
7055
7056 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7057 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7058 }
7059 else
7060 cands[c].dual = 0.0;
7061
7062 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7063 {
7064 SCIP_VAR* var;
7065
7066 var = cands[c].var;
7067 assert(var != NULL);
7068
7069 if( cands[c].expr != NULL )
7070 {
7072 cands[c].pscost = SCIP_INVALID;
7073 else
7074 {
7075 SCIP_Real brpoint;
7076 SCIP_Real pscostdown;
7077 SCIP_Real pscostup;
7078 char strategy;
7079
7080 /* decide how to compute pseudo-cost scores
7081 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7082 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7083 */
7084 if( !SCIPvarIsIntegral(var) )
7085 strategy = conshdlrdata->branchpscostupdatestrategy;
7086 else
7087 strategy = 'l';
7088
7089 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7090
7091 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7092 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7093 * For here, I use a simple #counts >= branchpscostreliable.
7094 * TODO use SCIPgetVarPseudocostCount() instead?
7095 */
7096 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7097 {
7098 switch( strategy )
7099 {
7100 case 's' :
7101 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7102 break;
7103 case 'd' :
7104 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7105 break;
7106 case 'l' :
7107 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7108 pscostdown = SCIP_INVALID;
7109 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7110 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7111 else
7112 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, sol, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7113 break;
7114 default :
7115 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7116 pscostdown = SCIP_INVALID;
7117 }
7118 }
7119 else
7120 pscostdown = SCIP_INVALID;
7121
7122 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7123 {
7124 switch( strategy )
7125 {
7126 case 's' :
7127 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7128 break;
7129 case 'd' :
7130 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7131 break;
7132 case 'l' :
7133 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7134 pscostup = SCIP_INVALID;
7135 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7136 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7137 else
7138 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, sol, var) );
7139 break;
7140 default :
7141 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7142 pscostup = SCIP_INVALID;
7143 }
7144 }
7145 else
7146 pscostup = SCIP_INVALID;
7147
7148 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7149 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7150 */
7151 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7152 cands[c].pscost = SCIP_INVALID;
7153 else if( pscostdown == SCIP_INVALID )
7154 cands[c].pscost = pscostup;
7155 else if( pscostup == SCIP_INVALID )
7156 cands[c].pscost = pscostdown;
7157 else
7158 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7159 }
7160 }
7161 else
7162 {
7163 SCIP_Real pscostdown;
7164 SCIP_Real pscostup;
7165 SCIP_Real solval;
7166
7167 solval = SCIPgetSolVal(scip, sol, cands[c].var);
7168
7169 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7170 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7171 * and different between variable value and rounded up value for pscostup
7172 */
7173 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7174 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7175 else
7176 pscostdown = SCIP_INVALID;
7177
7178 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7179 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7180 else
7181 pscostup = SCIP_INVALID;
7182
7183 /* TODO see above for nonlinear variable case */
7184 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7185 cands[c].pscost = SCIP_INVALID;
7186 else if( pscostdown == SCIP_INVALID )
7187 cands[c].pscost = pscostup;
7188 else if( pscostup == SCIP_INVALID )
7189 cands[c].pscost = pscostdown;
7190 else
7191 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7192 }
7193
7194 if( cands[c].pscost != SCIP_INVALID )
7195 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7196 }
7197 else
7198 cands[c].pscost = SCIP_INVALID;
7199
7200 if( conshdlrdata->branchvartypeweight > 0.0 )
7201 {
7202 switch( SCIPvarGetType(cands[c].var) )
7203 {
7205 cands[c].vartype = 1.0;
7206 break;
7208 cands[c].vartype = 0.1;
7209 break;
7211 if( SCIPvarIsImpliedIntegral(cands[c].var) )
7212 cands[c].vartype = 0.01;
7213 else
7214 cands[c].vartype = 0.0;
7215 break;
7216 default:
7217 SCIPerrorMessage("invalid variable type\n");
7218 SCIPABORT();
7219 return; /*lint !e527*/
7220 } /*lint !e788*/
7221
7222 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7223 }
7224 }
7225
7226 /* now compute a weighted score for each candidate from the single scores
7227 * the single scores are scaled to be in [0,1] for this
7228 */
7229 for( c = 0; c < ncands; ++c )
7230 {
7231 SCIP_Real weightsum;
7232
7233 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7234
7235 cands[c].weighted = 0.0;
7236 weightsum = 0.0;
7237
7238 if( maxscore.auxviol > 0.0 )
7239 {
7240 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7241 weightsum += conshdlrdata->branchviolweight;
7242
7243 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7244 }
7245
7246 if( maxscore.fractionality > 0.0 )
7247 {
7248 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7249 weightsum += conshdlrdata->branchfracweight;
7250
7251 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7252 }
7253
7254 if( maxscore.domain > 0.0 )
7255 {
7256 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7257 weightsum += conshdlrdata->branchdomainweight;
7258
7259 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7260 }
7261
7262 if( maxscore.dual > 0.0 )
7263 {
7264 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7265 weightsum += conshdlrdata->branchdualweight;
7266
7267 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7268 }
7269
7270 if( maxscore.pscost > 0.0 )
7271 {
7272 /* use pseudo-costs only if available */
7273 if( cands[c].pscost != SCIP_INVALID )
7274 {
7275 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7276 weightsum += conshdlrdata->branchpscostweight;
7277
7278 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7279 }
7280 else
7281 {
7282 /* do not add pscostscore, if not available, also do not add into weightsum */
7283 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7284 }
7285 }
7286
7287 if( maxscore.vartype > 0.0 )
7288 {
7289 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7290 weightsum += conshdlrdata->branchvartypeweight;
7291
7292 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7293 }
7294
7295 assert(weightsum > 0.0); /* we should have got at least one valid score */
7296 cands[c].weighted /= weightsum;
7297
7298 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7299 }
7300}
7301
7302/** compare two branching candidates by their weighted score
7303 *
7304 * if weighted score is equal, use variable index of (aux)var
7305 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7306 */
7307static
7308SCIP_DECL_SORTINDCOMP(branchcandCompare)
7309{
7310 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7311
7312 if( cands[ind1].weighted != cands[ind2].weighted )
7313 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7314
7315 if( cands[ind1].var != cands[ind2].var )
7316 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7317
7318 return cands[ind1].expr != NULL ? 1 : -1;
7319}
7320
7321/** picks a candidate from array of branching candidates */
7322static
7324 SCIP* scip, /**< SCIP data structure */
7325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7326 BRANCHCAND* cands, /**< branching candidates */
7327 int ncands, /**< number of candidates */
7328 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7329 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
7330 BRANCHCAND** selected /**< buffer to store selected branching candidates */
7331 )
7332{
7333 SCIP_CONSHDLRDATA* conshdlrdata;
7334 int* perm;
7335 int c;
7336 int left;
7337 int right;
7338 SCIP_Real threshold;
7339
7340 assert(cands != NULL);
7341 assert(ncands >= 1);
7342 assert(selected != NULL);
7343
7344 if( ncands == 1 )
7345 {
7346 *selected = cands;
7347 return SCIP_OKAY;
7348 }
7349
7350 /* if there are more than one candidate, then compute scores and select */
7351
7352 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7353 assert(conshdlrdata != NULL);
7354
7355 /* compute additional scores on branching candidates and weighted score */
7356 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
7357
7358 /* sort candidates by weighted score */
7359 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7360 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7361
7362 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7363 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7364 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7365
7366 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7367 left = 0;
7368 right = ncands - 1;
7369 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7370 while( left < right )
7371 {
7372 int mid = (left + right) / 2;
7373 if( cands[perm[mid]].weighted >= threshold )
7374 left = mid + 1;
7375 else
7376 right = mid;
7377 }
7378 assert(left <= ncands);
7379
7380 if( left < ncands )
7381 {
7382 if( cands[perm[left]].weighted >= threshold )
7383 {
7384 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7385 ncands = left + 1;
7386 }
7387 else
7388 {
7389 assert(cands[perm[left]].weighted < threshold);
7390 ncands = left;
7391 }
7392 }
7393 assert(ncands > 0);
7394
7395 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7396 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7397 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7398
7399 if( ncands > 1 )
7400 {
7401 /* choose at random from candidates 0..ncands-1 */
7402 if( conshdlrdata->branchrandnumgen == NULL )
7403 {
7404 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7405 }
7406 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7407 *selected = &cands[perm[c]];
7408 }
7409 else
7410 *selected = &cands[perm[0]];
7411
7412 SCIPfreeBufferArray(scip, &perm);
7413
7414 return SCIP_OKAY;
7415}
7416
7417/** do spatial branching or register branching candidates */
7418static
7420 SCIP* scip, /**< SCIP data structure */
7421 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7422 SCIP_CONS** conss, /**< constraints to process */
7423 int nconss, /**< number of constraints */
7424 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7425 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7426 SCIP_Longint soltag, /**< tag of solution */
7427 SCIP_RESULT* result /**< pointer to store the result of branching */
7428 )
7429{
7430 SCIP_CONSHDLRDATA* conshdlrdata;
7431 BRANCHCAND* cands;
7432 int ncands;
7433 BRANCHCAND* selected = NULL;
7434 SCIP_NODE* downchild;
7435 SCIP_NODE* eqchild;
7436 SCIP_NODE* upchild;
7437
7438 assert(conshdlr != NULL);
7439 assert(result != NULL);
7440
7441 *result = SCIP_DIDNOTFIND;
7442
7443 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7444 assert(conshdlrdata != NULL);
7445
7446 if( conshdlrdata->branchexternal )
7447 {
7448 /* just register branching candidates as external */
7449 SCIP_Bool success;
7450
7451 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7452 if( success )
7453 *result = SCIP_INFEASIBLE;
7454
7455 return SCIP_OKAY;
7456 }
7457
7458 /* collect branching candidates and their auxviol-score */
7460 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7461
7462 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7463 * we will return here and let the fallbacks in consEnfo() decide how to proceed
7464 */
7465 if( ncands == 0 )
7466 goto TERMINATE;
7467
7468 /* here we include fractionality of integer variables into the branching score
7469 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7470 */
7471 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
7472 assert(selected != NULL);
7473 assert(selected->expr != NULL);
7474
7475 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7476 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7477
7478 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7479 &upchild) );
7480 if( downchild != NULL || eqchild != NULL || upchild != NULL )
7481 *result = SCIP_BRANCHED;
7482 else
7483 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7484 *result = SCIP_REDUCEDDOM;
7485
7486 TERMINATE:
7487 SCIPfreeBufferArray(scip, &cands);
7488
7489 return SCIP_OKAY;
7490}
7491
7492/** call enforcement or estimate callback of nonlinear handler
7493 *
7494 * Calls the enforcement callback, if available.
7495 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7496 *
7497 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7498 */
7499static
7501 SCIP* scip, /**< SCIP main data structure */
7502 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7503 SCIP_CONS* cons, /**< nonlinear constraint */
7504 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7505 SCIP_EXPR* expr, /**< expression */
7506 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7507 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7508 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7509 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7510 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7511 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7512 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7513 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7514 SCIP_RESULT* result /**< pointer to store the result */
7515 )
7516{
7517 assert(result != NULL);
7518
7519 /* call enforcement callback of the nlhdlr */
7520 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7521 allowweakcuts, separated, inenforcement, branchcandonly, result) );
7522
7523 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7524 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7525 {
7526 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7527 SCIPnlhdlrGetName(nlhdlr), *result); )
7528 return SCIP_OKAY;
7529 }
7530 else
7531 {
7532 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7533 }
7534
7535 *result = SCIP_DIDNOTFIND;
7536
7537 /* now call the estimator callback of the nlhdlr */
7538 if( SCIPnlhdlrHasEstimate(nlhdlr) )
7539 {
7540 SCIP_VAR* auxvar;
7541 SCIP_Bool sepasuccess = FALSE;
7542 SCIP_Bool branchscoresuccess = FALSE;
7543 SCIP_PTRARRAY* rowpreps;
7544 int minidx;
7545 int maxidx;
7546 int r;
7547 SCIP_ROWPREP* rowprep;
7548
7549 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7550
7551 auxvar = SCIPgetExprAuxVarNonlinear(expr);
7552 assert(auxvar != NULL);
7553
7554 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7555 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7556
7557 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7558 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7559
7560 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7561
7562 if( !sepasuccess )
7563 {
7564 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7565 SCIPnlhdlrGetName(nlhdlr)); )
7566 }
7567
7568 for( r = minidx; r <= maxidx; ++r )
7569 {
7570 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7571
7572 assert(rowprep != NULL);
7573 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7574
7575 if( !branchcandonly )
7576 {
7577 /* complete estimator to cut */
7578 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7579
7580 /* add the cut and/or branching scores
7581 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7582 */
7583 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7584 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7585 }
7586
7587 SCIPfreeRowprep(scip, &rowprep);
7588 }
7589
7590 if( branchcandonly && branchscoresuccess )
7591 {
7592 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7593 *result = SCIP_BRANCHED;
7594 }
7595
7596 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7597 }
7598
7599 return SCIP_OKAY;
7600}
7601
7602/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7603 *
7604 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7605 */
7606static
7608 SCIP* scip, /**< SCIP data structure */
7609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7610 SCIP_CONS* cons, /**< nonlinear constraint */
7611 SCIP_EXPR* expr, /**< expression */
7612 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7613 SCIP_Longint soltag, /**< tag of solution */
7614 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7615 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7616 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7617 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7618 )
7619{
7620 SCIP_CONSHDLRDATA* conshdlrdata;
7621 SCIP_EXPR_OWNERDATA* ownerdata;
7622 SCIP_Real origviol;
7623 SCIP_Bool underestimate;
7624 SCIP_Bool overestimate;
7625 SCIP_Real auxviol;
7626 SCIP_Bool auxunderestimate;
7627 SCIP_Bool auxoverestimate;
7628 SCIP_RESULT hdlrresult;
7629 int e;
7630
7631 assert(scip != NULL);
7632 assert(expr != NULL);
7633 assert(result != NULL);
7634
7635 ownerdata = SCIPexprGetOwnerData(expr);
7636 assert(ownerdata != NULL);
7637 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7638
7639 *result = SCIP_DIDNOTFIND;
7640
7641 /* make sure that this expression has been evaluated */
7642 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7643
7644 /* decide whether under- or overestimate is required and get amount of violation */
7645 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7646
7647 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7648 assert(conshdlrdata != NULL);
7649
7650 /* no sufficient violation w.r.t. the original variables -> skip expression */
7651 if( !overestimate && !underestimate )
7652 {
7653 return SCIP_OKAY;
7654 }
7655
7656 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7657 for( e = 0; e < ownerdata->nenfos; ++e )
7658 {
7659 SCIP_NLHDLR* nlhdlr;
7660
7661 /* skip nlhdlr that do not want to participate in any separation */
7662 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7663 continue;
7664
7665 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7666 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7667 continue;
7668
7669 nlhdlr = ownerdata->enfos[e]->nlhdlr;
7670 assert(nlhdlr != NULL);
7671
7672 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7673 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7674 ENFOLOG(
7675 SCIPinfoMessage(scip, enfologfile, " expr ");
7676 SCIPprintExpr(scip, expr, enfologfile);
7677 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7678 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7679 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7680 )
7681
7682 /* TODO if expr is root of constraint (consdata->expr == expr),
7683 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7684 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7685 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7686 * so we should enforce in these auxiliaries first
7687 * if changing this here, we must also adapt analyzeViolation()
7688 */
7689
7690 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7691 assert(auxviol >= 0.0);
7692
7693 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7694 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7695 {
7696 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7697 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7698 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7699
7700 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7701 continue;
7702 }
7703
7704 /* if aux-violation is small (below feastol) and we look only for strong cuts, then it's unlikely to give a strong cut, so skip it */
7705 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7706 {
7707 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7708 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7709 underestimate, overestimate); )
7710
7711 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7712 continue;
7713 }
7714
7715 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7716 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7717 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7718
7719 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7720 * wants to be called for separation on this side, then call separation of nlhdlr
7721 */
7722 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7723 {
7724 /* call the separation or estimation callback of the nonlinear handler for overestimation */
7725 hdlrresult = SCIP_DIDNOTFIND;
7726 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7727 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7728
7729 if( hdlrresult == SCIP_CUTOFF )
7730 {
7731 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7732 *result = SCIP_CUTOFF;
7733 ownerdata->lastenforced = conshdlrdata->enforound;
7734 break;
7735 }
7736
7737 if( hdlrresult == SCIP_SEPARATED )
7738 {
7739 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7740 *result = SCIP_SEPARATED;
7741 ownerdata->lastenforced = conshdlrdata->enforound;
7742 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7743 break;
7744 }
7745
7746 if( hdlrresult == SCIP_REDUCEDDOM )
7747 {
7748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7749 *result = SCIP_REDUCEDDOM;
7750 ownerdata->lastenforced = conshdlrdata->enforound;
7751 /* TODO or should we always just stop here? */
7752 }
7753
7754 if( hdlrresult == SCIP_BRANCHED )
7755 {
7756 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7757 assert(inenforcement);
7758
7759 /* separation and domain reduction takes precedence over branching */
7760 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7761 if( *result == SCIP_DIDNOTFIND )
7762 *result = SCIP_BRANCHED;
7763 ownerdata->lastenforced = conshdlrdata->enforound;
7764 }
7765 }
7766
7767 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7768 * wants to be called for separation on this side, then call separation of nlhdlr
7769 */
7770 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7771 {
7772 /* call the separation or estimation callback of the nonlinear handler for underestimation */
7773 hdlrresult = SCIP_DIDNOTFIND;
7774 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7775 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7776
7777 if( hdlrresult == SCIP_CUTOFF )
7778 {
7779 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7780 *result = SCIP_CUTOFF;
7781 ownerdata->lastenforced = conshdlrdata->enforound;
7782 break;
7783 }
7784
7785 if( hdlrresult == SCIP_SEPARATED )
7786 {
7787 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7788 *result = SCIP_SEPARATED;
7789 ownerdata->lastenforced = conshdlrdata->enforound;
7790 /* TODO or should we give other nlhdlr another chance? (also #3070) */
7791 break;
7792 }
7793
7794 if( hdlrresult == SCIP_REDUCEDDOM )
7795 {
7796 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7797 *result = SCIP_REDUCEDDOM;
7798 ownerdata->lastenforced = conshdlrdata->enforound;
7799 /* TODO or should we always just stop here? */
7800 }
7801
7802 if( hdlrresult == SCIP_BRANCHED )
7803 {
7804 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7805 assert(inenforcement);
7806
7807 /* separation takes precedence over branching */
7808 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7809 if( *result == SCIP_DIDNOTFIND )
7810 *result = SCIP_BRANCHED;
7811 ownerdata->lastenforced = conshdlrdata->enforound;
7812 }
7813 }
7814 }
7815
7816 return SCIP_OKAY;
7817}
7818
7819/** helper function to enforce a single constraint */
7820static
7822 SCIP* scip, /**< SCIP data structure */
7823 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7824 SCIP_CONS* cons, /**< constraint to process */
7825 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7826 SCIP_Longint soltag, /**< tag of solution */
7827 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7828 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7829 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7830 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7831 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7832 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7833 )
7834{
7835 SCIP_CONSDATA* consdata;
7836 SCIP_CONSHDLRDATA* conshdlrdata;
7837 SCIP_EXPR* expr;
7838
7839 assert(conshdlr != NULL);
7840 assert(cons != NULL);
7841 assert(it != NULL);
7842 assert(result != NULL);
7843 assert(success != NULL);
7844
7845 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7846 assert(conshdlrdata != NULL);
7847
7848 consdata = SCIPconsGetData(cons);
7849 assert(consdata != NULL);
7850 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7851
7852 *success = FALSE;
7853
7854 if( inenforcement && !branchcandonly && !consdata->ispropagated )
7855 {
7856 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7857 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7858 * (TODO: nlhdlr tells us now whether they do and so we could skip).
7859 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7860 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7861 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7862 * confuse the stalling check for how long to do separation).
7863 */
7864 SCIP_Bool infeasible;
7865 int ntightenings;
7866
7867 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7868 if( infeasible )
7869 {
7870 *result = SCIP_CUTOFF;
7871 return SCIP_OKAY;
7872 }
7873 /* if we tightened an auxvar bound, we better communicate that */
7874 if( ntightenings > 0 )
7875 *result = SCIP_REDUCEDDOM;
7876 }
7877
7878 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7879 {
7880 SCIP_EXPR_OWNERDATA* ownerdata;
7881 SCIP_RESULT resultexpr;
7882
7883 ownerdata = SCIPexprGetOwnerData(expr);
7884 assert(ownerdata != NULL);
7885
7886 /* we can only enforce if there is an auxvar to compare with */
7887 if( ownerdata->auxvar == NULL )
7888 continue;
7889
7890 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7891 if( ownerdata->lastenforced == conshdlrdata->enforound )
7892 {
7893 ENFOLOG(
7894 SCIPinfoMessage(scip, enfologfile, " skip expr ");
7895 SCIPprintExpr(scip, expr, enfologfile);
7896 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7897 )
7898 *success = TRUE;
7899 continue;
7900 }
7901
7902 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7903
7904 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7905 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7906 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
7907 *success = TRUE;
7908
7909 if( resultexpr == SCIP_CUTOFF )
7910 {
7911 *result = SCIP_CUTOFF;
7912 break;
7913 }
7914
7915 if( resultexpr == SCIP_SEPARATED )
7916 *result = SCIP_SEPARATED;
7917
7918 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7919 *result = SCIP_REDUCEDDOM;
7920
7921 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7922 *result = SCIP_BRANCHED;
7923 }
7924
7925 return SCIP_OKAY;
7926}
7927
7928/** try to separate violated constraints and, if in enforcement, register branching scores
7929 *
7930 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7931 *
7932 * Sets result to
7933 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7934 * - SCIP_CUTOFF, if node can be cutoff,
7935 * - SCIP_SEPARATED, if a cut has been added,
7936 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7937 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7938 * - SCIP_INFEASIBLE, if external branching candidates were registered
7939 */
7940static
7942 SCIP* scip, /**< SCIP data structure */
7943 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7944 SCIP_CONS** conss, /**< constraints to process */
7945 int nconss, /**< number of constraints */
7946 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7947 SCIP_Longint soltag, /**< tag of solution */
7948 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7949 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7950 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7951 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7952 )
7953{
7954 SCIP_CONSHDLRDATA* conshdlrdata;
7955 SCIP_EXPRITER* it;
7956 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7957 int c;
7958
7959 assert(conshdlr != NULL);
7960 assert(conss != NULL || nconss == 0);
7961 assert(result != NULL);
7962
7963 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7964 assert(conshdlrdata != NULL);
7965
7966 /* increase tag to tell whether branching scores in expression belong to this sweep
7967 * and which expressions have already been enforced in this sweep
7968 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7969 */
7970 ++(conshdlrdata->enforound);
7971
7972 *result = SCIP_DIDNOTFIND;
7973
7976
7977 for( c = 0; c < nconss; ++c )
7978 {
7979 assert(conss != NULL && conss[c] != NULL);
7980
7981 /* skip constraints that are not enabled or deleted */
7982 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7983 continue;
7984 assert(SCIPconsIsActive(conss[c]));
7985
7986 /* skip constraints that have separation disabled if we are only in separation */
7987 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7988 continue;
7989
7990 /* skip non-violated constraints */
7991 if( !isConsViolated(scip, conss[c]) )
7992 continue;
7993
7994 ENFOLOG(
7995 {
7996 SCIP_CONSDATA* consdata;
7997 int i;
7998 consdata = SCIPconsGetData(conss[c]);
7999 assert(consdata != NULL);
8000 SCIPinfoMessage(scip, enfologfile, " constraint ");
8001 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
8002 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
8003 for( i = 0; i < consdata->nvarexprs; ++i )
8004 {
8005 SCIP_VAR* var;
8006 var = SCIPgetVarExprVar(consdata->varexprs[i]);
8007 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
8008 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8009 }
8010 })
8011
8012 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
8013
8014 if( *result == SCIP_CUTOFF )
8015 break;
8016
8017 if( !consenforced && inenforcement && !branchcandonly )
8018 {
8019 SCIP_Real viol;
8020
8021 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
8022 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
8023 {
8024 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
8025 "cuts allowed\n", SCIPconsGetName(conss[c])); )
8026
8027 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
8028
8029 if( consenforced )
8030 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
8031
8032 if( *result == SCIP_CUTOFF )
8033 break;
8034 }
8035 }
8036 }
8037
8038 SCIPfreeExpriter(&it);
8039
8040 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8041
8042 if( *result == SCIP_BRANCHED && !branchcandonly )
8043 {
8044 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
8045 * branching
8046 */
8047 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
8048
8049 /* branching should either have branched: result == SCIP_BRANCHED,
8050 * or fixed a variable: result == SCIP_REDUCEDDOM,
8051 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
8052 * or have not done anything: result == SCIP_DIDNOTFIND
8053 */
8054 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
8055 }
8056
8057 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
8058
8059 return SCIP_OKAY;
8060}
8061
8062/** decide whether to branch on fractional integer or nonlinear variable
8063 *
8064 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
8065 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
8066 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
8067 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
8068 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
8069 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
8070 */
8071static
8073 SCIP* scip, /**< SCIP data structure */
8074 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8075 SCIP_CONS** conss, /**< constraints to process */
8076 int nconss, /**< number of constraints */
8077 SCIP_Longint soltag, /**< tag of LP solution */
8078 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
8079 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
8080 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
8081 )
8082{
8083 SCIP_RESULT result;
8084 int nlpcands;
8085 SCIP_VAR** lpcands; /* fractional integer variables */
8086 SCIP_Real* lpcandsfrac; /* fractionalities */
8087 BRANCHCAND* cands;
8088 BRANCHCAND* selected;
8089 int ncands;
8090 int c;
8091
8092 assert(scip != NULL);
8093 assert(conshdlr != NULL);
8094 assert(conss != NULL);
8095 assert(nconss > 0);
8096 assert(branchintegral != NULL);
8097 assert(cutoff != NULL);
8098
8099 *branchintegral = FALSE;
8100 *cutoff = FALSE;
8101
8103 return SCIP_OKAY;
8104
8105 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
8106 switch( result )
8107 {
8108 case SCIP_DIDNOTFIND:
8109 /* no branching candidates found could mean that the LP solution is in a convex region */
8110 *branchintegral = TRUE;
8111 return SCIP_OKAY;
8112
8113 case SCIP_CUTOFF:
8114 /* probably cannot happen, but easy to handle */
8115 *cutoff = TRUE;
8116 return SCIP_OKAY;
8117
8118 case SCIP_SEPARATED:
8119 case SCIP_REDUCEDDOM:
8120 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8121 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8122 return SCIP_ERROR;
8123
8124 case SCIP_BRANCHED:
8125 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8126 break;
8127
8128 case SCIP_INFEASIBLE:
8129 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8130 * but this was disabled by branchcandonly = TRUE)
8131 */
8132 default:
8133 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8134 return SCIP_ERROR;
8135 } /*lint !e788*/
8136
8137 /* collect spatial branching candidates and their auxviol-score */
8139 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8140
8141 /* add fractional integer variables to branching candidates */
8142 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
8143
8144 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8145
8146 for( c = 0; c < nlpcands; ++c )
8147 {
8148 assert(SCIPvarGetType(lpcands[c]) != SCIP_VARTYPE_CONTINUOUS);
8149 assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
8150 cands[ncands].expr = NULL;
8151 cands[ncands].var = lpcands[c];
8152 cands[ncands].auxviol = 0.0;
8153 cands[ncands].fractionality = lpcandsfrac[c];
8154 ++ncands;
8155 }
8156
8157 /* select a variable for branching
8158 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8159 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
8160 */
8161 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
8162 assert(selected != NULL);
8163
8164 if( selected->expr == NULL )
8165 {
8166 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8167
8168 *branchintegral = TRUE;
8169 }
8170
8171 SCIPfreeBufferArray(scip, &cands);
8172
8173 return SCIP_OKAY;
8174}
8175
8176/** decide whether to consider spatial branching before integrality has been enforced
8177 *
8178 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8179 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8180 *
8181 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8182 */
8183static
8185 SCIP* scip, /**< SCIP data structure */
8186 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8187 SCIP_SOL* sol /**< solution to be enforced */
8188 )
8189{
8190 SCIP_CONSHDLRDATA* conshdlrdata;
8191
8192 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8193 assert(conshdlrdata != NULL);
8194
8195 /* if LP still unbounded, then work on nonlinear constraints first */
8197 return FALSE;
8198
8199 /* no branching in cons_integral if no integer variables */
8201 return FALSE;
8202
8203 /* no branching in cons_integral if LP solution not fractional */
8204 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
8205 return FALSE;
8206
8207 /* no branching in cons_integral if relax solution not fractional */
8208 if( sol != NULL )
8209 {
8210 SCIP_Bool isfractional = FALSE;
8211 SCIP_VAR** vars;
8212 int nbinvars;
8213 int nintvars;
8214 int i;
8215
8216 vars = SCIPgetVars(scip);
8217 nbinvars = SCIPgetNBinVars(scip);
8218 nintvars = SCIPgetNIntVars(scip);
8219
8220 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
8221 {
8222 assert(vars[i] != NULL);
8223 assert(SCIPvarIsIntegral(vars[i]));
8224
8225 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[i])) )
8226 isfractional = TRUE;
8227 }
8228
8229 if( !isfractional )
8230 return FALSE;
8231 }
8232
8233 /* branchmixfractional being infinity means that integral should always go first */
8234 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8235 return TRUE;
8236
8237 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8238 if( conshdlrdata->branchmixfractional == 0.0 )
8239 return FALSE;
8240
8241 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8242 * @todo this gives the total pseudocost count divided by the number of discrete variables
8243 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8244 */
8245 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8246 return TRUE;
8247 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8248 return TRUE;
8249
8250 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8251 return FALSE;
8252}
8253
8254/** collect (and print (if debugging enfo)) information on violation in expressions
8255 *
8256 * assumes that constraint violations have been computed
8257 */
8258static
8260 SCIP* scip, /**< SCIP data structure */
8261 SCIP_CONS** conss, /**< constraints */
8262 int nconss, /**< number of constraints */
8263 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8264 SCIP_Longint soltag, /**< tag of solution */
8265 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8266 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8267 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8268 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8269 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8270 )
8271{
8272 SCIP_CONSDATA* consdata;
8273 SCIP_EXPRITER* it;
8274 SCIP_EXPR* expr;
8275 SCIP_Real v;
8276 int c;
8277
8278 assert(conss != NULL || nconss == 0);
8279 assert(maxabsconsviol != NULL);
8280 assert(maxrelconsviol != NULL);
8281 assert(maxauxviol != NULL);
8282 assert(maxvarboundviol != NULL);
8283
8286
8287 *maxabsconsviol = 0.0;
8288 *maxrelconsviol = 0.0;
8289 *minauxviol = SCIPinfinity(scip);
8290 *maxauxviol = 0.0;
8291 *maxvarboundviol = 0.0;
8292
8293 for( c = 0; c < nconss; ++c )
8294 {
8295 assert(conss != NULL && conss[c] != NULL);
8296
8297 consdata = SCIPconsGetData(conss[c]);
8298 assert(consdata != NULL);
8299
8300 /* skip constraints that are not enabled, deleted, or have separation disabled */
8301 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8302 continue;
8303 assert(SCIPconsIsActive(conss[c]));
8304
8305 v = getConsAbsViolation(conss[c]);
8306 *maxabsconsviol = MAX(*maxabsconsviol, v);
8307
8308 /* skip non-violated constraints */
8309 if( !isConsViolated(scip, conss[c]) )
8310 continue;
8311
8312 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8313 *maxrelconsviol = MAX(*maxrelconsviol, v);
8314
8315 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8316 {
8317 SCIP_EXPR_OWNERDATA* ownerdata;
8318 SCIP_Real auxvarvalue;
8319 SCIP_Real auxvarlb;
8320 SCIP_Real auxvarub;
8321 SCIP_Bool violunder;
8322 SCIP_Bool violover;
8323 SCIP_Real origviol;
8324 SCIP_Real auxviol;
8325 int e;
8326
8327 ownerdata = SCIPexprGetOwnerData(expr);
8328 assert(ownerdata != NULL);
8329
8330 if( ownerdata->auxvar == NULL )
8331 {
8332 /* check violation of variable bounds of original variable */
8333 if( SCIPisExprVar(scip, expr) )
8334 {
8335 SCIP_VAR* var;
8336 var = SCIPgetVarExprVar(expr);
8337 auxvarvalue = SCIPgetSolVal(scip, sol, var);
8338 auxvarlb = SCIPvarGetLbLocal(var);
8339 auxvarub = SCIPvarGetUbLocal(var);
8340
8341 origviol = 0.0;
8342 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8343 origviol = auxvarlb - auxvarvalue;
8344 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8345 origviol = auxvarvalue - auxvarub;
8346 if( origviol <= 0.0 )
8347 continue;
8348
8349 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8350
8351 ENFOLOG(
8352 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8353 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8354 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8355 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8356 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8357 SCIPinfoMessage(scip, enfologfile, "\n");
8358 )
8359 }
8360
8361 continue;
8362 }
8363
8364 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8365 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8366 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8367
8368 /* check violation of variable bounds of auxiliary variable */
8369 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8370 *maxvarboundviol = auxvarlb - auxvarvalue;
8371 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8372 *maxvarboundviol = auxvarvalue - auxvarub;
8373
8374 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8375
8376 ENFOLOG(
8377 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8378 {
8379 SCIPinfoMessage(scip, enfologfile, "expr ");
8380 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8381 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8382
8383 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8384 if( origviol > 0.0 )
8385 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8386 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8387 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8388 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8389 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8390 SCIPinfoMessage(scip, enfologfile, "\n");
8391 }
8392 )
8393
8394 /* no violation w.r.t. the original variables -> skip expression */
8395 if( origviol == 0.0 )
8396 continue;
8397
8398 /* compute aux-violation for each nonlinear handlers */
8399 for( e = 0; e < ownerdata->nenfos; ++e )
8400 {
8401 SCIP_NLHDLR* nlhdlr;
8402
8403 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8404 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8405 continue;
8406
8407 nlhdlr = ownerdata->enfos[e]->nlhdlr;
8408 assert(nlhdlr != NULL);
8409
8410 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8411 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8412
8413 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8414
8415 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8416
8417 if( auxviol > 0.0 )
8418 {
8419 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8420 *maxauxviol = MAX(*maxauxviol, auxviol);
8421 *minauxviol = MIN(*minauxviol, auxviol);
8422 }
8423 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8424 }
8425 }
8426 }
8427
8428 SCIPfreeExpriter(&it);
8429
8430 return SCIP_OKAY;
8431} /*lint !e715*/
8432
8433/** enforcement of constraints called by enfolp and enforelax */
8434static
8436 SCIP* scip, /**< SCIP data structure */
8437 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8438 SCIP_CONS** conss, /**< constraints to process */
8439 int nconss, /**< number of constraints */
8440 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8441 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8442 )
8443{
8444 SCIP_CONSHDLRDATA* conshdlrdata;
8445 SCIP_Real maxabsconsviol;
8446 SCIP_Real maxrelconsviol;
8447 SCIP_Real minauxviol;
8448 SCIP_Real maxauxviol;
8449 SCIP_Real maxvarboundviol;
8450 SCIP_Longint soltag;
8451 SCIP_Bool branchintegral;
8452 int nnotify;
8453 int c;
8454
8455 if( branchingIntegralFirst(scip, conshdlr, sol) )
8456 {
8457 /* let cons_integral handle enforcement */
8458 *result = SCIP_INFEASIBLE;
8459 return SCIP_OKAY;
8460 }
8461
8462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8463 assert(conshdlr != NULL);
8464
8465 soltag = SCIPgetExprNewSoltag(scip);
8466
8467 *result = SCIP_FEASIBLE;
8468 for( c = 0; c < nconss; ++c )
8469 {
8470 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8471
8472 if( isConsViolated(scip, conss[c]) )
8473 *result = SCIP_INFEASIBLE;
8474 }
8475
8476 if( *result == SCIP_FEASIBLE )
8477 {
8478 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8480 return SCIP_OKAY;
8481 }
8482
8483 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8484 &minauxviol, &maxauxviol, &maxvarboundviol) );
8485
8486 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8487 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8488 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8489 maxvarboundviol, SCIPgetLPFeastol(scip)); )
8490
8491 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8492
8493 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8494 if( sol == NULL )
8495 {
8496 SCIP_Bool cutoff;
8497
8498 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8499 if( cutoff )
8500 {
8501 *result = SCIP_CUTOFF;
8502 return SCIP_OKAY;
8503 }
8504 if( branchintegral )
8505 {
8506 /* let cons_integral handle enforcement */
8507 *result = SCIP_INFEASIBLE;
8508 return SCIP_OKAY;
8509 }
8510 }
8511
8512 /* try to propagate */
8513 if( conshdlrdata->propinenforce )
8514 {
8515 SCIP_RESULT propresult;
8516 int nchgbds = 0;
8517
8518 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8519
8520 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8521 {
8522 *result = propresult;
8523 return SCIP_OKAY;
8524 }
8525 }
8526
8527 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8528 * all violated expr/auxvar in violated constraints)
8529 */
8530 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8531 sol == NULL )
8532 {
8533 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8534 ++conshdlrdata->ntightenlp;
8535
8536 *result = SCIP_SOLVELP;
8537
8538 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8539 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8540
8541 return SCIP_OKAY;
8542 }
8543
8544 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8545 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8546 */
8547 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8548 {
8549 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8550 ++conshdlrdata->ntightenlp;
8551
8552 *result = SCIP_SOLVELP;
8553
8554 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8555
8556 return SCIP_OKAY;
8557 }
8558
8559 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8560
8561 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8562 *result == SCIP_INFEASIBLE )
8563 return SCIP_OKAY;
8564
8565 assert(*result == SCIP_DIDNOTFIND);
8566
8567 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8568 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8569
8570 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8571 {
8572 /* if there are still fractional integer variables, then let cons_integral go first */
8573 *result = SCIP_INFEASIBLE;
8574 return SCIP_OKAY;
8575 }
8576
8577 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8578 {
8579 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8580 ++conshdlrdata->ntightenlp;
8581
8582 *result = SCIP_SOLVELP;
8583
8584 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8585 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8586
8587 return SCIP_OKAY;
8588 }
8589
8590 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8591 SCIPgetLPFeastol(scip)) && sol == NULL )
8592 {
8593 /* try whether tighten the LP feasibility tolerance could help
8594 * maybe it is just some cut that hasn't been taken into account sufficiently
8595 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8596 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8597 * until the LP feastol reaches epsilon
8598 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8599 * when maxauxviol is above LP feastol)
8600 */
8601 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8602 ++conshdlrdata->ndesperatetightenlp;
8603
8604 *result = SCIP_SOLVELP;
8605
8606 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8607
8608 return SCIP_OKAY;
8609 }
8610
8611 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8612 if( !conshdlrdata->propinenforce )
8613 {
8614 SCIP_RESULT propresult;
8615 int nchgbds = 0;
8616
8617 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8618
8619 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8620 {
8621 *result = propresult;
8622 return SCIP_OKAY;
8623 }
8624 }
8625
8626 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8627 * now look if we find any unfixed variable that we could still branch on
8628 */
8629 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8630
8631 if( nnotify > 0 )
8632 {
8633 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8634 ++conshdlrdata->ndesperatebranch;
8635
8636 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8637
8638 return SCIP_OKAY;
8639 }
8640
8641 /* if everything is fixed in violated constraints, then let's cut off the node
8642 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8643 * result may not be conclusive (when constraint violations are small)
8644 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8645 * sufficiently (see st_e40)
8646 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8647 * not "desperate", but a pretty obvious thing to do
8648 */
8649 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8650 *result = SCIP_CUTOFF;
8651
8652 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8653 if( !SCIPisZero(scip, maxvarboundviol) )
8654 ++conshdlrdata->ndesperatecutoff;
8655
8656 return SCIP_OKAY;
8657}
8658
8659/** separation for all violated constraints to be used by SEPA callbacks */
8660static
8662 SCIP* scip, /**< SCIP data structure */
8663 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8664 SCIP_CONS** conss, /**< constraints to process */
8665 int nconss, /**< number of constraints */
8666 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8667 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8668 )
8669{
8670 SCIP_Longint soltag;
8671 SCIP_Bool haveviol = FALSE;
8672 int c;
8673
8674 *result = SCIP_DIDNOTFIND;
8675
8676 soltag = SCIPgetExprNewSoltag(scip);
8677
8678 /* compute violations */
8679 for( c = 0; c < nconss; ++c )
8680 {
8681 assert(conss[c] != NULL);
8682
8683 /* skip constraints that are not enabled, deleted, or have separation disabled */
8684 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8685 continue;
8686 assert(SCIPconsIsActive(conss[c]));
8687
8688 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8689
8690 if( isConsViolated(scip, conss[c]) )
8691 haveviol = TRUE;
8692 }
8693
8694 /* if none of our constraints are violated, don't attempt separation */
8695 if( !haveviol )
8696 {
8697 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8698 return SCIP_OKAY;
8699 }
8700
8701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8702
8703 /* call separation */
8704 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8705
8706 return SCIP_OKAY;
8707}
8708
8709/** hash key retrieval function for bilinear term entries */
8710static
8711SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8712{ /*lint --e{715}*/
8713 SCIP_CONSHDLRDATA* conshdlrdata;
8714 int idx;
8715
8716 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8717 assert(conshdlrdata != NULL);
8718
8719 idx = ((int)(size_t)elem) - 1;
8720 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8721
8722 return (void*)&conshdlrdata->bilinterms[idx];
8723}
8724
8725/** returns TRUE iff the bilinear term entries are equal */
8726static
8727SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8728{ /*lint --e{715}*/
8731
8732 /* get corresponding entries */
8733 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8734 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8735 assert(entry1->x != NULL && entry1->y != NULL);
8736 assert(entry2->x != NULL && entry2->y != NULL);
8737 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8738 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8739
8740 return entry1->x == entry2->x && entry1->y == entry2->y;
8741}
8742
8743/** returns the hash value of the key */
8744static
8745SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8746{ /*lint --e{715}*/
8748
8749 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8750 assert(entry->x != NULL && entry->y != NULL);
8751 assert(SCIPvarCompare(entry->x, entry->y) < 1);
8752
8753 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8754}
8755
8756/** compare two auxiliary expressions
8757 *
8758 * Compares auxiliary variables, followed by coefficients, and then constants.
8759 */
8760static
8762{
8765 int compvars;
8766 int i;
8767
8768 /* compare the auxiliary variables */
8769 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8770
8771 if( compvars != 0 )
8772 return compvars;
8773
8774 /* compare the coefficients and constants */
8775 for( i = 0; i < 3; ++i )
8776 {
8777 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8778 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8779 }
8780
8781 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8782}
8783
8784/* add an auxiliary expression to a bilinear term */
8785static
8787 SCIP* scip, /**< SCIP data structure */
8788 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8789 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8790 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8791 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8792 )
8793{
8794 SCIP_Bool found;
8795 int pos;
8796 int i;
8797
8798 *added = FALSE;
8799
8800 /* check if auxexpr has already been added to term */
8801 if( term->nauxexprs == 0 )
8802 {
8803 found = FALSE;
8804 pos = 0;
8805 }
8806 else
8807 {
8808 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8809 }
8810
8811 if( !found )
8812 {
8813 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8814 return SCIP_OKAY;
8815
8817 assert(term->auxexprssize >= term->nauxexprs + 1);
8818
8819 /* insert expression at the correct position */
8820 for( i = term->nauxexprs; i > pos; --i )
8821 {
8822 term->aux.exprs[i] = term->aux.exprs[i-1];
8823 }
8824 term->aux.exprs[pos] = auxexpr;
8825 ++(term->nauxexprs);
8826 *added = TRUE;
8827 }
8828 else
8829 {
8830 assert(term->aux.exprs != NULL);
8831 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8832 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8833 }
8834
8835 return SCIP_OKAY;
8836}
8837
8838/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8839static
8841 SCIP* scip, /**< SCIP data structure */
8842 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8843 SCIP_CONS** conss, /**< nonlinear constraints */
8844 int nconss /**< total number of nonlinear constraints */
8845 )
8846{
8847 SCIP_CONSHDLRDATA* conshdlrdata;
8848 SCIP_EXPRITER* it;
8849 int c;
8850
8851 assert(conss != NULL || nconss == 0);
8852
8853 if( nconss == 0 )
8854 return SCIP_OKAY;
8855
8856 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8857 assert(conshdlrdata != NULL);
8858
8859 /* check whether the bilinear terms have been stored already */
8860 if( conshdlrdata->bilinterms != NULL )
8861 return SCIP_OKAY;
8862
8863 /* create and initialize iterator */
8867
8868 /* iterate through all constraints */
8869 for( c = 0; c < nconss; ++c )
8870 {
8871 SCIP_CONSDATA* consdata;
8872 SCIP_EXPR* expr;
8873
8874 assert(conss != NULL && conss[c] != NULL);
8875 consdata = SCIPconsGetData(conss[c]);
8876 assert(consdata != NULL);
8877
8878 /* iterate through all expressions */
8879 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8880 {
8881 SCIP_EXPR** children = SCIPexprGetChildren(expr);
8882 SCIP_VAR* x = NULL;
8883 SCIP_VAR* y = NULL;
8884
8885 /* check whether the expression is of the form f(..)^2 */
8886 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8887 {
8888 x = SCIPgetExprAuxVarNonlinear(children[0]);
8889 y = x;
8890 }
8891 /* check whether the expression is of the form f(..) * g(..) */
8892 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8893 {
8894 x = SCIPgetExprAuxVarNonlinear(children[0]);
8895 y = SCIPgetExprAuxVarNonlinear(children[1]);
8896 }
8897
8898 /* add variables to the hash table */
8899 if( x != NULL && y != NULL )
8900 {
8903 }
8904 }
8905 }
8906
8907 /* release iterator */
8908 SCIPfreeExpriter(&it);
8909
8910 return SCIP_OKAY;
8911}
8912
8913/** store x, y and the locks in a new bilinear term */
8914static
8916 SCIP* scip, /**< SCIP data structure */
8917 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8918 SCIP_VAR* x, /**< the first variable */
8919 SCIP_VAR* y, /**< the second variable */
8920 int nlockspos, /**< number of positive locks of the bilinear term */
8921 int nlocksneg, /**< number of negative locks of the bilinear term */
8922 int* idx, /**< pointer to store the position of the term in bilinterms array */
8923 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8924 )
8925{
8926 SCIP_CONSHDLRDATA* conshdlrdata;
8928
8929 assert(conshdlr != NULL);
8930 assert(x != NULL);
8931 assert(y != NULL);
8932 assert(nlockspos >= 0);
8933 assert(nlocksneg >= 0);
8934
8935 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8936 assert(conshdlrdata != NULL);
8937
8938 /* ensure that x.index <= y.index */
8939 if( SCIPvarCompare(x, y) == 1 )
8940 {
8941 SCIPswapPointers((void**)&x, (void**)&y);
8942 }
8943 assert(SCIPvarCompare(x, y) < 1);
8944
8945 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8946
8947 /* update or create the term */
8948 if( *idx >= 0 )
8949 { /* the term has already been added */
8950 assert(conshdlrdata->bilinterms[*idx].x == x);
8951 assert(conshdlrdata->bilinterms[*idx].y == y);
8952
8953 /* get term and add locks */
8954 term = &conshdlrdata->bilinterms[*idx];
8955 assert(existing <= term->existing); /* implicit terms are added after existing ones */
8956 term->nlockspos += nlockspos;
8957 term->nlocksneg += nlocksneg;
8958 }
8959 else
8960 { /* this is the first time we encounter this product */
8961 /* ensure size of bilinterms array */
8962 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8963
8964 *idx = conshdlrdata->nbilinterms;
8965
8966 /* get term and set values in the created bilinear term */
8967 term = &conshdlrdata->bilinterms[*idx];
8968 assert(term != NULL);
8969 term->x = x;
8970 term->y = y;
8971 term->nauxexprs = 0;
8972 term->auxexprssize = 0;
8973 term->nlockspos = nlockspos;
8974 term->nlocksneg = nlocksneg;
8975 term->existing = existing;
8976 if( existing )
8977 term->aux.var = NULL;
8978 else
8979 term->aux.exprs = NULL;
8980
8981 /* increase the total number of bilinear terms */
8982 ++(conshdlrdata->nbilinterms);
8983
8984 /* save to the hashtable */
8985 if( conshdlrdata->bilinhashtable == NULL )
8986 {
8987 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8988 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8989 (void*)conshdlrdata) );
8990 }
8991 assert(conshdlrdata->bilinhashtable != NULL);
8992
8993 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8994 * because zero can not be inserted into hash table
8995 */
8996 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8997
8998 /* capture product variables */
9001 }
9002
9003 return SCIP_OKAY;
9004}
9005
9006/** frees array of bilinear terms and hash table */
9007static
9009 SCIP* scip, /**< SCIP data structure */
9010 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
9011 )
9012{
9013 int i;
9014 int j;
9015
9016 assert(conshdlrdata != NULL);
9017
9018 /* check whether bilinear terms have been stored */
9019 if( conshdlrdata->bilinterms == NULL )
9020 {
9021 assert(conshdlrdata->bilinterms == NULL);
9022 assert(conshdlrdata->nbilinterms == 0);
9023 assert(conshdlrdata->bilintermssize == 0);
9024
9025 return SCIP_OKAY;
9026 }
9027
9028 /* release variables */
9029 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
9030 {
9031 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
9032 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
9033
9034 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
9035 {
9036 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
9037 {
9038 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
9039 }
9040 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
9041 }
9042
9043 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
9044 {
9045 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
9046 continue;
9047 }
9048
9049 /* the rest is for simple terms with a single auxvar */
9050
9051 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
9052 if( conshdlrdata->bilinterms[i].aux.var != NULL )
9053 {
9054 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
9055 }
9056 }
9057
9058 /* free hash table */
9059 if( conshdlrdata->bilinhashtable != NULL )
9060 {
9061 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
9062 }
9063
9064 /* free bilinterms array; reset counters */
9065 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
9066 conshdlrdata->nbilinterms = 0;
9067 conshdlrdata->bilintermssize = 0;
9068
9069 return SCIP_OKAY;
9070}
9071
9072/*
9073 * vertex polyhedral separation
9074 */
9075
9076/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
9077static
9079 SCIP* scip, /**< SCIP data structure */
9080 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
9081 SCIP_LPI** lp /**< pointer to store created LP */
9082 )
9083{
9084 SCIP_Real* obj;
9085 SCIP_Real* lb;
9086 SCIP_Real* ub;
9087 SCIP_Real* val;
9088 int* beg;
9089 int* ind;
9090 unsigned int nnonz;
9091 unsigned int ncols;
9092 unsigned int nrows;
9093 unsigned int i;
9094 unsigned int k;
9095
9096 assert(scip != NULL);
9097 assert(lp != NULL);
9098 assert(nvars > 0);
9099 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9100
9101 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
9102
9103 /* create lpi to store the LP */
9105
9106 nrows = (unsigned int)nvars + 1;
9107 ncols = POWEROFTWO((unsigned int)nvars);
9108 nnonz = (ncols * (nrows + 1)) / 2;
9109
9110 /* allocate necessary memory; set obj, lb, and ub to zero */
9111 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
9113 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
9114 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
9115 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
9116 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
9117
9118 /* calculate nonzero entries in the LP */
9119 for( i = 0, k = 0; i < ncols; ++i )
9120 {
9121 int row;
9122 unsigned int a;
9123
9124 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
9125 ub[i] = SCIPlpiInfinity(*lp);
9126
9127 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
9128 beg[i] = (int)k;
9129 row = 0;
9130
9131 /* iterate through the bit representation of i */
9132 a = 1;
9133 while( a <= i )
9134 {
9135 if( (a & i) != 0 )
9136 {
9137 val[k] = 1.0;
9138 ind[k] = row;
9139
9140 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
9141
9142 ++k;
9143 }
9144
9145 a <<= 1;
9146 ++row;
9147 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
9148 assert(POWEROFTWO(row) == a);
9149 }
9150
9151 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
9152 val[k] = 1.0;
9153 ind[k] = (int)nrows - 1;
9154 ++k;
9155 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9156 }
9157 assert(k == nnonz);
9158
9159 /* load all data into LP interface
9160 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9161 */
9162 assert(nrows <= ncols);
9164 (int)ncols, obj, lb, ub, NULL,
9165 (int)nrows, lb, lb, NULL,
9166 (int)nnonz, beg, ind, val) );
9167
9168 /* for the last row, we can set the rhs to 1.0 already */
9169 ind[0] = (int)nrows - 1;
9170 val[0] = 1.0;
9171 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9172
9173 /* free allocated memory */
9180
9181 return SCIP_OKAY;
9182}
9183
9184/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9185 * \max_{v \in V} f(v) - (\alpha v + \beta) \f$ (\f$\max_{v \in V} \alpha v + \beta - f(v) \f$) where \f$ V \f$ is the
9186 * set of vertices of the domain
9187 */
9188static
9190 SCIP* scip, /**< SCIP data structure */
9191 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9192 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9193 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9194 int nallvars, /**< number of all variables */
9195 int nvars, /**< number of unfixed variables */
9196 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9197 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9198 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9199 )
9200{
9201 SCIP_Real maxerror;
9202 SCIP_Real facetval;
9203 SCIP_Real funval;
9204 SCIP_Real error;
9205 unsigned int i;
9206 unsigned int ncorners;
9207 unsigned int prev;
9208
9209 assert(scip != NULL);
9210 assert(funvals != NULL);
9211 assert(box != NULL);
9212 assert(nonfixedpos != NULL);
9213 assert(facetcoefs != NULL);
9214
9215 ncorners = POWEROFTWO(nvars);
9216 maxerror = 0.0;
9217
9218 /* check the origin (all variables at lower bound) */
9219 facetval = facetconstant;
9220 for( i = 0; i < (unsigned int) nallvars; ++i )
9221 facetval += facetcoefs[i] * box[2*i];
9222
9223 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9224 funval = funvals[0];
9225 if( overestimate )
9226 error = funval - facetval;
9227 else
9228 error = facetval - funval;
9229
9230 /* update maximum error */
9231 maxerror = MAX(error, maxerror);
9232
9233 prev = 0;
9234 for( i = 1; i < ncorners; ++i )
9235 {
9236 unsigned int gray;
9237 unsigned int diff;
9238 unsigned int pos;
9239 int origpos;
9240
9241 gray = i ^ (i >> 1);
9242 diff = gray ^ prev;
9243
9244 /* compute position of unique 1 of diff */
9245 pos = 0;
9246 while( (diff >>= 1) != 0 )
9247 ++pos;
9248 assert(pos < (unsigned int)nvars);
9249
9250 origpos = nonfixedpos[pos];
9251
9252 if( gray > prev )
9253 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9254 else
9255 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9256
9257 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9258 funval = funvals[gray];
9259 if( overestimate )
9260 error = funval - facetval;
9261 else
9262 error = facetval - funval;
9263
9264 /* update maximum error */
9265 maxerror = MAX(error, maxerror);
9266
9267 prev = gray;
9268 }
9269
9270 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9271
9272 return maxerror;
9273}
9274
9275/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9276static
9278 SCIP* scip, /**< SCIP data structure */
9279 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9280 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9281 SCIP_Real* xstar, /**< point to be separated */
9282 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9283 int nallvars, /**< half of the length of box */
9284 int* nonfixedpos, /**< indices of nonfixed variables */
9285 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9286 int nvars, /**< number of nonfixed variables */
9287 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9288 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9289 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9290 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9291 )
9292{ /*lint --e{715}*/
9293 SCIP_CONSHDLRDATA* conshdlrdata;
9294 SCIP_LPI* lp;
9295 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9296 int* inds;
9297 int ncols;
9298 int nrows;
9299 int i;
9300 SCIP_Real facetvalue;
9301 SCIP_Real mindomwidth;
9302 SCIP_RETCODE lpsolveretcode;
9303
9304 assert(scip != NULL);
9305 assert(conshdlr != NULL);
9306 assert(xstar != NULL);
9307 assert(box != NULL);
9308 assert(nonfixedpos != NULL);
9309 assert(funvals != NULL);
9310 assert(nvars >= 0);
9311 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9312 assert(success != NULL);
9313 assert(facetcoefs != NULL);
9314 assert(facetconstant != NULL);
9315
9316 *success = FALSE;
9317
9318 conshdlrdata = SCIPconshdlrGetData(conshdlr);
9319 assert(conshdlrdata != NULL);
9320
9321 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9322 {
9323 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9324 }
9325
9326 /* construct an LP for this size, if not having one already */
9327 if( conshdlrdata->vp_lp[nvars] == NULL )
9328 {
9329 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9330 }
9331 lp = conshdlrdata->vp_lp[nvars];
9332 assert(lp != NULL);
9333
9334 /* get number of cols and rows of separation lp */
9335 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9336 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9337
9338 /* number of columns should equal the number of corners = 2^nvars */
9339 assert(ncols == (int)POWEROFTWO(nvars));
9340
9341 /* allocate necessary memory */
9342 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9343 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9344
9345 /*
9346 * set up the described LP on the transformed space
9347 */
9348
9349 for( i = 0; i < ncols; ++i )
9350 inds[i] = i;
9351
9352 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9353 mindomwidth = 2*SCIPinfinity(scip);
9354 for( i = 0; i < nrows-1; ++i )
9355 {
9356 SCIP_Real solval;
9357 SCIP_Real lb;
9358 SCIP_Real ub;
9359 int varpos;
9360
9361 assert(i < nvars);
9362
9363 varpos = nonfixedpos[i];
9364 lb = box[2 * varpos];
9365 ub = box[2 * varpos + 1];
9366 solval = xstar[varpos];
9367
9368 if( ub - lb < mindomwidth )
9369 mindomwidth = ub - lb;
9370
9371 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9372 if( solval <= lb )
9373 aux[i] = 0.0;
9374 else if( solval >= ub )
9375 aux[i] = 1.0;
9376 else
9377 aux[i] = (solval - lb) / (ub - lb);
9378
9379 /* perturb point to hopefully obtain a facet of the convex envelope */
9380 if( conshdlrdata->vp_maxperturb > 0.0 )
9381 {
9382 assert(conshdlrdata->vp_randnumgen != NULL);
9383
9384 if( aux[i] == 1.0 )
9385 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9386 else if( aux[i] == 0.0 )
9387 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9388 else
9389 {
9390 SCIP_Real perturbation;
9391
9392 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9393 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9394 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9395 }
9396 assert(0.0 < aux[i] && aux[i] < 1.0);
9397 }
9398
9399 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9400 }
9401
9402 /* update LP */
9403 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9404 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9406
9407 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9408 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9409 {
9410 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9411 }
9412 /* set an iteration limit so we do not run forever */
9414 /* since we work with the dual of the LP, primal feastol determines how much we want the computed facet to be the best possible one */
9416 /* since we work with the dual of the LP, dual feastol determines validity of the facet
9417 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9418 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9419 */
9421
9422#ifdef SCIP_DEBUG
9424#endif
9425
9426 /*
9427 * solve the LP and store the resulting facet for the transformed space
9428 */
9429 if( conshdlrdata->vp_dualsimplex )
9430 {
9431 lpsolveretcode = SCIPlpiSolveDual(lp);
9432 }
9433 else
9434 {
9435 lpsolveretcode = SCIPlpiSolvePrimal(lp);
9436 }
9437 if( lpsolveretcode == SCIP_LPERROR )
9438 {
9439 SCIPdebugMsg(scip, "LP error, aborting.\n");
9440 goto CLEANUP;
9441 }
9442 SCIP_CALL( lpsolveretcode );
9443
9444 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9445 if( !SCIPlpiIsDualFeasible(lp) )
9446 {
9447 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9448 goto CLEANUP;
9449 }
9450
9451 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9452 * columns than needed, in particular, \bar \beta is the last dual multiplier
9453 */
9454 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9455
9456 for( i = 0; i < nvars; ++i )
9457 facetcoefs[nonfixedpos[i]] = aux[i];
9458 /* last dual multiplier is the constant */
9459 *facetconstant = aux[nrows - 1];
9460
9461#ifdef SCIP_DEBUG
9462 SCIPdebugMsg(scip, "facet for the transformed problem: ");
9463 for( i = 0; i < nallvars; ++i )
9464 {
9465 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9466 }
9467 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9468#endif
9469
9470 /*
9471 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9472 */
9473
9474 SCIPdebugMsg(scip, "facet in orig. space: ");
9475
9476 facetvalue = 0.0;
9477 for( i = 0; i < nvars; ++i )
9478 {
9479 SCIP_Real lb;
9480 SCIP_Real ub;
9481 int varpos;
9482
9483 varpos = nonfixedpos[i];
9484 lb = box[2 * varpos];
9485 ub = box[2 * varpos + 1];
9486 assert(!SCIPisEQ(scip, lb, ub));
9487
9488 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9489 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9490
9491 /* beta = beta_bar - sum_i alpha_i * lb_i */
9492 *facetconstant -= facetcoefs[varpos] * lb;
9493
9494 /* evaluate */
9495 facetvalue += facetcoefs[varpos] * xstar[varpos];
9496
9497 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9498 }
9499 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9500
9501 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9502 facetvalue += *facetconstant;
9503
9504 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9505
9506 /* if overestimate, then we want facetvalue < targetvalue
9507 * if underestimate, then we want facetvalue > targetvalue
9508 * if none holds, give up
9509 * so maybe here we should check against the minimal violation
9510 */
9511 if( overestimate == (facetvalue > targetvalue) )
9512 {
9513 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9514 goto CLEANUP;
9515 }
9516
9517 /* if we made it until here, then we have a nice facet */
9518 *success = TRUE;
9519
9520CLEANUP:
9521 /* free allocated memory */
9522 SCIPfreeBufferArray(scip, &inds);
9524
9525 return SCIP_OKAY;
9526}
9527
9528/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9529 *
9530 * In other words, compute the line that passes through two given points.
9531 */
9532static
9534 SCIP* scip, /**< SCIP data structure */
9535 SCIP_Real left, /**< left coordinate */
9536 SCIP_Real right, /**< right coordinate */
9537 SCIP_Real funleft, /**< value of function in left coordinate */
9538 SCIP_Real funright, /**< value of function in right coordinate */
9539 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9540 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9541 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9542 )
9543{
9544 assert(scip != NULL);
9545 assert(SCIPisLE(scip, left, right));
9546 assert(!SCIPisInfinity(scip, -left));
9547 assert(!SCIPisInfinity(scip, right));
9548 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9549 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9550 assert(success != NULL);
9551 assert(facetcoef != NULL);
9552 assert(facetconstant != NULL);
9553
9554 *facetcoef = (funright - funleft) / (right - left);
9555 *facetconstant = funleft - *facetcoef * left;
9556
9557 *success = TRUE;
9558
9559 return SCIP_OKAY;
9560}
9561
9562/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9563 *
9564 * Three points a, b, and c are given.
9565 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9566 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9567 */
9568static
9570 SCIP* scip, /**< SCIP data structure */
9571 SCIP_Real a1, /**< first coordinate of a */
9572 SCIP_Real a2, /**< second coordinate of a */
9573 SCIP_Real a3, /**< third coordinate of a */
9574 SCIP_Real b1, /**< first coordinate of b */
9575 SCIP_Real b2, /**< second coordinate of b */
9576 SCIP_Real b3, /**< third coordinate of b */
9577 SCIP_Real c1, /**< first coordinate of c */
9578 SCIP_Real c2, /**< second coordinate of c */
9579 SCIP_Real c3, /**< third coordinate of c */
9580 SCIP_Real* alpha, /**< coefficient of first coordinate */
9581 SCIP_Real* beta, /**< coefficient of second coordinate */
9582 SCIP_Real* gamma_, /**< coefficient of third coordinate */
9583 SCIP_Real* delta /**< constant right-hand side */
9584 )
9585{
9586 assert(scip != NULL);
9587 assert(alpha != NULL);
9588 assert(beta != NULL);
9589 assert(gamma_ != NULL);
9590 assert(delta != NULL);
9591
9592 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9593 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9594 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9595 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9596
9597 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9598
9599 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9600 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9601 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9602 {
9603 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9604 *delta = 0.0;
9605 *alpha = 0.0;
9606 *beta = 0.0;
9607 *gamma_ = 0.0;
9608 return SCIP_OKAY;
9609 }
9610
9611 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9612 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9613 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9614 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9615 {
9616 SCIP_Real m[9];
9617 SCIP_Real rhs[3];
9618 SCIP_Real x[3];
9619 SCIP_Bool success;
9620
9621 /*
9622 SCIPdebugMsg(scip, "a = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", a1, a2, a3, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3, SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3));
9623 SCIPdebugMsg(scip, "b = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", b1, b2, b3, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3, SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3));
9624 SCIPdebugMsg(scip, "c = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", c1, c2, c3, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3, SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3));
9625 */
9626
9627 /* initialize matrix column-wise */
9628 m[0] = a1;
9629 m[1] = b1;
9630 m[2] = c1;
9631 m[3] = a2;
9632 m[4] = b2;
9633 m[5] = c2;
9634 m[6] = a3;
9635 m[7] = b3;
9636 m[8] = c3;
9637
9638 rhs[0] = 1.0;
9639 rhs[1] = 1.0;
9640 rhs[2] = 1.0;
9641
9642 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9643
9644 /* solve the linear problem */
9645 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9646
9647 *delta = rhs[0];
9648 *alpha = x[0];
9649 *beta = x[1];
9650 *gamma_ = x[2];
9651
9652 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9653 * not add a cut to SCIP and that all assertions are trivially fulfilled
9654 */
9655 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9656 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9657 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9658 {
9659 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9660 *delta = 0.0;
9661 *alpha = 0.0;
9662 *beta = 0.0;
9663 *gamma_ = 0.0;
9664 }
9665 }
9666
9667 if( *gamma_ < 0.0 )
9668 {
9669 *alpha = -*alpha;
9670 *beta = -*beta;
9671 *gamma_ = -*gamma_;
9672 *delta = -*delta;
9673 }
9674
9675 return SCIP_OKAY;
9676}
9677
9678/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9679static
9681 SCIP* scip, /**< SCIP data structure */
9682 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9683 SCIP_Real p1[2], /**< first vertex of box */
9684 SCIP_Real p2[2], /**< second vertex of box */
9685 SCIP_Real p3[2], /**< third vertex of box */
9686 SCIP_Real p4[2], /**< forth vertex of box */
9687 SCIP_Real p1val, /**< value in p1 */
9688 SCIP_Real p2val, /**< value in p2 */
9689 SCIP_Real p3val, /**< value in p3 */
9690 SCIP_Real p4val, /**< value in p4 */
9691 SCIP_Real xstar[2], /**< point to be separated */
9692 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9693 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9694 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9695 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9696 )
9697{
9698 SCIP_Real alpha, beta, gamma_, delta;
9699 SCIP_Real xstarval, candxstarval = 0.0;
9700 int leaveout;
9701
9702 assert(scip != NULL);
9703 assert(success != NULL);
9704 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9705 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9706 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9707 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9708 assert(facetcoefs != NULL);
9709 assert(facetconstant != NULL);
9710
9711 *success = FALSE;
9712
9713 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9714 if( !overestimate )
9715 {
9716 p1val = -p1val;
9717 p2val = -p2val;
9718 p3val = -p3val;
9719 p4val = -p4val;
9720 targetvalue = -targetvalue;
9721 }
9722
9723 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9724 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9725 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9726 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9727
9728 /* Compute coefficients alpha, beta, gamma (>0), delta such that
9729 * alpha*x + beta*y + gamma*z = delta
9730 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9731 * the fourth corner point lies below this hyperplane.
9732 * Since we assume that f is vertex-polyhedral, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
9733 * alpha*x + beta*y - delta <= -gamma * f(x,y),
9734 * or, equivalently,
9735 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9736 */
9737 for( leaveout = 1; leaveout <= 4; ++leaveout )
9738 {
9739 switch( leaveout)
9740 {
9741 case 1 :
9742 /* get hyperplane through p2, p3, p4 */
9743 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9744 &alpha, &beta, &gamma_, &delta) );
9745 /* if not underestimating in p1, then go to next candidate */
9746 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9747 continue;
9748 break;
9749
9750 case 2 :
9751 /* get hyperplane through p1, p3, p4 */
9752 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9753 &alpha, &beta, &gamma_, &delta) );
9754 /* if not underestimating in p2, then go to next candidate */
9755 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9756 continue;
9757 break;
9758
9759 case 3 :
9760 /* get hyperplane through p1, p2, p4 */
9761 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9762 &alpha, &beta, &gamma_, &delta) );
9763 /* if not underestimating in p3, then go to next candidate */
9764 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9765 continue;
9766 break;
9767
9768 case 4 :
9769 /* get hyperplane through p1, p2, p3 */
9770 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9771 &alpha, &beta, &gamma_, &delta) );
9772 /* if not underestimating in p4, then stop */
9773 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9774 continue;
9775 break;
9776
9777 default: /* only for lint */
9778 alpha = SCIP_INVALID;
9779 beta = SCIP_INVALID;
9780 gamma_ = SCIP_INVALID;
9781 delta = SCIP_INVALID;
9782 break;
9783 }
9784
9785 /* check if bad luck: should not happen if numerics are fine */
9786 if( SCIPisZero(scip, gamma_) )
9787 continue;
9788 assert(!SCIPisNegative(scip, gamma_));
9789
9790 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9791 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9792 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9793 continue;
9794
9795 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9796
9797 /* value of hyperplane candidate in xstar */
9798 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9799
9800 /* if reaching target and first or better than previous candidate, then update */
9801 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9802 {
9803 /* flip hyperplane */
9804 if( !overestimate )
9805 gamma_ = -gamma_;
9806
9807 facetcoefs[0] = -alpha/gamma_;
9808 facetcoefs[1] = -beta/gamma_;
9809 *facetconstant = delta/gamma_;
9810
9811 *success = TRUE;
9812 candxstarval = xstarval;
9813 }
9814 }
9815
9816 return SCIP_OKAY;
9817}
9818
9819/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9820 * graph yet) in an array
9821 */
9822static
9824 SCIP* scip, /**< SCIP pointer */
9825 int** openidx, /**< address of openidx array */
9826 int nelems, /**< number of elements that need to be stored */
9827 int* maxnelems /**< pointer to store maximum number that can be stored */
9828 )
9829{
9830 assert(scip != NULL);
9831 assert(openidx != NULL);
9832 assert(maxnelems != NULL);
9833
9834 if( nelems > *maxnelems )
9835 {
9836 int newsize;
9837
9838 newsize = SCIPcalcMemGrowSize(scip, nelems);
9839 assert(newsize >= nelems);
9840
9841 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9842
9843 *maxnelems = newsize;
9844 }
9845
9846 return SCIP_OKAY;
9847}
9848
9849/** ensures that we can store information about local variables in an array */
9850static
9852 SCIP* scip, /**< SCIP pointer */
9853 SCIP_VAR*** vars, /**< address of variable array */
9854 SCIP_Real** vals, /**< address of value array */
9855 int nelems, /**< number of elements that need to be stored */
9856 int* maxnelems /**< pointer to store maximum number that can be stored */
9857 )
9858{
9859 assert(scip != NULL);
9860 assert(vars != NULL);
9861 assert(vals != NULL);
9862 assert(maxnelems != NULL);
9863
9864 if( nelems > *maxnelems )
9865 {
9866 int newsize;
9867
9868 newsize = SCIPcalcMemGrowSize(scip, nelems);
9869 assert(newsize > *maxnelems);
9870
9871 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
9872 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9873
9874 *maxnelems = newsize;
9875 }
9876
9877 return SCIP_OKAY;
9878}
9879
9880/** tries to add gadget for finding signed permutations of bilinear products
9881 *
9882 * If a product has exactly two children being variables, negating both simultanteoulsy
9883 * is a signed permutation.
9884 */
9885static
9887 SCIP* scip, /**< SCIP pointer */
9888 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9889 SCIP_CONS* cons, /**< constraint containing product expression */
9890 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9891 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9892 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9893 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9894 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9895 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9896 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9897 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9898 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9899 )
9900{
9901 SYM_EXPRDATA* symdata;
9902 SCIP_EXPR** children;
9903 SCIP_VAR* var1 = NULL;
9904 SCIP_VAR* var2 = NULL;
9905 SCIP_Real val1 = 0.0;
9906 SCIP_Real val2 = 0.0;
9907 SCIP_Real coef;
9908 SCIP_Real prodval;
9909 SCIP_Real constant;
9910 int nlocvars;
9911 int optype;
9912 int nchildren;
9913 int prodidx;
9914 int coefidx1;
9915 int coefidx2;
9916 int childidx;
9917
9918 assert(scip != NULL);
9919 assert(expr != NULL);
9920 assert(SCIPisExprProduct(scip, expr));
9921 assert(graph != NULL);
9922 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9923 assert(consvars != NULL);
9924 assert(consvals != NULL);
9925 assert(maxnconsvars != NULL);
9926 assert(*maxnconsvars > 0);
9927 assert(handledexprs != NULL);
9928 assert(success != NULL);
9929
9930 *success = FALSE;
9931
9932 /* we require exactly two children being variables */
9933 nchildren = SCIPexprGetNChildren(expr);
9934 if( nchildren != 2 )
9935 return SCIP_OKAY;
9936
9937 children = SCIPexprGetChildren(expr);
9938 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9939 return SCIP_OKAY;
9940
9941 /* check whether each child is not multi-aggregated and is not shifted */
9942 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9943
9944 for( childidx = 0; childidx < 2; ++childidx )
9945 {
9946 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9947 (*consvals)[0] = 1.0;
9948 nlocvars = 1;
9949 constant = 0.0;
9950
9951 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9952 &constant, SCIPconsIsTransformed(cons)) );
9953
9954 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9955 return SCIP_OKAY;
9956
9957 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9958 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9959 return SCIP_OKAY;
9960
9961 /* store information about variables */
9962 if( childidx == 0 )
9963 {
9964 var1 = (*consvars)[0];
9965 val1 = (*consvals)[0];
9966 }
9967 else
9968 {
9969 var2 = (*consvars)[0];
9970 val2 = (*consvals)[0];
9971 }
9972 }
9973 assert(var1 != NULL);
9974 assert(var2 != NULL);
9975
9976 /* store the we handle the children */
9977 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9978 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9979
9980 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9981 assert(symdata != NULL);
9982 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9983
9984 coef = SCIPgetSymExprdataConstants(symdata)[0];
9985
9986 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9987
9988 /* add gadget modeling the product
9989 *
9990 * Since the constants are 0, each variable is centered at the origin, which leads to
9991 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9992 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9993 * negate both variables simulataneously.
9994 */
9996 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9997 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9998
9999 prodval = coef * val1 * val2;
10000
10001 /* introduce nodes for the product value and its negation; since flipping both variables
10002 * simultaneously is a signed symmetry, assign both nodes the same value
10003 */
10004 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
10005 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
10006
10007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
10008 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
10009 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
10010
10011 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10012 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10013 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
10014 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10015 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10016 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
10017 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
10018 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
10019
10020 *success = TRUE;
10021
10022 return SCIP_OKAY;
10023}
10024
10025/** returns whether an operator is even and, if yes, stores data about operator */
10026static
10028 SCIP* scip, /**< SCIP pointer */
10029 SCIP_EXPR* expr, /**< expression corresponding to operator */
10030 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
10031 * needed for symmetry computation */
10032 SCIP_Real* value /**< pointer to store value for symmetry computation */
10033 )
10034{
10035 SYM_EXPRDATA* symdata;
10036
10037 assert(scip != NULL);
10038 assert(expr != NULL);
10039 assert(hasvalue != NULL);
10040 assert(value != NULL);
10041
10042 /* check for different operators known to be even */
10043 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
10044 {
10045 /* get remaining information needed for symmetry detection */
10046 if( SCIPisExprSignpower(scip, expr) )
10047 {
10048 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10049 assert(symdata != NULL);
10050 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10051
10052 *value = SCIPgetSymExprdataConstants(symdata)[0];
10053 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
10054
10056 }
10057 else
10058 {
10059 assert(SCIPisExprCos(scip, expr));
10060 *hasvalue = FALSE;
10061 }
10062
10063 return TRUE;
10064 }
10065 else if( SCIPisExprPower(scip, expr) )
10066 {
10067 SCIP_Real exponent;
10068 int safeexponent;
10069
10070 /* only consider expressions corresponding to an even power */
10071 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
10072 assert(symdata != NULL);
10073 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10074
10075 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10077
10078 /* check whether the exponent is an even integer */
10079 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
10080 return FALSE;
10081
10082 /* deal with numerics */
10083 safeexponent = (int) (exponent + 0.5);
10084 if( safeexponent % 2 != 0 )
10085 return FALSE;
10086
10087 *hasvalue = TRUE;
10088 *value = exponent;
10089
10090 return TRUE;
10091 }
10092 else if( SCIPisExprAbs(scip, expr) )
10093 {
10094 *hasvalue = FALSE;
10095
10096 return TRUE;
10097 }
10098
10099 return FALSE;
10100}
10101
10102/** returns whether a variable is centered at 0 */
10103static
10105 SCIP* scip, /**< SCIP pointer */
10106 SCIP_VAR* var /**< variable to be checked */
10107 )
10108{
10109 assert(scip != NULL);
10110 assert(var != NULL);
10111
10113 return FALSE;
10114
10116 return TRUE;
10117
10119 return TRUE;
10120
10121 return FALSE;
10122}
10123
10124/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
10125static
10127 SCIP* scip, /**< SCIP pointer */
10128 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10129 SCIP_EXPR* child, /**< child expression of evenopexpr */
10130 SCIP_CONS* cons, /**< constraint containing expression */
10131 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10132 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10133 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10134 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10135 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10136 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10137 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10138 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10139 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10140 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10141 )
10142{
10143 SCIP_VAR* var;
10144 SCIP_Real constant;
10145 SCIP_Real edgeweight;
10146 int nlocvars;
10147 int nodeidx;
10148 int optype;
10149 int thisopidx;
10150
10151 assert(scip != NULL);
10152 assert(evenopexpr != NULL);
10153 assert(child != NULL);
10154 assert(SCIPisExprVar(scip, child));
10155 assert(cons != NULL);
10156 assert(graph != NULL);
10157 assert(parentidx >= 0);
10158 assert(consvars != NULL);
10159 assert(consvals != NULL);
10160 assert(maxnconsvars != NULL);
10161 assert(success != NULL);
10162
10163 *success = FALSE;
10164
10165 /* check whether child variable is (multi-)aggregated */
10166 var = SCIPgetVarExprVar(child);
10167 (*consvars)[0] = var;
10168 (*consvals)[0] = 1.0;
10169 constant = 0.0;
10170 nlocvars = 1;
10171
10172 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10173 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10174 SCIPconsIsTransformed(cons)) );
10175
10176 /* skip multi-aggregated variables or variables with domain not centered at 0 */
10177 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10178 return SCIP_OKAY;
10179
10180 if( !varIsCenteredAt0(scip, var) )
10181 return SCIP_OKAY;
10182
10183 /* store partial information for gadget */
10184 var = (*consvars)[0];
10185 edgeweight = (*consvals)[0];
10186
10187 /* add gadget to graph for even univariate expression */
10188 *success = TRUE;
10189
10191
10192 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10193 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10194
10195 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10196 TRUE, edgeweight) );
10198 TRUE, edgeweight) );
10199
10200 if( hassymval )
10201 {
10202 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10203 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10204 }
10205
10206 return SCIP_OKAY;
10207}
10208
10209/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10210static
10212 SCIP* scip, /**< SCIP pointer */
10213 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10214 SCIP_EXPR* child, /**< child expression of evenopexpr */
10215 SCIP_CONS* cons, /**< constraint containing expression */
10216 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10217 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10218 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10219 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10220 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10221 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10222 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10223 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10224 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10225 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10226 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10227 )
10228{
10229 SCIP_VAR* var;
10230 SCIP_Real constant;
10231 SCIP_Real weight;
10232 int nlocvars;
10233 int nodeidx;
10234 int optype;
10235 int thisopidx;
10236 int i;
10237
10238 assert(scip != NULL);
10239 assert(evenopexpr != NULL);
10240 assert(child != NULL);
10241 assert(SCIPisExprSum(scip, child));
10242 assert(cons != NULL);
10243 assert(graph != NULL);
10244 assert(parentidx >= 0);
10245 assert(consvars != NULL);
10246 assert(consvals != NULL);
10247 assert(maxnconsvars != NULL);
10248 assert(handledexprs != NULL);
10249 assert(success != NULL);
10250
10251 *success = FALSE;
10252
10253 /* check whether child variable is (multi-)aggregated and whether all children are variables */
10254 nlocvars = SCIPexprGetNChildren(child);
10255
10256 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10257
10258 for( i = 0; i < nlocvars; ++i)
10259 {
10260 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10261 {
10262 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10263 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10264 }
10265 else
10266 return SCIP_OKAY;
10267 }
10268 constant = SCIPgetConstantExprSum(child);
10269
10270 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10271 SCIPconsIsTransformed(cons)) );
10272
10273 /* we can only handle the case without constant and two variables with domain centered at origin */
10274 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10275 return SCIP_OKAY;
10276 assert(nlocvars > 0);
10277
10278 var = (*consvars)[0];
10279 if( !varIsCenteredAt0(scip, var) )
10280 return SCIP_OKAY;
10281
10282 if( nlocvars == 2 )
10283 {
10284 var = (*consvars)[1];
10285 if( !varIsCenteredAt0(scip, var) )
10286 return SCIP_OKAY;
10287 }
10288
10289 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10290 *success = TRUE;
10291 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10292 {
10293 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10294 }
10295
10297
10298 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10299 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10300
10301 if( hassymval )
10302 {
10303 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10304 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10305 }
10306
10307 if( nlocvars == 1 )
10308 {
10309 var = (*consvars)[0];
10310 weight = (*consvals)[0];
10311
10312 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10313 TRUE, weight) );
10315 TRUE, weight) );
10316 }
10317 else
10318 {
10319 int dummyidx1;
10320 int dummyidx2;
10321
10322 /* add dummy nodes for gadget */
10323 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10324 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10325
10326 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10327 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10328 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10329
10330 /* connect dummy nodes with variables */
10331 for( i = 0; i < 2; ++i)
10332 {
10333 var = (*consvars)[i];
10334 weight = ABS((*consvals)[i]);
10335
10336 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10337 TRUE, weight) );
10339 TRUE, weight) );
10340 }
10341 }
10342
10343 return SCIP_OKAY;
10344}
10345
10346/** tries to add gadget for finding signed permutations of even univariate operators
10347 *
10348 * We handle two cases. First, if a univariate operator is even and has a variable
10349 * as child, negating the child is signed permutation. Second, the univariate operator
10350 * is even and has a weighted sum of two variables as child.
10351 */
10352static
10354 SCIP* scip, /**< SCIP pointer */
10355 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10356 SCIP_CONS* cons, /**< constraint containing expression */
10357 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10358 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10359 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10360 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10361 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10362 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10363 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10364 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10365 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10366 )
10367{
10368 SCIP_EXPR* child;
10369 SCIP_Real val = 0.0;
10370 SCIP_Bool hasval = FALSE;
10371
10372 assert(scip != NULL);
10373 assert(expr != NULL);
10374 assert(graph != NULL);
10375 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10376 assert(consvars != NULL);
10377 assert(consvals != NULL);
10378 assert(maxnconsvars != NULL);
10379 assert(*maxnconsvars > 0);
10380 assert(handledexprs != NULL);
10381 assert(success != NULL);
10382
10383 *success = FALSE;
10384
10385 /* ignore variable or value expressions */
10386 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10387 return SCIP_OKAY;
10388 assert(SCIPexprGetNChildren(expr) > 0);
10389
10390 /* ignore operators with too many children */
10391 if( SCIPexprGetNChildren(expr) > 1 )
10392 return SCIP_OKAY;
10393
10394 /* check whether operator is even */
10395 if( !isEvenOperator(scip, expr, &hasval, &val) )
10396 return SCIP_OKAY;
10397
10398 /* we can only treat the operator if its child is a variable or a sum */
10399 child = SCIPexprGetChildren(expr)[0];
10400 if( SCIPisExprVar(scip, child) )
10401 {
10402 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10403 hasval, val, consvars, consvals, maxnconsvars, success) );
10404 }
10405 else if( SCIPisExprSum(scip, child) )
10406 {
10407 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10408 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10409 }
10410
10411 if( *success )
10412 {
10413 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10414 }
10415
10416 return SCIP_OKAY;
10417}
10418
10419/** compares two variable pointers */
10420static
10422{ /*lint --e{715}*/
10423 SCIP_VAR** vars;
10424 SCIP_VAR* var1;
10425 SCIP_VAR* var2;
10426
10427 vars = (SCIP_VAR**) dataptr;
10428
10429 var1 = vars[ind1];
10430 var2 = vars[ind2];
10431 assert(var1 != NULL);
10432 assert(var2 != NULL);
10433
10434 /* sort variables by their unique index */
10435 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10436 return -1;
10437 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10438 return 1;
10439
10440 return 0;
10441}
10442
10443/** gets domain center of a variable which has not semi-infinite domain */
10444static
10446 SCIP* scip, /**< SCIP pointer */
10447 SCIP_VAR* var /**< variable */
10448 )
10449{
10450 SCIP_Real ub;
10451 SCIP_Real lb;
10452
10453 ub = SCIPvarGetUbGlobal(var);
10454 lb = SCIPvarGetLbGlobal(var);
10455
10456 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10457
10458 if ( SCIPisInfinity(scip, ub) )
10459 return 0.0;
10460
10461 return (ub + lb) / 2;
10462}
10463
10464/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10465static
10467 SCIP* scip, /**< SCIP pointer */
10468 SCIP_EXPR* sumexpr, /**< sum expression */
10469 SCIP_CONS* cons, /**< constraint containing the sum expression */
10470 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10471 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10472 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10473 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10474 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10475 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10476 )
10477{
10478 SYM_EXPRDATA* symdata;
10479 SCIP_EXPR** children;
10480 SCIP_EXPR** powexprs;
10481 SCIP_EXPR** prodexprs;
10482 SCIP_EXPR* child;
10483 SCIP_VAR** powvars;
10484 SCIP_VAR** prodvars;
10485 SCIP_VAR* actvar;
10486 SCIP_VAR* actvar2;
10487 SCIP_VAR* var;
10488 SCIP_VAR* var2;
10489 SCIP_Real* sumcoefs;
10490 SCIP_Real constant;
10491 SCIP_Real constant2;
10492 SCIP_Real val;
10493 SCIP_Real val2;
10494 SCIP_Bool* powexprused = NULL;
10495 int* powperm = NULL;
10496 int* prodperm = NULL;
10497 int nchildren;
10498 int nlocvars;
10499 int nodeidx;
10500 int coefnodeidx1;
10501 int coefnodeidx2;
10502 int cnt;
10503 int i;
10504 int j;
10505 int nterms;
10506 int npowexprs = 0;
10507 int nprodexprs = 0;
10508 int powcoef = 0;
10509
10510 assert(scip != NULL);
10511 assert(sumexpr != NULL);
10512 assert(cons != NULL);
10513 assert(SCIPisExprSum(scip, sumexpr));
10514 assert(consvars != NULL);
10515 assert(consvals != NULL);
10516 assert(maxnconsvars != NULL);
10517 assert(*maxnconsvars > 0);
10518 assert(handledexprs != NULL);
10519
10520 /* iterate over sum expression and extract all power and product expressions */
10521 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10522 children = SCIPexprGetChildren(sumexpr);
10523 nchildren = SCIPexprGetNChildren(sumexpr);
10524 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10525 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10526 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10527 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10528
10529 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10530 /** @todo make this work in a more general case */
10531 for( i = 0; i < nchildren; ++i )
10532 {
10533 if( SCIPisExprPower(scip, children[i]) )
10534 {
10535 SCIP_Real exponent;
10536
10537 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10538 if( powcoef == 0 )
10539 {
10540 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10541 powcoef = (int) SCIPround(scip, sumcoefs[i]);
10542 }
10543 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10544 continue;
10545
10546 /* we only store power expressions if their child is a variable */
10547 assert(SCIPexprGetNChildren(children[i]) == 1);
10548 child = SCIPexprGetChildren(children[i])[0];
10549 if( !SCIPisExprVar(scip, child) )
10550 continue;
10551
10552 /* the power is required to be a 2 */
10553 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10554 assert(symdata != NULL);
10555 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10556
10557 exponent = SCIPgetSymExprdataConstants(symdata)[0];
10558 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10559
10560 if( !SCIPisEQ(scip, exponent, 2.0) )
10561 continue;
10562
10563 /* we only store power expressions if the child is not multi-aggregated */
10564 var = SCIPgetVarExprVar(child);
10566 {
10567 powexprs[npowexprs] = children[i];
10568 powvars[npowexprs++] = var;
10569 }
10570 }
10571 else if( SCIPisExprProduct(scip, children[i]) )
10572 {
10573 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10574 if( powcoef == 0 )
10575 {
10576 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10577 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10578 }
10579 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10580 continue;
10581
10582 /* we only store power expressions if they have exactly two children being variables */
10583 if( SCIPexprGetNChildren(children[i]) != 2 )
10584 continue;
10585 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10586 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10587 continue;
10588
10589 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10590 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10591
10592 /* we only store product expressions if the children are not multi-aggregated */
10595 {
10596 prodexprs[nprodexprs] = children[i];
10597 prodvars[nprodexprs++] = var;
10598 prodexprs[nprodexprs] = children[i];
10599 prodvars[nprodexprs++] = var2;
10600 }
10601 }
10602 }
10603
10604 if( npowexprs == 0 || nprodexprs != npowexprs )
10605 goto FREEMEMORY;
10606
10607 /* check whether the power variables and product variables match */
10608 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10609 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10610
10611 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10612 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10613
10614 for( i = 0; i < npowexprs; ++i )
10615 {
10616 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10617 goto FREEMEMORY;
10618 }
10619
10620 /* if we reach this line, the variables match: we have found a potential norm constraint */
10621 assert(npowexprs % 2 == 0);
10622 nterms = npowexprs / 2;
10623 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10624
10625 /* add gadget of each squared difference term */
10626 cnt = 0;
10627 for( i = 0; i < nterms; ++i )
10628 {
10629 SCIP_Bool var1found = FALSE;
10630 SCIP_Bool var2found = FALSE;
10631
10632 (*consvals)[0] = 1.0;
10633 (*consvars)[0] = prodvars[cnt++];
10634 constant = 0.0;
10635 nlocvars = 1;
10636
10638 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10639
10640 if( nlocvars != 1 )
10641 {
10642 ++cnt;
10643 continue;
10644 }
10645 actvar = (*consvars)[0];
10646 val = (*consvals)[0];
10647
10648 (*consvals)[0] = 1.0;
10649 (*consvars)[0] = prodvars[cnt++];
10650 constant2 = 0.0;
10651 nlocvars = 1;
10652
10654 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10655
10656 if( nlocvars != 1 )
10657 continue;
10658 actvar2 = (*consvars)[0];
10659 val2 = (*consvals)[0];
10660
10661 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10662 * cannot be centered at the origin or they are not centered around the same point
10663 */
10664 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10668 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10669 continue;
10670
10671 /* add gadget */
10672 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10673 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10674 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10675
10676 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10677 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10678 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10679 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10680 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10681 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10682 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10683 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10684 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10685 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10686 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10687
10688 /* mark product expression as handled */
10689 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10690
10691 /* find corresponding unused power expressions and mark them as handled */
10692 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10693 {
10694 if( powexprused[j] )
10695 continue;
10696 assert(cnt >= 2);
10697
10698 if( !var1found && powvars[j] == prodvars[cnt - 2] )
10699 {
10700 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10701 powexprused[j] = TRUE;
10702 var1found = TRUE;
10703 }
10704 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10705 {
10706 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10707 powexprused[j] = TRUE;
10708 var2found = TRUE;
10709 }
10710 }
10711 }
10712
10713 FREEMEMORY:
10714 SCIPfreeBufferArrayNull(scip, &powexprused);
10715 SCIPfreeBufferArrayNull(scip, &prodperm);
10716 SCIPfreeBufferArrayNull(scip, &powperm);
10717 SCIPfreeBufferArray(scip, &prodvars);
10718 SCIPfreeBufferArray(scip, &powvars);
10719 SCIPfreeBufferArray(scip, &prodexprs);
10720 SCIPfreeBufferArray(scip, &powexprs);
10721
10722 return SCIP_OKAY;
10723}
10724
10725/** adds symmetry information of constraint to a symmetry detection graph */
10726static
10728 SCIP* scip, /**< SCIP pointer */
10729 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10730 SCIP_CONS* cons, /**< constraint */
10731 SYM_GRAPH* graph, /**< symmetry detection graph */
10732 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10733 )
10734{ /*lint --e{850}*/
10735 SCIP_EXPRITER* it;
10736 SCIP_HASHSET* handledexprs;
10737 SCIP_EXPR* rootexpr;
10738 SCIP_EXPR* expr;
10739 SCIP_VAR** consvars;
10740 SCIP_Real* consvals;
10741 SCIP_Real constant;
10742 SCIP_Real parentcoef = 0.0;
10743 int* openidx;
10744 int maxnopenidx;
10745 int parentidx;
10746 int nconsvars;
10747 int maxnconsvars;
10748 int nlocvars;
10749 int nopenidx = 0;
10750 int consnodeidx;
10751 int nodeidx;
10752 int i;
10753 SCIP_Bool iscolored;
10754 SCIP_Bool hasparentcoef;
10755
10756 assert(scip != NULL);
10757 assert(cons != NULL);
10758 assert(graph != NULL);
10759 assert(success != NULL);
10760
10761 /* store lhs/rhs */
10763 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10764
10765 rootexpr = SCIPgetExprNonlinear(cons);
10766 assert(rootexpr != NULL);
10767
10768 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10769 expr = SCIPgetExprNonlinear(cons);
10770 assert(expr != NULL);
10771
10775
10776 /* find potential number of nodes in graph */
10777 maxnopenidx = 0;
10778 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10779 {
10781 continue;
10782
10783 ++maxnopenidx;
10784 }
10785
10786 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10787
10788 maxnconsvars = SCIPgetNVars(scip);
10789 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10790 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10791
10792 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10793 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10794
10795 /* iterate over expression tree and store nodes/edges */
10796 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10799
10800 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10801 {
10802 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10803 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10804 {
10805 SCIP_EXPR* baseexpr;
10806
10807 baseexpr = expr;
10808 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10809 expr = SCIPexpriterGetNext(it);
10810
10811 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10812
10813 /* leave the expression */
10814 continue;
10815 }
10816
10817 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10819 {
10820 --nopenidx;
10821 continue;
10822 }
10824
10825 /* find parentidx */
10826 if( expr == rootexpr )
10827 parentidx = consnodeidx;
10828 else
10829 {
10830 assert(nopenidx >= 1);
10831 parentidx = openidx[nopenidx - 1];
10832 }
10833
10834 /* possibly find a coefficient assigned to the expression by the parent */
10835 hasparentcoef = FALSE;
10836 if ( expr != rootexpr )
10837 {
10838 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10839 }
10840
10841 /* deal with different kinds of expressions and store them in the symmetry data structure */
10842 if( SCIPisExprVar(scip, expr) )
10843 {
10844 /* needed to correctly reset value when leaving expression */
10845 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10846
10847 openidx[nopenidx++] = -1;
10848
10849 assert(maxnconsvars > 0);
10850 assert(parentidx > 0);
10851
10852 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10853 if( hasparentcoef )
10854 {
10855 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10856
10857 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10858 parentidx = nodeidx;
10859 }
10860
10861 /* connect (aggregation of) variable expression with its parent */
10862 nconsvars = 1;
10863 consvars[0] = SCIPgetVarExprVar(expr);
10864 consvals[0] = 1.0;
10865 constant = 0.0;
10866
10867 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10868 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10869
10870 /* check whether variable is aggregated */
10871 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10872 {
10873 int thisidx;
10874
10875 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10876 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10877
10878 parentidx = thisidx;
10879 }
10880 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10881 nconsvars, constant) );
10882 }
10883 else if( SCIPisExprValue(scip, expr) )
10884 {
10885 assert(parentidx > 0);
10886
10887 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10888
10889 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10890
10891 /* needed to correctly reset value when leaving expression */
10892 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10893
10894 openidx[nopenidx++] = -1;
10895 }
10896 else
10897 {
10898 SCIP_Bool usedefaultgadget = TRUE;
10899
10900 assert(expr == rootexpr || parentidx > 0);
10901 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10902
10903 if( SCIPisExprSum(scip, expr) )
10904 {
10905 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10906 SCIP_EXPR** children;
10907 int sumidx;
10908 int optype;
10909 int childidx;
10910
10911 /* sums are handled by a special gadget */
10912 usedefaultgadget = FALSE;
10913
10914 /* extract all children being variables and compute the sum of active variables expression */
10915 nlocvars = 0;
10916 children = SCIPexprGetChildren(expr);
10917
10918 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10919
10920 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10921 {
10922 if( !SCIPisExprVar(scip, children[childidx]) )
10923 continue;
10924
10925 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10926 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10927
10928 /* store that we have already handled this expression */
10929 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10930 }
10931
10932 constant = SCIPgetConstantExprSum(expr);
10933
10934 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10935 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10936
10938
10939 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10940 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10941
10942 /* add the linear part of the sum */
10943 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10944
10945 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10946
10947 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10948 if( symtype == SYM_SYMTYPE_SIGNPERM )
10949 {
10950 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10951 &consvars, &consvals, &maxnconsvars, handledexprs) );
10952 }
10953
10954 /* store sumidx for children that have not been treated */
10955 openidx[nopenidx++] = sumidx;
10956 }
10957 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10958 {
10959 SCIP_Bool succ;
10960
10961 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10962 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10963
10964 if( succ )
10965 {
10966 usedefaultgadget = FALSE;
10967 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10968 }
10969 }
10970 else if( symtype == SYM_SYMTYPE_SIGNPERM )
10971 {
10972 SCIP_Bool succ;
10973
10974 /* we can find more signed permutations for even univariate operators */
10975 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10976 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10977
10978 if( succ )
10979 {
10980 usedefaultgadget = FALSE;
10981 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10982 }
10983 }
10984
10985 if( usedefaultgadget )
10986 {
10987 int opidx;
10988 int optype;
10989
10991 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10992 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10993
10994 /* possibly add constants of expression */
10996 {
10997 SYM_EXPRDATA* symdata;
10998
10999 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
11000 assert(symdata != NULL);
11001
11002 /* if expression has multiple constants, assign colors to edges to distinguish them */
11003 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
11004 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
11005 {
11006 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
11007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
11008 }
11009
11010 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
11011 }
11012
11013 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
11014
11015 openidx[nopenidx++] = opidx;
11016 }
11017 }
11018 }
11019
11020 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
11021 SCIPfreeBufferArray(scip, &consvals);
11022 SCIPfreeBufferArray(scip, &consvars);
11023 SCIPfreeBufferArray(scip, &openidx);
11024 SCIPfreeExpriter(&it);
11025
11026 *success = TRUE;
11027
11028 return SCIP_OKAY;
11029}
11030
11031/*
11032 * Callback methods of constraint handler
11033 */
11034
11035/** copy method for constraint handler plugins (called when SCIP copies plugins) */
11036static
11037SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
11038{ /*lint --e{715}*/
11039 SCIP_CONSHDLR* targetconshdlr;
11040 SCIP_CONSHDLRDATA* sourceconshdlrdata;
11041 int i;
11042
11043 assert(scip != NULL);
11044 assert(conshdlr != NULL);
11045 assert(valid != NULL);
11046 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11047
11048 /* create basic data of constraint handler and include it to scip */
11050
11051 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11052 assert(targetconshdlr != NULL);
11053 assert(targetconshdlr != conshdlr);
11054
11055 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
11056 assert(sourceconshdlrdata != NULL);
11057
11058 /* copy nonlinear handlers */
11059 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
11060 {
11061 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
11062 }
11063
11064 *valid = TRUE;
11065
11066 return SCIP_OKAY;
11067}
11068
11069/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11070static
11071SCIP_DECL_CONSFREE(consFreeNonlinear)
11072{ /*lint --e{715}*/
11073 SCIP_CONSHDLRDATA* conshdlrdata;
11074 int i;
11075
11076 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11077 assert(conshdlrdata != NULL);
11078
11079 /* free nonlinear handlers */
11080 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11081 {
11082 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
11083 assert(conshdlrdata->nlhdlrs[i] == NULL);
11084 }
11085 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
11086 conshdlrdata->nlhdlrssize = 0;
11087
11088 /* free upgrade functions */
11089 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
11090 {
11091 assert(conshdlrdata->consupgrades[i] != NULL);
11092 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
11093 }
11094 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
11095
11096 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
11097
11098 SCIPqueueFree(&conshdlrdata->reversepropqueue);
11099
11100 if( conshdlrdata->vp_randnumgen != NULL )
11101 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11102
11103 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11104 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11105 {
11106 if( conshdlrdata->vp_lp[i] != NULL )
11107 {
11108 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11109 }
11110 }
11111
11112 assert(conshdlrdata->branchrandnumgen == NULL);
11113
11114 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
11115 SCIPhashmapFree(&conshdlrdata->var2expr);
11116
11117 SCIPfreeBlockMemory(scip, &conshdlrdata);
11118 SCIPconshdlrSetData(conshdlr, NULL);
11119
11120 return SCIP_OKAY;
11121}
11122
11123
11124/** initialization method of constraint handler (called after problem was transformed) */
11125static
11126SCIP_DECL_CONSINIT(consInitNonlinear)
11127{ /*lint --e{715}*/
11128 SCIP_CONSHDLRDATA* conshdlrdata;
11129 int i;
11130
11131 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11132 assert(conshdlrdata != NULL);
11133
11134 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
11135 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
11136 /* set to 1 so it is larger than initial value of lastenforound in exprs */
11137 conshdlrdata->enforound = 1;
11138 /* reset numbering for auxiliary variables */
11139 conshdlrdata->auxvarid = 0;
11140
11141 for( i = 0; i < nconss; ++i )
11142 {
11143 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
11144 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
11145 }
11146
11147 /* sort nonlinear handlers by detection priority, in decreasing order */
11148 if( conshdlrdata->nnlhdlrs > 1 )
11149 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
11150
11151 /* get heuristics for later use */
11152 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11153 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11154
11155 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11156 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11157 {
11158 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11159 }
11160
11161 /* reset statistics in constraint handler */
11162 conshdlrdata->nweaksepa = 0;
11163 conshdlrdata->ntightenlp = 0;
11164 conshdlrdata->ndesperatebranch = 0;
11165 conshdlrdata->ndesperatecutoff = 0;
11166 conshdlrdata->ndesperatetightenlp = 0;
11167 conshdlrdata->nforcelp = 0;
11168 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11169 conshdlrdata->ncanonicalizecalls = 0;
11170
11171#ifdef ENFOLOGFILE
11172 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11173#endif
11174
11175 return SCIP_OKAY;
11176}
11177
11178
11179/** deinitialization method of constraint handler (called before transformed problem is freed) */
11180static
11181SCIP_DECL_CONSEXIT(consExitNonlinear)
11182{ /*lint --e{715}*/
11183 SCIP_CONSHDLRDATA* conshdlrdata;
11184 SCIP_CONS** consssorted;
11185 int i;
11186
11187 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11188 assert(conshdlrdata != NULL);
11189
11190 if( nconss > 0 )
11191 {
11192 /* for better performance of dropVarEvents, we sort by index, descending */
11193 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11194 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11195
11196 for( i = 0; i < nconss; ++i )
11197 {
11198 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11199 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11200 }
11201
11202 SCIPfreeBufferArray(scip, &consssorted);
11203 }
11204
11205 conshdlrdata->subnlpheur = NULL;
11206 conshdlrdata->trysolheur = NULL;
11207
11208 if( conshdlrdata->vp_randnumgen != NULL )
11209 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11210
11211 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11212 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11213 {
11214 if( conshdlrdata->vp_lp[i] != NULL )
11215 {
11216 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11217 }
11218 }
11219
11220 if( conshdlrdata->branchrandnumgen != NULL )
11221 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11222
11223 /* deinitialize nonlinear handlers */
11224 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11225 {
11226 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11227 }
11228
11229 ENFOLOG(
11230 if( enfologfile != NULL )
11231 {
11232 fclose(enfologfile);
11233 enfologfile = NULL;
11234 })
11235
11236 return SCIP_OKAY;
11237}
11238
11239
11240/** presolving initialization method of constraint handler (called when presolving is about to begin) */
11241#ifdef SCIP_DISABLED_CODE
11242static
11244{ /*lint --e{715}*/
11245 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11246 SCIPABORT(); /*lint --e{527}*/
11247
11248 return SCIP_OKAY;
11249}
11250#else
11251#define consInitpreNonlinear NULL
11252#endif
11253
11254
11255/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11256static
11257SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11258{ /*lint --e{715}*/
11259 SCIP_Bool infeasible;
11260
11261 if( nconss == 0 )
11262 return SCIP_OKAY;
11263
11264 /* skip some extra work if already known to be infeasible */
11266 return SCIP_OKAY;
11267
11268 /* simplify constraints and replace common subexpressions */
11269 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11270
11271 /* currently SCIP does not offer to communicate this,
11272 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11273 * or if a constraint expression became constant
11274 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11275 */
11276 /* assert(!infeasible); */
11277
11278 /* tell SCIP that we have something nonlinear */
11280
11281 return SCIP_OKAY;
11282}
11283
11284
11285/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11286static
11287SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11288{ /*lint --e{715}*/
11289 SCIP_CONSHDLRDATA* conshdlrdata;
11290 int i;
11291
11292 /* skip remaining initializations if we have solved already
11293 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11294 * assumes nonempty activities in expressions
11295 */
11296 switch( SCIPgetStatus(scip) )
11297 {
11302 return SCIP_OKAY;
11303 default: ;
11304 } /*lint !e788 */
11305
11306 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11307 assert(conshdlrdata != NULL);
11308
11309 /* reset one of the number of detections counter to count only current round */
11310 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11311 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11312
11313 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11314
11315 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11316 if( conshdlrdata->branchpscostweight > 0.0 )
11317 {
11318 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11319 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11320 {
11321 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11322 SCIPABORT();
11323 return SCIP_INVALIDDATA;
11324 }
11325 }
11326
11327 return SCIP_OKAY;
11328}
11329
11330
11331/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11332static
11333SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11334{ /*lint --e{715}*/
11335 SCIP_CONSHDLRDATA* conshdlrdata;
11336
11337 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11338
11339 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11340 assert(conshdlrdata != NULL);
11341
11342 /* free hash table for bilinear terms */
11343 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11344
11345 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11346 conshdlrdata->checkedvarlocks = FALSE;
11347
11348 /* drop catching new solution event, if catched before */
11349 if( conshdlrdata->newsoleventfilterpos >= 0 )
11350 {
11351 SCIP_EVENTHDLR* eventhdlr;
11352
11353 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11354 assert(eventhdlr != NULL);
11355
11356 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11357 conshdlrdata->newsoleventfilterpos = -1;
11358 }
11359
11360 return SCIP_OKAY;
11361}
11362
11363
11364/** frees specific constraint data */
11365static
11366SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11367{ /*lint --e{715}*/
11368 assert(consdata != NULL);
11369 assert(*consdata != NULL);
11370 assert((*consdata)->expr != NULL);
11371
11372 /* constraint locks should have been removed */
11373 assert((*consdata)->nlockspos == 0);
11374 assert((*consdata)->nlocksneg == 0);
11375
11376 /* free variable expressions */
11377 SCIP_CALL( freeVarExprs(scip, *consdata) );
11378
11379 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11380
11381 /* free nonlinear row representation */
11382 if( (*consdata)->nlrow != NULL )
11383 {
11384 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11385 }
11386
11387 SCIPfreeBlockMemory(scip, consdata);
11388
11389 return SCIP_OKAY;
11390}
11391
11392
11393/** transforms constraint data into data belonging to the transformed problem */
11394static
11395SCIP_DECL_CONSTRANS(consTransNonlinear)
11396{ /*lint --e{715}*/
11397 SCIP_EXPR* targetexpr;
11398 SCIP_CONSDATA* sourcedata;
11399
11400 sourcedata = SCIPconsGetData(sourcecons);
11401 assert(sourcedata != NULL);
11402
11403 /* get a copy of sourceexpr with transformed vars */
11404 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11405 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11406
11407 /* create transformed cons (only captures targetexpr, no need to copy again) */
11408 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11409 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11410 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11411 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11412 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11413 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11414
11415 /* release target expr */
11416 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11417
11418 return SCIP_OKAY;
11419}
11420
11421
11422/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11423static
11424SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11425{ /*lint --e{715}*/
11426 SCIP_CONSHDLRDATA* conshdlrdata;
11427
11428 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11429 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11430 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11431 * for now, there is an assert in detectNlhdlrs to require initial if separated
11432 */
11433 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11434
11435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11436 assert(conshdlrdata != NULL);
11437
11438 /* catch new solution event */
11439 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11440 {
11441 SCIP_EVENTHDLR* eventhdlr;
11442
11443 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11444 assert(eventhdlr != NULL);
11445
11446 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11447 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11448 }
11449
11450 /* collect all bilinear terms for which an auxvar is present
11451 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11452 * addition (and removal?) of constraints during solve
11453 * this is typically the majority of constraints, but the method should be made more flexible
11454 */
11455 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11456
11457 return SCIP_OKAY;
11458}
11459
11460
11461/** separation method of constraint handler for LP solutions */
11462static
11463SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11464{ /*lint --e{715}*/
11465 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11466
11467 return SCIP_OKAY;
11468}
11469
11470
11471/** separation method of constraint handler for arbitrary primal solutions */
11472static
11473SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11474{ /*lint --e{715}*/
11475 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11476
11477 return SCIP_OKAY;
11478}
11479
11480
11481/** constraint enforcing method of constraint handler for LP solutions */
11482static
11483SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11484{ /*lint --e{715}*/
11485 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11486
11487 return SCIP_OKAY;
11488}
11489
11490
11491/** constraint enforcing method of constraint handler for relaxation solutions */
11492static
11493SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11494{ /*lint --e{715}*/
11495 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11496
11497 return SCIP_OKAY;
11498}
11499
11500
11501/** constraint enforcing method of constraint handler for pseudo solutions */
11502static
11503SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11504{ /*lint --e{715}*/
11505 SCIP_RESULT propresult;
11506 SCIP_Longint soltag;
11507 int nchgbds;
11508 int nnotify;
11509 int c;
11510
11511 soltag = SCIPgetExprNewSoltag(scip);
11512
11513 *result = SCIP_FEASIBLE;
11514 for( c = 0; c < nconss; ++c )
11515 {
11516 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11517
11518 if( isConsViolated(scip, conss[c]) )
11519 *result = SCIP_INFEASIBLE;
11520 }
11521
11522 if( *result == SCIP_FEASIBLE )
11523 return SCIP_OKAY;
11524
11525 /* try to propagate
11526 * TODO obey propinenfo parameter, but we need something to recognize cutoff
11527 */
11528 nchgbds = 0;
11529 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11530
11531 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11532 {
11533 *result = propresult;
11534 return SCIP_OKAY;
11535 }
11536
11537 /* register all unfixed variables in all violated constraints as branching candidates */
11538 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11539 if( nnotify > 0 )
11540 {
11541 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11542
11543 return SCIP_OKAY;
11544 }
11545
11546 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11547 *result = SCIP_SOLVELP;
11548 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11549
11550 return SCIP_OKAY;
11551}
11552
11553
11554/** feasibility check method of constraint handler for integral solutions */
11555static
11556SCIP_DECL_CONSCHECK(consCheckNonlinear)
11557{ /*lint --e{715}*/
11558 SCIP_CONSHDLRDATA* conshdlrdata;
11559 SCIP_CONSDATA* consdata;
11560 SCIP_Real maxviol;
11561 SCIP_Bool maypropfeasible;
11562 SCIP_Longint soltag;
11563 int c;
11564
11565 assert(scip != NULL);
11566 assert(conshdlr != NULL);
11567 assert(conss != NULL || nconss == 0);
11568 assert(result != NULL);
11569
11570 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11571 assert(conshdlrdata != NULL);
11572
11573 *result = SCIP_FEASIBLE;
11574 soltag = SCIPgetExprNewSoltag(scip);
11575 maxviol = 0.0;
11576 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11578
11579 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
11580 maypropfeasible = FALSE;
11581
11582 /* check nonlinear constraints for feasibility */
11583 for( c = 0; c < nconss; ++c )
11584 {
11585 assert(conss != NULL && conss[c] != NULL);
11586 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11587
11588 if( isConsViolated(scip, conss[c]) )
11589 {
11590 *result = SCIP_INFEASIBLE;
11591 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11592
11593 consdata = SCIPconsGetData(conss[c]);
11594 assert(consdata != NULL);
11595
11596 /* print reason for infeasibility */
11597 if( printreason )
11598 {
11599 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11600 SCIPinfoMessage(scip, NULL, ";\n");
11601
11602 if( consdata->lhsviol > SCIPfeastol(scip) )
11603 {
11604 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11605 }
11606 if( consdata->rhsviol > SCIPfeastol(scip) )
11607 {
11608 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11609 }
11610 }
11611 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11612 {
11613 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11614 return SCIP_OKAY;
11615 }
11616
11617 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11618 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11619 maypropfeasible = FALSE;
11620
11621 if( maypropfeasible )
11622 {
11623 if( consdata->lhsviol > SCIPfeastol(scip) )
11624 {
11625 /* check if there is a variable which may help to get the left hand side satisfied
11626 * if there is no such variable, then we cannot get feasible
11627 */
11628 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11629 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11630 maypropfeasible = FALSE;
11631 }
11632 else
11633 {
11634 assert(consdata->rhsviol > SCIPfeastol(scip));
11635 /* check if there is a variable which may help to get the right hand side satisfied
11636 * if there is no such variable, then we cannot get feasible
11637 */
11638 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11639 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11640 maypropfeasible = FALSE;
11641 }
11642 }
11643 }
11644 }
11645
11646 if( *result == SCIP_INFEASIBLE && maypropfeasible )
11647 {
11648 SCIP_Bool success;
11649
11650 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11651
11652 /* do not pass solution to NLP heuristic if we made it feasible this way */
11653 if( success )
11654 return SCIP_OKAY;
11655 }
11656
11657 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11658 {
11659 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11660 }
11661
11662 return SCIP_OKAY;
11663}
11664
11665
11666/** domain propagation method of constraint handler */
11667static
11668SCIP_DECL_CONSPROP(consPropNonlinear)
11669{ /*lint --e{715}*/
11670 int nchgbds = 0;
11671
11672 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11673 assert(nchgbds >= 0);
11674
11675 /* TODO would it make sense to check for redundant constraints? */
11676
11677 return SCIP_OKAY;
11678}
11679
11680
11681/** presolving method of constraint handler */
11682static
11683SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11684{ /*lint --e{715}*/
11685 SCIP_CONSHDLRDATA* conshdlrdata;
11686 SCIP_Bool infeasible;
11687 int c;
11688
11689 *result = SCIP_DIDNOTFIND;
11690
11691 if( nconss == 0 )
11692 {
11693 *result = SCIP_DIDNOTRUN;
11694 return SCIP_OKAY;
11695 }
11696
11697 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11698 assert(conshdlrdata != NULL);
11699
11700 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11701 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11702 if( infeasible )
11703 {
11704 *result = SCIP_CUTOFF;
11705 return SCIP_OKAY;
11706 }
11707
11708 /* merge constraints with the same root expression */
11709 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11710 {
11711 SCIP_Bool success;
11712
11713 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11714 if( success )
11715 *result = SCIP_SUCCESS;
11716 }
11717
11718 /* propagate constraints */
11719 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11720 if( *result == SCIP_CUTOFF )
11721 return SCIP_OKAY;
11722
11723 /* propagate function domains (TODO integrate with simplify?) */
11724 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11725 {
11726 SCIP_RESULT localresult;
11727 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11728 if( localresult == SCIP_CUTOFF )
11729 {
11730 *result = SCIP_CUTOFF;
11731 return SCIP_OKAY;
11732 }
11733 if( localresult == SCIP_REDUCEDDOM )
11734 *result = SCIP_REDUCEDDOM;
11735 }
11736
11737 /* check for redundant constraints, remove constraints that are a value expression */
11738 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11739 if( infeasible )
11740 {
11741 *result = SCIP_CUTOFF;
11742 return SCIP_OKAY;
11743 }
11744
11745 /* try to upgrade constraints */
11746 for( c = 0; c < nconss; ++c )
11747 {
11748 SCIP_Bool upgraded;
11749
11750 /* skip inactive and deleted constraints */
11751 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11752 continue;
11753
11754 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11755 }
11756
11757 /* try to change continuous variables that appear linearly to be implicit integer */
11758 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11759 {
11760 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11761
11762 if( infeasible )
11763 {
11764 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11765 *result = SCIP_CUTOFF;
11766 return SCIP_OKAY;
11767 }
11768 }
11769
11770 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11772 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11773 {
11774 /* run this presolving technique only once because we don't want to generate identical bound disjunction
11775 * constraints multiple times
11776 */
11777 conshdlrdata->checkedvarlocks = TRUE;
11778
11779 for( c = 0; c < nconss; ++c )
11780 {
11781 int tmpnchgvartypes = 0;
11782 int tmpnaddconss = 0;
11783
11784 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11785 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11786 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11787
11788 if( infeasible )
11789 {
11790 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11791 *result = SCIP_CUTOFF;
11792 return SCIP_OKAY;
11793 }
11794
11795 (*nchgvartypes) += tmpnchgvartypes;
11796 (*naddconss) += tmpnaddconss;
11797 }
11798 }
11799
11800 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11801 *result = SCIP_SUCCESS;
11802 else
11803 *result = SCIP_DIDNOTFIND;
11804
11805 return SCIP_OKAY;
11806}
11807
11808
11809/** propagation conflict resolving method of constraint handler */
11810#ifdef SCIP_DISABLED_CODE
11811static
11813{ /*lint --e{715}*/
11814 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11815 SCIPABORT(); /*lint --e{527}*/
11816
11817 return SCIP_OKAY;
11818}
11819#else
11820#define consRespropNonlinear NULL
11821#endif
11822
11823
11824/** variable rounding lock method of constraint handler */
11825static
11826SCIP_DECL_CONSLOCK(consLockNonlinear)
11827{ /*lint --e{715}*/
11828 SCIP_CONSDATA* consdata;
11829 SCIP_EXPR_OWNERDATA* ownerdata;
11830 SCIP_Bool reinitsolve = FALSE;
11831
11832 assert(conshdlr != NULL);
11833 assert(cons != NULL);
11834
11835 consdata = SCIPconsGetData(cons);
11836 assert(consdata != NULL);
11837 assert(consdata->expr != NULL);
11838
11839 ownerdata = SCIPexprGetOwnerData(consdata->expr);
11840
11841 /* check whether we need to initSolve again because
11842 * - we have enfo initialized (nenfos >= 0)
11843 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11844 */
11845 if( ownerdata->nenfos >= 0 )
11846 {
11847 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11848 reinitsolve = TRUE;
11849 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11850 reinitsolve = TRUE;
11851 }
11852
11853 if( reinitsolve )
11854 {
11855 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11856 }
11857
11858 /* add locks */
11859 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11860
11861 if( reinitsolve )
11862 {
11863 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11864 }
11865
11866 return SCIP_OKAY;
11867}
11868
11869
11870/** constraint activation notification method of constraint handler */
11871static
11872SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11873{ /*lint --e{715}*/
11874 SCIP_CONSDATA* consdata;
11875 SCIP_Bool infeasible = FALSE;
11876
11877 consdata = SCIPconsGetData(cons);
11878 assert(consdata != NULL);
11879
11880 /* simplify root expression if the constraint has been added after presolving */
11882 {
11883 SCIP_Bool replacedroot;
11884
11885 if( !consdata->issimplified )
11886 {
11887 SCIP_EXPR* simplified;
11888 SCIP_Bool changed;
11889
11890 /* simplify constraint */
11891 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11892 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11893 assert(simplified != NULL);
11894 consdata->expr = simplified;
11895 consdata->issimplified = TRUE;
11896 }
11897
11898 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11899 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11900 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11901
11902 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11903 {
11904 SCIP_CONSHDLRDATA* conshdlrdata;
11905 SCIP_EXPRITER* it;
11906 SCIP_EXPR* expr;
11907
11908 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11909 assert(conshdlrdata != NULL);
11910
11912 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11914 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11915 {
11916 SCIP_EXPR* child;
11917 SCIP_EXPR* hashmapexpr;
11918
11919 child = SCIPexpriterGetChildExprDFS(it);
11920 if( !SCIPisExprVar(scip, child) )
11921 continue;
11922
11923 /* check which expression is stored in the hashmap for the var of child */
11924 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11925 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11926 if( hashmapexpr != NULL && hashmapexpr != child )
11927 {
11929 }
11930 }
11931 SCIPfreeExpriter(&it);
11932 }
11933 }
11934
11935 /* store variable expressions */
11937 {
11938 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11939 }
11940
11941 /* add manually locks to constraints that are not checked for feasibility */
11942 if( !SCIPconsIsChecked(cons) )
11943 {
11944 assert(consdata->nlockspos == 0);
11945 assert(consdata->nlocksneg == 0);
11946
11947 SCIP_CALL( addLocks(scip, cons, 1, 0) );
11948 }
11949
11950 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11951 {
11952 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11953 }
11954
11955 /* TODO deal with infeasibility */
11956 assert(!infeasible);
11957
11958 return SCIP_OKAY;
11959}
11960
11961
11962/** constraint deactivation notification method of constraint handler */
11963static
11964SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11965{ /*lint --e{715}*/
11966 SCIP_CONSHDLRDATA* conshdlrdata;
11967
11968 conshdlrdata = SCIPconshdlrGetData(conshdlr);
11969 assert(conshdlrdata != NULL);
11970
11972 {
11973 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11974 }
11975
11977 {
11978 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11980 }
11981
11982 /* remove locks that have been added in consActiveExpr() */
11983 if( !SCIPconsIsChecked(cons) )
11984 {
11985 SCIP_CALL( addLocks(scip, cons, -1, 0) );
11986
11987 assert(SCIPconsGetData(cons)->nlockspos == 0);
11988 assert(SCIPconsGetData(cons)->nlocksneg == 0);
11989 }
11990
11991 return SCIP_OKAY;
11992}
11993
11994
11995/** constraint enabling notification method of constraint handler */
11996static
11997SCIP_DECL_CONSENABLE(consEnableNonlinear)
11998{ /*lint --e{715}*/
11999 SCIP_CONSHDLRDATA* conshdlrdata;
12000
12001 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12002 assert(conshdlrdata != NULL);
12003
12005 {
12006 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12007 }
12008
12009 return SCIP_OKAY;
12010}
12011
12012
12013/** constraint disabling notification method of constraint handler */
12014static
12015SCIP_DECL_CONSDISABLE(consDisableNonlinear)
12016{ /*lint --e{715}*/
12017 SCIP_CONSHDLRDATA* conshdlrdata;
12018
12019 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12020 assert(conshdlrdata != NULL);
12021
12023 {
12024 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12025 }
12026
12027 return SCIP_OKAY;
12028}
12029
12030/** variable deletion of constraint handler */
12031#ifdef SCIP_DISABLED_CODE
12032static
12034{ /*lint --e{715}*/
12035 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12036 SCIPABORT(); /*lint --e{527}*/
12037
12038 return SCIP_OKAY;
12039}
12040#else
12041#define consDelvarsNonlinear NULL
12042#endif
12043
12044
12045/** constraint display method of constraint handler */
12046static
12047SCIP_DECL_CONSPRINT(consPrintNonlinear)
12048{ /*lint --e{715}*/
12049 SCIP_CONSDATA* consdata;
12050
12051 consdata = SCIPconsGetData(cons);
12052 assert(consdata != NULL);
12053 assert(consdata->expr != NULL);
12054
12055 /* print left hand side for ranged constraints */
12056 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12057 {
12058 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12059 }
12060
12061 /* print expression */
12062 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
12063
12064 /* print right hand side */
12065 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12066 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12067 else if( !SCIPisInfinity(scip, consdata->rhs) )
12068 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12069 else if( !SCIPisInfinity(scip, -consdata->lhs) )
12070 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12071 else
12072 SCIPinfoMessage(scip, file, " [free]");
12073
12074 return SCIP_OKAY;
12075}
12076
12077
12078/** constraint copying method of constraint handler */
12079static
12080SCIP_DECL_CONSCOPY(consCopyNonlinear)
12081{ /*lint --e{715}*/
12082 SCIP_CONSHDLR* targetconshdlr;
12083 SCIP_EXPR* targetexpr = NULL;
12084 SCIP_CONSDATA* sourcedata;
12085
12086 assert(cons != NULL);
12087
12088 sourcedata = SCIPconsGetData(sourcecons);
12089 assert(sourcedata != NULL);
12090
12091 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12092 assert(targetconshdlr != NULL);
12093
12094 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
12095
12096 if( targetexpr == NULL )
12097 *valid = FALSE;
12098
12099 *cons = NULL;
12100 if( *valid )
12101 {
12102 /* create copy (only capture targetexpr, no need to copy again) */
12103 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
12104 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
12105 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12106 }
12107
12108 if( targetexpr != NULL )
12109 {
12110 /* release target expr */
12111 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
12112 }
12113
12114 return SCIP_OKAY;
12115}
12116
12117
12118/** constraint parsing method of constraint handler */
12119static
12120SCIP_DECL_CONSPARSE(consParseNonlinear)
12121{ /*lint --e{715}*/
12122 SCIP_Real lhs;
12123 SCIP_Real rhs;
12124 char* endptr;
12125 SCIP_EXPR* consexprtree;
12126
12127 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
12128
12129 assert(scip != NULL);
12130 assert(success != NULL);
12131 assert(str != NULL);
12132 assert(name != NULL);
12133 assert(cons != NULL);
12134
12135 *success = FALSE;
12136
12137 /* return if string empty */
12138 if( !*str )
12139 return SCIP_OKAY;
12140
12141 endptr = (char*)str;
12142
12143 /* set left and right hand side to their default values */
12144 lhs = -SCIPinfinity(scip);
12145 rhs = SCIPinfinity(scip);
12146
12147 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
12148
12149 /* check for left hand side */
12150 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12151 {
12152 /* there is a number coming, maybe it is a left-hand-side */
12153 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12154 {
12155 SCIPerrorMessage("error parsing number from <%s>\n", str);
12156 return SCIP_READERROR;
12157 }
12158
12159 /* ignore whitespace */
12160 SCIP_CALL( SCIPskipSpace(&endptr) );
12161
12162 if( endptr[0] != '<' || endptr[1] != '=' )
12163 {
12164 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12165 lhs = -SCIPinfinity(scip);
12166 }
12167 else
12168 {
12169 /* it was indeed a left-hand-side, so continue parsing after it */
12170 str = endptr + 2;
12171
12172 /* ignore whitespace */
12173 SCIP_CALL( SCIPskipSpace((char**)&str) );
12174 }
12175 }
12176
12177 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12178
12179 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12180 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12181
12182 /* check for left or right hand side */
12183 SCIP_CALL( SCIPskipSpace((char**)&str) );
12184
12185 /* check for free constraint */
12186 if( strncmp(str, "[free]", 6) == 0 )
12187 {
12188 if( !SCIPisInfinity(scip, -lhs) )
12189 {
12190 SCIPerrorMessage("cannot have left hand side and [free] status \n");
12191 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12192 return SCIP_OKAY;
12193 }
12194 *success = TRUE;
12195 }
12196 else
12197 {
12198 switch( *str )
12199 {
12200 case '<':
12201 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12202 break;
12203 case '=':
12204 if( !SCIPisInfinity(scip, -lhs) )
12205 {
12206 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12207 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12208 return SCIP_OKAY;
12209 }
12210 else
12211 {
12212 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12213 lhs = rhs;
12214 }
12215 break;
12216 case '>':
12217 if( !SCIPisInfinity(scip, -lhs) )
12218 {
12219 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12220 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12221 return SCIP_OKAY;
12222 }
12223 else
12224 {
12225 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12226 break;
12227 }
12228 case '\0':
12229 *success = TRUE;
12230 break;
12231 default:
12232 SCIPerrorMessage("unexpected character %c\n", *str);
12233 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12234 return SCIP_OKAY;
12235 }
12236 }
12237
12238 /* create constraint */
12239 SCIP_CALL( createCons(scip, conshdlr, cons, name,
12240 consexprtree, lhs, rhs, FALSE,
12241 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12242 assert(*cons != NULL);
12243
12244 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12245
12246 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12247
12248 return SCIP_OKAY;
12249}
12250
12251
12252/** constraint method of constraint handler which returns the variables (if possible) */
12253static
12254SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12255{ /*lint --e{715}*/
12256 SCIP_CONSDATA* consdata;
12257 int i;
12258
12259 consdata = SCIPconsGetData(cons);
12260 assert(consdata != NULL);
12261
12262 /* store variable expressions if not done so far */
12263 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12264
12265 /* check whether array is too small in order to store all variables */
12266 if( varssize < consdata->nvarexprs )
12267 {
12268 *success = FALSE;
12269 return SCIP_OKAY;
12270 }
12271
12272 for( i = 0; i < consdata->nvarexprs; ++i )
12273 {
12274 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12275 assert(vars[i] != NULL);
12276 }
12277
12278 *success = TRUE;
12279
12280 return SCIP_OKAY;
12281}
12282
12283/** constraint method of constraint handler which returns the number of variables (if possible) */
12284static
12285SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12286{ /*lint --e{715}*/
12287 SCIP_CONSDATA* consdata;
12288
12289 consdata = SCIPconsGetData(cons);
12290 assert(consdata != NULL);
12291
12292 /* store variable expressions if not done so far */
12293 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12294
12295 *nvars = consdata->nvarexprs;
12296 *success = TRUE;
12297
12298 return SCIP_OKAY;
12299}
12300
12301/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12302#ifdef SCIP_DISABLED_CODE
12303static
12305{ /*lint --e{715}*/
12306 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12307 SCIPABORT(); /*lint --e{527}*/
12308
12309 return SCIP_OKAY;
12310}
12311#else
12312#define consGetDiveBdChgsNonlinear NULL
12313#endif
12314
12315/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12316static
12317SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12318{ /*lint --e{715}*/
12319 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12320
12321 return SCIP_OKAY;
12322}
12323
12324/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12325static
12326SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12327{ /*lint --e{715}*/
12328 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12329
12330 return SCIP_OKAY;
12331}
12332
12333/** output method of cons_nonlinear statistics table to output file stream 'file' */
12334static
12335SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12336{ /*lint --e{715}*/
12337 SCIP_CONSHDLR* conshdlr;
12338 SCIP_CONSHDLRDATA* conshdlrdata;
12339
12340 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12341 assert(conshdlr != NULL);
12342
12343 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12344 assert(conshdlrdata != NULL);
12345
12346 /* print statistics for constraint handler */
12347 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12348 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12349 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12350 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12351 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12352 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12353 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12354 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12355 SCIPinfoMessage(scip, file, "\n");
12356 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12357 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12358 SCIPinfoMessage(scip, file, "\n");
12359
12360 return SCIP_OKAY;
12361}
12362
12363/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
12364static
12365SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
12366{
12367 SCIP_CONSHDLR* conshdlr;
12368 SCIP_CONSHDLRDATA* conshdlrdata;
12369
12370 assert(scip != NULL);
12371 assert(table != NULL);
12372 assert(datatree != NULL);
12373
12374 /* Find the constraint handler */
12375 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12376 assert(conshdlr != NULL);
12377
12378 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12379 assert(conshdlrdata != NULL);
12380
12381 /* Insert statistics */
12382 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
12383 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
12384 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
12385 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
12386 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
12387 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
12388 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
12389
12390 return SCIP_OKAY;
12391}
12392
12393/** output method of nlhdlr statistics table to output file stream 'file' */
12394static
12395SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
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 /* skip nlhdlr table if there never were active nonlinear constraints */
12404 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12405 return SCIP_OKAY;
12406
12407 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12408 assert(conshdlrdata != NULL);
12409
12410 /* print statistics for nonlinear handlers */
12411 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12412
12413 return SCIP_OKAY;
12414}
12415
12416/** collect method of nlhdlr statistics table to SCIP_DATATREE */
12417static
12418SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
12419{ /*lint --e{715}*/
12420 SCIP_CONSHDLR* conshdlr;
12421 SCIP_CONSHDLRDATA* conshdlrdata;
12422
12423 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12424 assert(conshdlr != NULL);
12425
12426 /* skip nlhdlr table if there never were active nonlinear constraints */
12427 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12428 return SCIP_OKAY;
12429
12430 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12431 assert(conshdlrdata != NULL);
12432
12433 /* collect statistics for nonlinear handlers */
12434 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
12435
12436 return SCIP_OKAY;
12437}
12438
12439/** execution method of display nlhdlrs dialog */
12440static
12441SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12442{ /*lint --e{715}*/
12443 SCIP_CONSHDLR* conshdlr;
12444 SCIP_CONSHDLRDATA* conshdlrdata;
12445 int i;
12446
12447 /* add dialog to history of dialogs that have been executed */
12448 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12449
12450 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12451 assert(conshdlr != NULL);
12452
12453 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12454 assert(conshdlrdata != NULL);
12455
12456 /* display list of nonlinear handler */
12457 SCIPdialogMessage(scip, NULL, "\n");
12458 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12459 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12460 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12461 {
12462 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12463 assert(nlhdlr != NULL);
12464
12465 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12466 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12469 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12470 SCIPdialogMessage(scip, NULL, "\n");
12471 }
12472 SCIPdialogMessage(scip, NULL, "\n");
12473
12474 /* next dialog will be root dialog again */
12475 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12476
12477 return SCIP_OKAY;
12478}
12479
12480/*
12481 * constraint handler specific interface methods
12482 */
12483
12484/** creates the handler for nonlinear constraints and includes it in SCIP */
12486 SCIP* scip /**< SCIP data structure */
12487 )
12488{
12489 SCIP_CONSHDLRDATA* conshdlrdata;
12490 SCIP_DIALOG* parentdialog;
12491
12492 /* create nonlinear constraint handler data */
12493 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12494 conshdlrdata->intevalvar = intEvalVarBoundTightening;
12495 conshdlrdata->curboundstag = 1;
12496 conshdlrdata->lastboundrelax = 1;
12497 conshdlrdata->curpropboundstag = 1;
12498 conshdlrdata->newsoleventfilterpos = -1;
12499 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12500 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12501 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12502
12503 /* include constraint handler */
12509 conshdlrCopyNonlinear,
12510 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12511 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12512 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12513 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12514 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12515 consActiveNonlinear, consDeactiveNonlinear,
12516 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12517 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12518 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12519 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12520
12521 /* add nonlinear constraint handler parameters */
12522 /* TODO organize into more subcategories */
12523 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12524 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12525 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12526
12527 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12528 "whether to check bounds of all auxiliary variable to seed reverse propagation",
12529 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12530
12531 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12532 "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",
12533 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12534
12535 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12536 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12537 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12538
12539 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12540 "by how much to relax constraint sides during bound tightening",
12541 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12542
12543 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12544 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12545 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12546
12547 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12548 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12549 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12550
12551 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12552 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12553 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12554
12555 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12556 "maximal number of auxiliary expressions per bilinear term",
12557 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12558
12559 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12560 "whether to reformulate products of binary variables during presolving",
12561 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12562
12563 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12564 "whether to use the AND constraint handler for reformulating binary products",
12565 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12566
12567 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12568 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12569 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12570
12571 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12572 "whether to forbid multiaggregation of nonlinear variables",
12573 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12574
12575 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12576 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12577 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12578
12579 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12580 "whether to (re)run propagation in enforcement",
12581 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12582
12583 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12584 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12585 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12586
12587 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12588 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12589 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12590
12591 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12592 "consider efficacy requirement when deciding whether a cut is \"strong\"",
12593 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12594
12595 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12596 "whether to force \"strong\" cuts in enforcement",
12597 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12598
12599 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12600 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12601 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12602
12603 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12604 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12605 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12606
12607 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12608 "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",
12609 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12610
12611 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12612 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12613 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12614
12615 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12616 "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)",
12617 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12618
12619 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12620 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12621 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12622
12623 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12624 "whether to use external branching candidates and branching rules for branching",
12625 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12626
12627 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12628 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12629 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12630
12631 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12632 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12633 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12634
12635 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12636 "weight by how much to consider the violation assigned to a variable for its branching score",
12637 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12638
12639 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12640 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12641 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12642
12643 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12644 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12645 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12646
12647 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12648 "weight by how much to consider the pseudo cost of a variable for its branching score",
12649 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12650
12651 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12652 "weight by how much to consider the domain width in branching score",
12653 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12654
12655 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12656 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12657 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12658
12659 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12660 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12661 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12662
12663 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12664 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12665 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12666
12667 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12668 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12669 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12670
12671 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12672 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12673 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12674
12675 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12676 "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)",
12677 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12678
12679 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12680 "whether to assume that any constraint in the presolved problem is convex",
12681 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
12682
12683 /* include handler for bound change events */
12684 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12685 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12686 assert(conshdlrdata->eventhdlr != NULL);
12687
12688 /* include tables for statistics */
12691 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
12693
12696 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
12698
12699 /* create, include, and release display nlhdlrs dialog */
12700 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12701 {
12702 SCIP_DIALOG* dialog;
12703
12704 assert(parentdialog != NULL);
12705 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12706
12708 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12710 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12711 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12712 }
12713
12714 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12715 processNewSolutionEvent, NULL) );
12716
12717 return SCIP_OKAY;
12718}
12719
12720/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12722 SCIP* scip, /**< SCIP data structure */
12723 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12724 int priority, /**< priority of upgrading method */
12725 SCIP_Bool active, /**< should the upgrading method by active by default? */
12726 const char* conshdlrname /**< name of the constraint handler */
12727 )
12728{
12729 SCIP_CONSHDLR* conshdlr;
12730 SCIP_CONSHDLRDATA* conshdlrdata;
12731 CONSUPGRADE* consupgrade;
12733 char paramdesc[SCIP_MAXSTRLEN];
12734 int i;
12735
12736 assert(conshdlrname != NULL );
12737 assert(nlconsupgd != NULL);
12738
12739 /* find the nonlinear constraint handler */
12740 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12741 if( conshdlr == NULL )
12742 {
12743 SCIPerrorMessage("nonlinear constraint handler not found\n");
12744 return SCIP_PLUGINNOTFOUND;
12745 }
12746
12747 conshdlrdata = SCIPconshdlrGetData(conshdlr);
12748 assert(conshdlrdata != NULL);
12749
12750 /* check whether upgrade method exists already */
12751 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12752 {
12753 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12754 {
12755#ifdef SCIP_DEBUG
12756 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12757#endif
12758 return SCIP_OKAY;
12759 }
12760 }
12761
12762 /* create a nonlinear constraint upgrade data object */
12763 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12764 consupgrade->consupgd = nlconsupgd;
12765 consupgrade->priority = priority;
12766 consupgrade->active = active;
12767
12768 /* insert nonlinear constraint upgrade method into constraint handler data */
12769 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12770 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12771
12772 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12773 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12774 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12775 conshdlrdata->consupgrades[i] = consupgrade;
12776 conshdlrdata->nconsupgrades++;
12777
12778 /* adds parameter to turn on and off the upgrading step */
12779 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12780 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12782 paramname, paramdesc,
12783 &consupgrade->active, FALSE, active, NULL, NULL) );
12784
12785 return SCIP_OKAY;
12786}
12787
12788/** creates and captures a nonlinear constraint
12789 *
12790 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12791 */
12793 SCIP* scip, /**< SCIP data structure */
12794 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12795 const char* name, /**< name of constraint */
12796 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12797 SCIP_Real lhs, /**< left hand side of constraint */
12798 SCIP_Real rhs, /**< right hand side of constraint */
12799 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12800 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12801 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12802 * Usually set to TRUE. */
12803 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12804 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12805 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12806 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12807 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12808 * Usually set to TRUE. */
12809 SCIP_Bool local, /**< is constraint only valid locally?
12810 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12811 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12812 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12813 * adds coefficients to this constraint. */
12814 SCIP_Bool dynamic, /**< is constraint subject to aging?
12815 * Usually set to FALSE. Set to TRUE for own cuts which
12816 * are separated as constraints. */
12817 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12818 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12819 )
12820{
12821 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12822 SCIP_CONSHDLR* conshdlr;
12823
12824 /* find the nonlinear constraint handler */
12825 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12826 if( conshdlr == NULL )
12827 {
12828 SCIPerrorMessage("nonlinear constraint handler not found\n");
12829 return SCIP_PLUGINNOTFOUND;
12830 }
12831
12832 /* create constraint */
12833 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12834 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12835
12836 return SCIP_OKAY;
12837}
12838
12839/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12840 *
12841 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12842 *
12843 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12844 *
12845 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12846 */
12848 SCIP* scip, /**< SCIP data structure */
12849 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12850 const char* name, /**< name of constraint */
12851 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12852 SCIP_Real lhs, /**< left hand side of constraint */
12853 SCIP_Real rhs /**< right hand side of constraint */
12854 )
12855{
12856 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12858
12859 return SCIP_OKAY;
12860}
12861
12862/** creates and captures a quadratic nonlinear constraint
12863 *
12864 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12865 */
12867 SCIP* scip, /**< SCIP data structure */
12868 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12869 const char* name, /**< name of constraint */
12870 int nlinvars, /**< number of linear terms */
12871 SCIP_VAR** linvars, /**< array with variables in linear part */
12872 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12873 int nquadterms, /**< number of quadratic terms */
12874 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12875 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12876 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12877 SCIP_Real lhs, /**< left hand side of quadratic equation */
12878 SCIP_Real rhs, /**< right hand side of quadratic equation */
12879 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12880 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12881 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12882 * Usually set to TRUE. */
12883 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12884 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12885 SCIP_Bool check, /**< should the constraint be checked for feasibility?
12886 * TRUE for model constraints, FALSE for additional, redundant constraints. */
12887 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12888 * Usually set to TRUE. */
12889 SCIP_Bool local, /**< is constraint only valid locally?
12890 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12891 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12892 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12893 * adds coefficients to this constraint. */
12894 SCIP_Bool dynamic, /**< is constraint subject to aging?
12895 * Usually set to FALSE. Set to TRUE for own cuts which
12896 * are separated as constraints. */
12897 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12898 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12899 )
12900{
12901 SCIP_CONSHDLR* conshdlr;
12902 SCIP_EXPR* expr;
12903 int i;
12904
12905 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12906 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12907
12908 /* check data for infinity or nan values */
12909 for( i = 0; i < nlinvars; ++i )
12910 {
12911 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
12912 {
12913 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
12914 return SCIP_INVALIDDATA;
12915 }
12916 }
12917 for( i = 0; i < nquadterms; ++i )
12918 {
12919 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
12920 {
12921 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
12922 return SCIP_INVALIDDATA;
12923 }
12924 }
12925 /* lhs and rhs will be checked in createCons */
12926
12927 /* get nonlinear constraint handler */
12928 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12929 if( conshdlr == NULL )
12930 {
12931 SCIPerrorMessage("nonlinear constraint handler not found\n");
12932 return SCIP_PLUGINNOTFOUND;
12933 }
12934
12935 /* create quadratic expression */
12936 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12937 assert(expr != NULL);
12938
12939 /* create nonlinear constraint */
12940 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12941 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12942
12943 /* release quadratic expression (captured by constraint now) */
12944 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12945
12946 return SCIP_OKAY;
12947}
12948
12949/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12950 *
12951 * All flags can be set via SCIPconsSetFLAGNAME-methods.
12952 *
12953 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12954 *
12955 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12956 */
12958 SCIP* scip, /**< SCIP data structure */
12959 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12960 const char* name, /**< name of constraint */
12961 int nlinvars, /**< number of linear terms */
12962 SCIP_VAR** linvars, /**< array with variables in linear part */
12963 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12964 int nquadterms, /**< number of quadratic terms */
12965 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12966 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12967 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12968 SCIP_Real lhs, /**< left hand side of quadratic equation */
12969 SCIP_Real rhs /**< right hand side of quadratic equation */
12970 )
12971{
12972 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12974
12975 return SCIP_OKAY;
12976}
12977
12978/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12979 *
12980 * \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$
12981 *
12982 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12983 */
12985 SCIP* scip, /**< SCIP data structure */
12986 SCIP_CONS** cons, /**< pointer to hold the created constraint */
12987 const char* name, /**< name of constraint */
12988 int nvars, /**< number of variables on left hand side of constraint (n) */
12989 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12990 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12991 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12992 SCIP_Real constant, /**< constant on left hand side (gamma) */
12993 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12994 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12995 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12996 )
12997{
12998 SCIP_EXPR* expr;
12999 SCIP_EXPR* lhssum;
13000 SCIP_EXPR* terms[2];
13001 SCIP_Real termcoefs[2];
13002 int i;
13003
13004 assert(vars != NULL || nvars == 0);
13005
13006 /* check values for infinity or nan */
13007 for( i = 0; i < nvars; ++i )
13008 {
13009 if( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) )
13010 {
13011 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13012 return SCIP_INVALIDDATA;
13013 }
13014 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, coefs[i])) )
13015 {
13016 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
13017 return SCIP_INVALIDDATA;
13018 }
13019 }
13020 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
13021 {
13022 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
13023 return SCIP_INVALIDDATA;
13024 }
13025 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
13026 {
13027 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
13028 return SCIP_INVALIDDATA;
13029 }
13030 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
13031 {
13032 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
13033 return SCIP_INVALIDDATA;
13034 }
13035 /* lhs and rhs will be checked in createCons */
13036
13037 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
13038 for( i = 0; i < nvars; ++i )
13039 {
13040 SCIP_EXPR* varexpr;
13041 SCIP_EXPR* powexpr;
13042
13043 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
13044 if( offsets != NULL && offsets[i] != 0.0 )
13045 {
13046 SCIP_EXPR* sum;
13047 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
13048 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
13049 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
13050 }
13051 else
13052 {
13053 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
13054 }
13055
13056 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
13057 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
13058 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
13059 }
13060
13061 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
13062 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
13063 termcoefs[0] = 1.0;
13064
13065 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
13066 termcoefs[1] = -rhscoeff;
13067
13068 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
13069
13070 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13071 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13072
13073 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
13074
13075 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
13076
13077 return SCIP_OKAY;
13078}
13079
13080/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
13081 *
13082 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
13083 *
13084 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13085 */
13087 SCIP* scip, /**< SCIP data structure */
13088 SCIP_CONS** cons, /**< pointer to hold the created constraint */
13089 const char* name, /**< name of constraint */
13090 SCIP_VAR* x, /**< nonlinear variable x in constraint */
13091 SCIP_VAR* z, /**< linear variable z in constraint */
13092 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
13093 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
13094 SCIP_Real zcoef, /**< coefficient of z in constraint */
13095 SCIP_Real lhs, /**< left hand side of constraint */
13096 SCIP_Real rhs /**< right hand side of constraint */
13097 )
13098{
13099 SCIP_EXPR* xexpr;
13100 SCIP_EXPR* terms[2];
13101 SCIP_Real coefs[2];
13102 SCIP_EXPR* sumexpr;
13103
13104 assert(x != NULL);
13105 assert(z != NULL);
13106
13107 if( !SCIPisFinite(exponent) )
13108 {
13109 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13110 return SCIP_INVALIDDATA;
13111 }
13112
13113 if( !SCIPisFinite(xoffset) )
13114 {
13115 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13116 return SCIP_INVALIDDATA;
13117 }
13118
13119 if( !SCIPisFinite(zcoef) )
13120 {
13121 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
13122 return SCIP_INVALIDDATA;
13123 }
13124
13125 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
13126 if( xoffset != 0.0 )
13127 {
13128 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
13129 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
13130
13131 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13132 }
13133 else
13134 {
13135 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
13136 }
13137 coefs[0] = 1.0;
13138
13139 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
13140 coefs[1] = zcoef;
13141
13142 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
13143
13144 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
13145
13146 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
13147 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
13148 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
13149 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
13150
13151 return SCIP_OKAY;
13152}
13153
13154/** gets tag indicating current local variable bounds */
13156 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13157 )
13158{
13159 SCIP_CONSHDLRDATA* conshdlrdata;
13160
13161 assert(conshdlr != NULL);
13162 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13163
13164 return conshdlrdata->curboundstag;
13165}
13166
13167/** gets the `curboundstag` from the last time where variable bounds were relaxed */
13169 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13170 )
13171{
13172 SCIP_CONSHDLRDATA* conshdlrdata;
13173
13174 assert(conshdlr != NULL);
13175 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13176
13177 return conshdlrdata->lastboundrelax;
13178}
13179
13180/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
13181 *
13182 * @attention This method is not intended for normal use.
13183 * These tags are maintained by the event handler for variable bound change events.
13184 * This method is used by some unittests.
13185 */
13187 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13188 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
13189 )
13190{
13191 SCIP_CONSHDLRDATA* conshdlrdata;
13192
13193 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13194 assert(conshdlrdata != NULL);
13195
13196 ++conshdlrdata->curboundstag;
13197 assert(conshdlrdata->curboundstag > 0);
13198
13199 if( boundrelax )
13200 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
13201}
13202
13203/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
13205 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13206 )
13207{
13208 assert(conshdlr != NULL);
13209
13210 return SCIPconshdlrGetData(conshdlr)->var2expr;
13211}
13212
13213/** processes a rowprep for cut addition and maybe report branchscores */
13215 SCIP* scip, /**< SCIP data structure */
13216 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
13217 SCIP_CONS* cons, /**< nonlinear constraint */
13218 SCIP_EXPR* expr, /**< expression */
13219 SCIP_ROWPREP* rowprep, /**< cut to be added */
13220 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
13221 SCIP_VAR* auxvar, /**< auxiliary variable */
13222 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
13223 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
13224 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
13225 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
13226 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
13227 SCIP_RESULT* result /**< pointer to store the result */
13228 )
13229{
13230 SCIP_Real cutviol;
13231 SCIP_CONSHDLRDATA* conshdlrdata;
13232 SCIP_Real auxvarvalue = SCIP_INVALID;
13233 SCIP_Bool sepasuccess;
13234 SCIP_Real estimateval = SCIP_INVALID;
13235 SCIP_Real mincutviolation;
13236
13237 assert(nlhdlr != NULL);
13238 assert(cons != NULL);
13239 assert(expr != NULL);
13240 assert(rowprep != NULL);
13241 assert(auxvar != NULL);
13242 assert(result != NULL);
13243
13244 /* decide on minimal violation of cut */
13245 if( sol == NULL )
13246 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
13247 else
13248 mincutviolation = SCIPfeastol(scip);
13249
13250 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
13251 assert(conshdlrdata != NULL);
13252
13253 sepasuccess = TRUE;
13254
13255 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
13256 if( cutviol > 0.0 )
13257 {
13258 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
13259
13260 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
13261 if( !allowweakcuts && auxvalue != SCIP_INVALID )
13262 {
13263 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
13264 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
13265 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
13266 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
13267 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
13268 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
13269 *
13270 * if we are overestimating, we have z >= c'x-b >= f(x)
13271 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
13272 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
13273 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
13274 *
13275 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13276 */
13277 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13278 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13279 {
13280 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13281 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13282 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13283 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13284 sepasuccess = FALSE;
13285 }
13286 }
13287
13288 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13289 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13290 }
13291 else
13292 {
13293 sepasuccess = FALSE;
13294 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13295 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13296 }
13297
13298 /* clean up estimator */
13299 if( sepasuccess )
13300 {
13301 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13302 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13303 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13304 SCIPprintRowprep(scip, rowprep, enfologfile); )
13305
13306 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13307 * instead, may even scale them down, that is, scale so that max coef is close to 1
13308 */
13309 if( !allowweakcuts )
13310 {
13311 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13312
13313 if( !sepasuccess )
13314 {
13315 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13316 }
13317 else
13318 {
13319 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13320 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13321 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13322 if( sepasuccess )
13323 sepasuccess = cutviol > mincutviolation;
13324 }
13325
13326 if( sepasuccess && auxvalue != SCIP_INVALID )
13327 {
13328 /* check whether cut is weak now
13329 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13330 * reconstructing estimateval from cutviol (TODO improve or remove?)
13331 */
13332 SCIP_Real auxvarcoef = 0.0;
13333 int i;
13334
13335 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13336 * it should be...
13337 */
13338 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13339 {
13340 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13341 {
13342 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13343 break;
13344 }
13345 }
13346
13347 if( auxvarcoef == 0.0 ||
13348 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13349 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13350 {
13351 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13352 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13353 sepasuccess = FALSE;
13354 }
13355 }
13356 }
13357 else
13358 {
13359 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13360
13361 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13362 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13363 */
13364 if( !branchscoresuccess )
13366
13367 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13368
13369 if( !sepasuccess )
13370 {
13371 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13372 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13373 }
13374
13375 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13376 * changed
13377 */
13378 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13379 {
13380 SCIP_Real violscore;
13381
13382#ifdef BRSCORE_ABSVIOL
13383 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13384#else
13385 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13386#endif
13387 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13388
13389 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13390 * - were fixed,
13391 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13392 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13393 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13394 * so I'm disabling the assert for now
13395 */
13396 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13397 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13398 }
13399 }
13400 }
13401
13402 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13403 if( sepasuccess )
13404 {
13405 SCIP_ROW* row;
13406
13407 if( conshdlrdata->branchdualweight > 0.0 )
13408 {
13409 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13410 * skip if gap is zero
13411 */
13412 if( auxvalue == SCIP_INVALID )
13413 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13414 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13415 {
13416 char gap[40];
13417 /* coverity[secure_coding] */
13418 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13419 strcat(SCIProwprepGetName(rowprep), gap);
13420 }
13421 }
13422
13423 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13424
13425 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13426 {
13427 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13429 }
13430 else if( !SCIPisCutApplicable(scip, row) )
13431 {
13432 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13433 }
13434 else
13435 {
13436 SCIP_Bool infeasible;
13437
13438 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13439 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13440
13441 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13442 * if we haven't found strong cuts before)
13443 */
13444 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13445
13446 /* mark row as not removable from LP for current node (this can prevent some cycling) */
13447 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13449
13450 if( infeasible )
13451 {
13452 *result = SCIP_CUTOFF;
13454 }
13455 else
13456 {
13457 *result = SCIP_SEPARATED;
13459 }
13460 }
13461
13462 SCIP_CALL( SCIPreleaseRow(scip, &row) );
13463 }
13464 else if( branchscoresuccess )
13465 {
13466 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13467 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13468
13469 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13470 * expressions eligible for branching candidate, see enforceConstraints() and branching()
13471 */
13472 *result = SCIP_BRANCHED;
13473 }
13474 else
13475 {
13476 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13477 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13478 " (!)" : ""); )
13479 }
13480
13481 return SCIP_OKAY;
13482}
13483
13484/** returns whether all nonlinear constraints are assumed to be convex */
13486 SCIP_CONSHDLR* conshdlr
13487 )
13488{
13489 SCIP_CONSHDLRDATA* conshdlrdata;
13490
13491 assert(conshdlr != NULL);
13492
13493 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13494 assert(conshdlrdata != NULL);
13495
13496 return conshdlrdata->assumeconvex;
13497}
13498
13499/** collects all bilinear terms for a given set of constraints
13500 *
13501 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13502 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13503 */
13505 SCIP* scip, /**< SCIP data structure */
13506 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13507 SCIP_CONS** conss, /**< nonlinear constraints */
13508 int nconss /**< total number of nonlinear constraints */
13509 )
13510{
13511 assert(conshdlr != NULL);
13512 assert(conss != NULL || nconss == 0);
13513
13514 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13515
13516 return SCIP_OKAY;
13517}
13518
13519/** returns the total number of bilinear terms that are contained in all nonlinear constraints
13520 *
13521 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13522 */
13524 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13525 )
13526{
13527 SCIP_CONSHDLRDATA* conshdlrdata;
13528
13529 assert(conshdlr != NULL);
13530
13531 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13532 assert(conshdlrdata != NULL);
13533
13534 return conshdlrdata->nbilinterms;
13535}
13536
13537/** returns all bilinear terms that are contained in all nonlinear constraints
13538 *
13539 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13540 * @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.
13541 */
13543 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13544 )
13545{
13546 SCIP_CONSHDLRDATA* conshdlrdata;
13547
13548 assert(conshdlr != NULL);
13549
13550 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13551 assert(conshdlrdata != NULL);
13552
13553 return conshdlrdata->bilinterms;
13554}
13555
13556/** returns the index of the bilinear term representing the product of the two given variables
13557 *
13558 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13559 * @return The method returns -1 if the variables do not appear bilinearly.
13560 */
13562 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13563 SCIP_VAR* x, /**< first variable */
13564 SCIP_VAR* y /**< second variable */
13565 )
13566{
13567 SCIP_CONSHDLRDATA* conshdlrdata;
13569 int idx;
13570
13571 assert(conshdlr != NULL);
13572 assert(x != NULL);
13573 assert(y != NULL);
13574
13575 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13576 assert(conshdlrdata != NULL);
13577
13578 if( conshdlrdata->bilinhashtable == NULL )
13579 {
13580 return -1;
13581 }
13582
13583 /* ensure that x.index <= y.index */
13584 if( SCIPvarCompare(x, y) == 1 )
13585 {
13586 SCIPswapPointers((void**)&x, (void**)&y);
13587 }
13588 assert(SCIPvarCompare(x, y) < 1);
13589
13590 /* use a new entry to find the image in the bilinear hash table */
13591 entry.x = x;
13592 entry.y = y;
13593 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13594 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13595 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13596 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13597
13598 return idx;
13599}
13600
13601/** returns the bilinear term that represents the product of two given variables
13602 *
13603 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13604 * @return The method returns NULL if the variables do not appear bilinearly.
13605 */
13607 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13608 SCIP_VAR* x, /**< first variable */
13609 SCIP_VAR* y /**< second variable */
13610 )
13611{
13612 SCIP_CONSHDLRDATA* conshdlrdata;
13613 int idx;
13614
13615 assert(conshdlr != NULL);
13616 assert(x != NULL);
13617 assert(y != NULL);
13618
13619 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13620 assert(conshdlrdata != NULL);
13621
13622 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13623 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13624
13625 if( idx >= 0 )
13626 {
13627 return &conshdlrdata->bilinterms[idx];
13628 }
13629
13630 return NULL;
13631}
13632
13633/** evaluates an auxiliary expression for a bilinear term */
13635 SCIP* scip, /**< SCIP data structure */
13636 SCIP_VAR* x, /**< first variable of the bilinear term */
13637 SCIP_VAR* y, /**< second variable of the bilinear term */
13638 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13639 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13640 )
13641{
13642 assert(scip != NULL);
13643 assert(x != NULL);
13644 assert(y != NULL);
13645 assert(auxexpr != NULL);
13646 assert(auxexpr->auxvar != NULL);
13647
13648 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13649 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13650}
13651
13652/** stores the variables of a bilinear term in the data of the constraint handler */
13654 SCIP* scip, /**< SCIP data structure */
13655 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13656 SCIP_VAR* x, /**< first variable */
13657 SCIP_VAR* y, /**< second variable */
13658 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13659 int nlockspos, /**< number of positive expression locks */
13660 int nlocksneg /**< number of negative expression locks */
13661 )
13662{
13663 SCIP_CONSHDLRDATA* conshdlrdata;
13665 int idx;
13666
13667 assert(conshdlr != NULL);
13668
13669 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13670 assert(conshdlrdata != NULL);
13671
13672 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13673
13674 term = &conshdlrdata->bilinterms[idx];
13675 assert(term != NULL);
13676 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13677 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) */
13678
13679 /* store and capture auxiliary variable */
13680 if( auxvar != NULL )
13681 {
13682 term->aux.var = auxvar;
13683 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13684 }
13685
13686 return SCIP_OKAY;
13687}
13688
13689/** stores the variables of a bilinear term in the data of the constraint handler */
13691 SCIP* scip, /**< SCIP data structure */
13692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13693 SCIP_VAR* x, /**< first variable */
13694 SCIP_VAR* y, /**< second variable */
13695 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13696 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13697 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13698 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13699 SCIP_Real cst, /**< constant of the auxiliary expression */
13700 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13701 )
13702{
13703 SCIP_CONSHDLRDATA* conshdlrdata;
13706 int idx;
13707 int nlockspos;
13708 int nlocksneg;
13709 SCIP_Bool added;
13710
13711 assert(conshdlr != NULL);
13712
13713 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13714 assert(conshdlrdata != NULL);
13715
13716 nlockspos = overestimate ? 1 : 0;
13717 nlocksneg = overestimate ? 0 : 1;
13718
13719 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13720
13721 term = &conshdlrdata->bilinterms[idx];
13722 assert(term != NULL);
13723 assert(SCIPvarCompare(term->x, term->y) < 1);
13724
13725 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13726 {
13727 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13728 /* this is the case where we are adding an implicitly defined relation for a product that has already
13729 * been explicitly defined; convert auxvar into an auxexpr */
13730
13731 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13732 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13733 return SCIP_OKAY;
13734
13735 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13736 auxvarexpr->cst = 0.0;
13737 auxvarexpr->coefs[0] = 1.0;
13738 auxvarexpr->coefs[1] = 0.0;
13739 auxvarexpr->coefs[2] = 0.0;
13740 auxvarexpr->auxvar = term->aux.var;
13741 auxvarexpr->underestimate = term->nlocksneg > 0;
13742 auxvarexpr->overestimate = term->nlockspos > 0;
13743
13744 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13745 term->aux.exprs = NULL;
13746
13747 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13748
13749 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13750 assert(added);
13751 }
13752
13753 /* create and add auxexpr */
13754 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13755 auxexpr->underestimate = !overestimate;
13756 auxexpr->overestimate = overestimate;
13757 auxexpr->auxvar = auxvar;
13758 auxexpr->coefs[0] = coefaux;
13759 if( term->x == x )
13760 {
13761 assert(term->y == y);
13762 auxexpr->coefs[1] = coefx;
13763 auxexpr->coefs[2] = coefy;
13764 }
13765 else
13766 {
13767 assert(term->x == y);
13768 assert(term->y == x);
13769 auxexpr->coefs[1] = coefy;
13770 auxexpr->coefs[2] = coefx;
13771 }
13772 auxexpr->cst = cst;
13773 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13774
13775 if( !added )
13776 {
13777 SCIPfreeBlockMemory(scip, &auxexpr);
13778 }
13779 else if( auxvar != NULL )
13780 { /* capture auxiliary variable */
13781 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13782 }
13783
13784 return SCIP_OKAY;
13785}
13786
13787/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13789 SCIP* scip, /**< SCIP data structure */
13790 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13791 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13792 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13793 void* fundata, /**< data for function evaluation (can be NULL) */
13794 SCIP_Real* xstar, /**< point to be separated */
13795 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13796 int nallvars, /**< half of the length of box */
13797 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13798 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13799 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13800 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13801 )
13802{
13803 SCIP_Real* corner;
13804 SCIP_Real* funvals;
13805 int* nonfixedpos;
13806 SCIP_Real maxfaceterror;
13807 int nvars; /* number of nonfixed variables */
13808 unsigned int ncorners;
13809 unsigned int i;
13810 int j;
13811
13812 assert(scip != NULL);
13813 assert(conshdlr != NULL);
13814 assert(function != NULL);
13815 assert(xstar != NULL);
13816 assert(box != NULL);
13817 assert(success != NULL);
13818 assert(facetcoefs != NULL);
13819 assert(facetconstant != NULL);
13820
13821 *success = FALSE;
13822
13823 /* identify fixed variables */
13824 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13825 nvars = 0;
13826 for( j = 0; j < nallvars; ++j )
13827 {
13828 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13829 continue;
13830 nonfixedpos[nvars] = j;
13831 nvars++;
13832 }
13833
13834 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13835 * if too many variables are not fixed, then we do nothing currently
13836 */
13837 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13838 {
13839 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13840 SCIPfreeBufferArray(scip, &nonfixedpos);
13841 return SCIP_OKAY;
13842 }
13843
13844 /* compute f(v^i) for each corner v^i of [l,u] */
13845 ncorners = POWEROFTWO(nvars);
13846 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13847 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13848 for( j = 0; j < nallvars; ++j )
13849 {
13850 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13851 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13852 }
13853 for( i = 0; i < ncorners; ++i )
13854 {
13855 SCIPdebugMsg(scip, "corner %u: ", i);
13856 for( j = 0; j < nvars; ++j )
13857 {
13858 int varpos = nonfixedpos[j];
13859 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13860 * we check this by shifting i for j positions to the right and checking whether the last bit is set
13861 */
13862 if( (i >> j) & 0x1 )
13863 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13864 else
13865 corner[varpos] = box[2 * varpos ]; /* lb of var */
13866 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13867 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13868 }
13869
13870 funvals[i] = function(corner, nallvars, fundata);
13871
13872 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13873
13874 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13875 {
13876 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13877 goto CLEANUP;
13878 }
13879 }
13880
13881 /* clear coefs array; below we only fill in coefs for nonfixed variables */
13882 BMSclearMemoryArray(facetcoefs, nallvars);
13883
13884 if( nvars == 1 )
13885 {
13886 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13887
13888 /* check whether target has been missed */
13889 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13890 {
13891 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13892 *success = FALSE;
13893 }
13894 }
13895 else if( nvars == 2 && SCIPlapackIsAvailable() )
13896 {
13897 int idx1 = nonfixedpos[0];
13898 int idx2 = nonfixedpos[1];
13899 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13900 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13901 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13902 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13903 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13904 SCIP_Real coefs[2] = { 0.0, 0.0 };
13905
13906 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13907
13908 facetcoefs[idx1] = coefs[0];
13909 facetcoefs[idx2] = coefs[1];
13910 }
13911 else
13912 {
13913 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13914 }
13915 if( !*success )
13916 {
13917 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13918 goto CLEANUP;
13919 }
13920
13921 /*
13922 * check and adjust facet with the algorithm of Rikun et al.
13923 */
13924
13925 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13926
13927 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13928 if( maxfaceterror > 0.0 )
13929 {
13930 SCIP_CONSHDLRDATA* conshdlrdata;
13931 SCIP_Real midval;
13932 SCIP_Real feastol;
13933
13935
13936 /* evaluate function in middle point to get some idea for a scaling */
13937 for( j = 0; j < nvars; ++j )
13938 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13939 midval = function(corner, nallvars, fundata);
13940 if( midval == SCIP_INVALID )
13941 midval = 1.0;
13942
13943 conshdlrdata = SCIPconshdlrGetData(conshdlr);
13944 assert(conshdlrdata != NULL);
13945
13946 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13947 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13948 {
13949 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13950 *success = FALSE;
13951 goto CLEANUP;
13952 }
13953
13954 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13955
13956 if( overestimate )
13957 *facetconstant += maxfaceterror;
13958 else
13959 *facetconstant -= maxfaceterror;
13960 }
13961
13962 /* if we made it until here, then we have a nice facet */
13963 assert(*success);
13964
13965CLEANUP:
13966 /* free allocated memory */
13967 SCIPfreeBufferArray(scip, &corner);
13968 SCIPfreeBufferArray(scip, &funvals);
13969 SCIPfreeBufferArray(scip, &nonfixedpos);
13970
13971 return SCIP_OKAY;
13972}
13973
13974/*
13975 * constraint specific interface methods
13976 */
13977
13978/** returns the expression of the given nonlinear constraint */
13980 SCIP_CONS* cons /**< constraint data */
13981 )
13982{
13983 SCIP_CONSDATA* consdata;
13984
13985 assert(cons != NULL);
13986 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13987
13988 consdata = SCIPconsGetData(cons);
13989 assert(consdata != NULL);
13990
13991 return consdata->expr;
13992}
13993
13994/** gets the left hand side of a nonlinear constraint */
13996 SCIP_CONS* cons /**< constraint data */
13997 )
13998{
13999 SCIP_CONSDATA* consdata;
14000
14001 assert(cons != NULL);
14002 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14003
14004 consdata = SCIPconsGetData(cons);
14005 assert(consdata != NULL);
14006
14007 return consdata->lhs;
14008}
14009
14010/** gets the right hand side of a nonlinear constraint */
14012 SCIP_CONS* cons /**< constraint data */
14013 )
14014{
14015 SCIP_CONSDATA* consdata;
14016
14017 assert(cons != NULL);
14018 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14019
14020 consdata = SCIPconsGetData(cons);
14021 assert(consdata != NULL);
14022
14023 return consdata->rhs;
14024}
14025
14026/** gets the nonlinear constraint as a nonlinear row representation. */
14028 SCIP* scip, /**< SCIP data structure */
14029 SCIP_CONS* cons, /**< constraint */
14030 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14031 )
14032{
14033 SCIP_CONSDATA* consdata;
14034
14035 assert(cons != NULL);
14036 assert(nlrow != NULL);
14037 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14038
14039 consdata = SCIPconsGetData(cons);
14040 assert(consdata != NULL);
14041
14042 if( consdata->nlrow == NULL )
14043 {
14044 SCIP_CALL( createNlRow(scip, cons) );
14045 }
14046 assert(consdata->nlrow != NULL);
14047 *nlrow = consdata->nlrow;
14048
14049 return SCIP_OKAY;
14050}
14051
14052/** returns the curvature of the expression of a given nonlinear constraint
14053 *
14054 * @note The curvature information is computed during CONSINITSOL.
14055 */
14057 SCIP_CONS* cons /**< constraint data */
14058 )
14059{
14060 SCIP_CONSDATA* consdata;
14061
14062 assert(cons != NULL);
14063 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14064
14065 consdata = SCIPconsGetData(cons);
14066 assert(consdata != NULL);
14067
14068 return consdata->curv;
14069}
14070
14071/** checks whether expression of constraint can be represented as quadratic form
14072 *
14073 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
14074 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
14075 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
14076 */
14078 SCIP* scip, /**< SCIP data structure */
14079 SCIP_CONS* cons, /**< constraint data */
14080 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
14081 )
14082{
14083 SCIP_CONSDATA* consdata;
14084
14085 assert(scip != NULL);
14086 assert(cons != NULL);
14087 assert(isquadratic != NULL);
14088 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14089
14090 consdata = SCIPconsGetData(cons);
14091 assert(consdata != NULL);
14092 assert(consdata->expr != NULL);
14093
14094 /* check whether constraint expression is quadratic in extended formulation */
14095 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
14096
14097 /* if not quadratic in non-extended formulation, then do indicate quadratic */
14098 if( *isquadratic )
14099 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
14100
14101 return SCIP_OKAY;
14102}
14103
14104/** changes left-hand-side of a nonlinear constraint
14105 *
14106 * @attention This method can only be called in the problem stage.
14107 */
14109 SCIP* scip, /**< SCIP data structure */
14110 SCIP_CONS* cons, /**< constraint data */
14111 SCIP_Real lhs /**< new left-hand-side */
14112 )
14113{
14114 SCIP_CONSDATA* consdata;
14115
14116 assert(scip != NULL);
14117 assert(cons != NULL);
14118 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14119
14121 {
14122 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14123 return SCIP_INVALIDCALL;
14124 }
14125
14126 /* we should have an original constraint */
14127 assert(SCIPconsIsOriginal(cons));
14128
14129 consdata = SCIPconsGetData(cons);
14130 assert(consdata != NULL);
14131
14132 if( consdata->lhs == lhs )
14133 return SCIP_OKAY;
14134
14135 consdata->lhs = lhs;
14136
14137 /* not sure we care about any of these flags for original constraints */
14138 consdata->ispropagated = FALSE;
14139
14140 return SCIP_OKAY;
14141}
14142
14143/** changes right-hand-side of a nonlinear constraint
14144 *
14145 * @attention This method can only be called in the problem stage.
14146 */
14148 SCIP* scip, /**< SCIP data structure */
14149 SCIP_CONS* cons, /**< constraint data */
14150 SCIP_Real rhs /**< new right-hand-side */
14151 )
14152{
14153 SCIP_CONSDATA* consdata;
14154
14155 assert(scip != NULL);
14156 assert(cons != NULL);
14157 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
14158
14160 {
14161 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
14162 return SCIP_INVALIDCALL;
14163 }
14164
14165 /* we should have an original constraint */
14166 assert(SCIPconsIsOriginal(cons));
14167
14168 consdata = SCIPconsGetData(cons);
14169 assert(consdata != NULL);
14170
14171 if( consdata->rhs == rhs )
14172 return SCIP_OKAY;
14173
14174 consdata->rhs = rhs;
14175
14176 /* not sure we care about any of these flags for original constraints */
14177 consdata->ispropagated = FALSE;
14178
14179 return SCIP_OKAY;
14180}
14181
14182/** changes expression of a nonlinear constraint
14183 *
14184 * @attention This method can only be called in the problem stage.
14185 */
14187 SCIP* scip, /**< SCIP data structure */
14188 SCIP_CONS* cons, /**< constraint data */
14189 SCIP_EXPR* expr /**< new expression */
14190 )
14191{
14192 SCIP_CONSHDLR* conshdlr;
14193 SCIP_CONSDATA* consdata;
14194
14195 assert(scip != NULL);
14196 assert(cons != NULL);
14197 assert(expr != NULL);
14198
14200 {
14201 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
14202 return SCIP_INVALIDCALL;
14203 }
14204
14205 /* we should have an original constraint */
14206 assert(SCIPconsIsOriginal(cons));
14207
14208 conshdlr = SCIPconsGetHdlr(cons);
14209 assert(conshdlr != NULL);
14210 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14211
14212 consdata = SCIPconsGetData(cons);
14213 assert(consdata != NULL);
14214 assert(consdata->expr != NULL);
14215
14216 /* we should not have collected additional data for the expr
14217 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14218 */
14219 assert(consdata->nvarexprs == 0);
14220 assert(consdata->varexprs == NULL);
14221 assert(!consdata->catchedevents);
14222
14223 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
14224
14225 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14226 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14227
14228 /* not sure we care about any of these flags for original constraints */
14229 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
14230 consdata->issimplified = FALSE;
14231 consdata->ispropagated = FALSE;
14232
14233 return SCIP_OKAY;
14234}
14235
14236/** adds coef * var to nonlinear constraint
14237 *
14238 * @attention This method can only be called in the problem stage.
14239 */
14241 SCIP* scip, /**< SCIP data structure */
14242 SCIP_CONS* cons, /**< constraint data */
14243 SCIP_VAR* var, /**< variable */
14244 SCIP_Real coef /**< coefficient */
14245 )
14246{
14247 SCIP_CONSHDLR* conshdlr;
14248 SCIP_CONSDATA* consdata;
14249 SCIP_EXPR* varexpr;
14250
14251 assert(scip != NULL);
14252 assert(cons != NULL);
14253
14255 {
14256 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14257 return SCIP_INVALIDCALL;
14258 }
14259
14260 /* we should have an original constraint */
14261 assert(SCIPconsIsOriginal(cons));
14262
14263 if( coef == 0.0 )
14264 return SCIP_OKAY;
14265
14266 conshdlr = SCIPconsGetHdlr(cons);
14267 assert(conshdlr != NULL);
14268 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14269
14270 consdata = SCIPconsGetData(cons);
14271 assert(consdata != NULL);
14272 assert(consdata->expr != NULL);
14273
14274 /* we should not have collected additional data for it
14275 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14276 */
14277 assert(consdata->nvarexprs == 0);
14278 assert(consdata->varexprs == NULL);
14279 assert(!consdata->catchedevents);
14280
14281 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14282
14283 /* append to sum, if consdata->expr is sum and not used anywhere else */
14284 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14285 {
14286 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14287 }
14288 else
14289 {
14290 /* create new expression = 1 * consdata->expr + coef * var */
14291 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14292 SCIP_Real coefs[2] = { 1.0, coef };
14293
14294 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14295
14296 /* release old root expr */
14297 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14298 }
14299
14300 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14301
14302 /* not sure we care about any of these flags for original constraints */
14303 consdata->issimplified = FALSE;
14304 consdata->ispropagated = FALSE;
14305
14306 return SCIP_OKAY;
14307}
14308
14309/** adds coef * expr to nonlinear constraint
14310 *
14311 * @attention This method can only be called in the problem stage.
14312 */
14314 SCIP* scip, /**< SCIP data structure */
14315 SCIP_CONS* cons, /**< nonlinear constraint */
14316 SCIP_EXPR* expr, /**< expression */
14317 SCIP_Real coef /**< coefficient */
14318 )
14319{
14320 SCIP_CONSHDLR* conshdlr;
14321 SCIP_CONSDATA* consdata;
14322 SCIP_EXPR* exprowned;
14323
14324 assert(scip != NULL);
14325 assert(cons != NULL);
14326
14328 {
14329 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
14330 return SCIP_INVALIDCALL;
14331 }
14332
14333 /* we should have an original constraint */
14334 assert(SCIPconsIsOriginal(cons));
14335
14336 if( coef == 0.0 )
14337 return SCIP_OKAY;
14338
14339 conshdlr = SCIPconsGetHdlr(cons);
14340 assert(conshdlr != NULL);
14341 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14342
14343 consdata = SCIPconsGetData(cons);
14344 assert(consdata != NULL);
14345 assert(consdata->expr != NULL);
14346
14347 /* free quadratic representation, if any is stored */
14348 SCIPfreeExprQuadratic(scip, consdata->expr);
14349
14350 /* free varexprs in consdata, in case they have been stored
14351 * (e.g., by a call to consGet(N)VarsNonlinear)
14352 */
14353 SCIP_CALL( freeVarExprs(scip, consdata) );
14354
14355 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14356 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14357
14358 /* append to sum, if consdata->expr is sum and not used anywhere else */
14359 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14360 {
14361 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14362 }
14363 else
14364 {
14365 /* create new expression = 1 * consdata->expr + coef * var */
14366 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14367 SCIP_Real coefs[2] = { 1.0, coef };
14368
14369 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14370
14371 /* release old root expr */
14372 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14373 }
14374
14375 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14376
14377 /* not sure we care about any of these flags for original constraints */
14378 consdata->issimplified = FALSE;
14379 consdata->ispropagated = FALSE;
14380
14381 return SCIP_OKAY;
14382}
14383
14384/** computes value of constraint expression in a given solution
14385 *
14386 * Stores value of constraint expression in sol in activity.
14387 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14388 */
14390 SCIP* scip, /**< SCIP data structure */
14391 SCIP_CONS* cons, /**< constraint */
14392 SCIP_SOL* sol, /**< solution */
14393 SCIP_Real* activity /**< buffer to store computed activity */
14394 )
14395{
14396 SCIP_CONSDATA* consdata;
14397
14398 assert(cons != NULL);
14399 assert(activity != NULL);
14400
14401 consdata = SCIPconsGetData(cons);
14402 assert(consdata != NULL);
14403
14404 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14405 *activity = SCIPexprGetEvalValue(consdata->expr);
14406
14407 return SCIP_OKAY;
14408}
14409
14410/** gets absolute violation of nonlinear constraint
14411 *
14412 * This function evaluates the constraints in the given solution.
14413 *
14414 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14415 */
14417 SCIP* scip, /**< SCIP data structure */
14418 SCIP_CONS* cons, /**< constraint */
14419 SCIP_SOL* sol, /**< solution to check */
14420 SCIP_Real* viol /**< buffer to store computed violation */
14421 )
14422{
14423 assert(cons != NULL);
14424 assert(viol != NULL);
14425
14426 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14427 *viol = getConsAbsViolation(cons);
14428
14429 return SCIP_OKAY;
14430}
14431
14432/** gets scaled violation of nonlinear constraint
14433 *
14434 * This function evaluates the constraints in the given solution.
14435 *
14436 * The scaling that is applied to the absolute violation of the constraint
14437 * depends on the setting of parameter constraints/nonlinear/violscale.
14438 */
14440 SCIP* scip, /**< SCIP data structure */
14441 SCIP_CONS* cons, /**< constraint */
14442 SCIP_SOL* sol, /**< solution to check */
14443 SCIP_Real* viol /**< buffer to store computed violation */
14444 )
14445{
14446 assert(cons != NULL);
14447 assert(viol != NULL);
14448
14449 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14450 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14451
14452 return SCIP_OKAY;
14453}
14454
14455/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14457 SCIP* scip, /**< SCIP data structure */
14458 SCIP_CONS* cons, /**< nonlinear constraint */
14459 SCIP_VAR** var, /**< pointer to store the variable */
14460 SCIP_Real* coef /**< pointer to store the coefficient */
14461 )
14462{
14463 SCIP_CONSDATA* consdata;
14464
14465 assert(cons != NULL);
14466 assert(var != NULL);
14467 assert(coef != NULL);
14468
14469 /* check for a linear variable that can be increased or decreased without harming feasibility */
14471
14472 consdata = SCIPconsGetData(cons);
14473 assert(consdata != NULL);
14474
14475 *var = consdata->linvardecr;
14476 *coef = consdata->linvardecrcoef;
14477}
14478
14479/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14481 SCIP* scip, /**< SCIP data structure */
14482 SCIP_CONS* cons, /**< nonlinear constraint */
14483 SCIP_VAR** var, /**< pointer to store the variable */
14484 SCIP_Real* coef /**< pointer to store the coefficient */
14485 )
14486{
14487 SCIP_CONSDATA* consdata;
14488
14489 assert(cons != NULL);
14490 assert(var != NULL);
14491 assert(coef != NULL);
14492
14493 /* check for a linear variable that can be increased or decreased without harming feasibility */
14495
14496 consdata = SCIPconsGetData(cons);
14497 assert(consdata != NULL);
14498
14499 *var = consdata->linvarincr;
14500 *coef = consdata->linvarincrcoef;
14501}
14502
14503
14504/*
14505 * Methods for Expressions in Nonlinear Constraints
14506 */
14507
14508/** returns the number of positive rounding locks of an expression */
14510 SCIP_EXPR* expr /**< expression */
14511 )
14512{
14513 assert(expr != NULL);
14514 assert(SCIPexprGetOwnerData(expr) != NULL);
14515
14516 return SCIPexprGetOwnerData(expr)->nlockspos;
14517}
14518
14519/** returns the number of negative rounding locks of an expression */
14521 SCIP_EXPR* expr /**< expression */
14522 )
14523{
14524 assert(expr != NULL);
14525 assert(SCIPexprGetOwnerData(expr) != NULL);
14526
14527 return SCIPexprGetOwnerData(expr)->nlocksneg;
14528}
14529
14530/** returns the variable used for linearizing a given expression (return value might be NULL)
14531 *
14532 * @note for variable expression it returns the corresponding variable
14533 */
14535 SCIP_EXPR* expr /**< expression */
14536 )
14537{
14538 SCIP_EXPR_OWNERDATA* ownerdata;
14539
14540 assert(expr != NULL);
14541
14542 ownerdata = SCIPexprGetOwnerData(expr);
14543 assert(ownerdata != NULL);
14544
14545 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14546}
14547
14548/** returns the number of enforcements for an expression */
14550 SCIP_EXPR* expr /**< expression */
14551 )
14552{
14553 assert(expr != NULL);
14554 assert(SCIPexprGetOwnerData(expr) != NULL);
14555
14556 return SCIPexprGetOwnerData(expr)->nenfos;
14557}
14558
14559/** returns the data for one of the enforcements of an expression */
14561 SCIP_EXPR* expr, /**< expression */
14562 int idx, /**< position of enforcement in enfos array */
14563 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14564 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14565 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14566 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14567 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14568 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14569 )
14570{
14571 SCIP_EXPR_OWNERDATA* ownerdata;
14572
14573 assert(expr != NULL);
14574
14575 ownerdata = SCIPexprGetOwnerData(expr);
14576 assert(ownerdata != NULL);
14577 assert(idx >= 0);
14578 assert(idx < ownerdata->nenfos);
14579 assert(ownerdata->enfos[idx] != NULL);
14580 assert(nlhdlr != NULL);
14581
14582 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14583
14584 if( nlhdlrexprdata != NULL )
14585 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14586
14587 if( nlhdlrparticipation != NULL )
14588 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14589
14590 if( sepabelowusesactivity != NULL )
14591 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14592
14593 if( sepaaboveusesactivity != NULL )
14594 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14595
14596 if( auxvalue != NULL )
14597 *auxvalue = ownerdata->enfos[idx]->auxvalue;
14598}
14599
14600/** sets the auxiliary value of expression for one of the enforcements of an expression */
14602 SCIP_EXPR* expr, /**< expression */
14603 int idx, /**< position of enforcement in enfos array */
14604 SCIP_Real auxvalue /**< the new value of auxval */
14605 )
14606{
14607 SCIP_EXPR_OWNERDATA* ownerdata;
14608
14609 assert(expr != NULL);
14610
14611 ownerdata = SCIPexprGetOwnerData(expr);
14612 assert(ownerdata != NULL);
14613
14614 assert(idx >= 0);
14615 assert(idx < ownerdata->nenfos);
14616 assert(ownerdata->enfos[idx] != NULL);
14617
14618 ownerdata->enfos[idx]->auxvalue = auxvalue;
14619}
14620
14621/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14622 *
14623 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14624 */
14626 SCIP_EXPR* expr /**< expression */
14627 )
14628{
14629 assert(expr != NULL);
14630 assert(SCIPexprGetOwnerData(expr) != NULL);
14631
14632 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14633}
14634
14635/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14636 *
14637 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14638 */
14640 SCIP_EXPR* expr /**< expression */
14641 )
14642{
14643 assert(expr != NULL);
14644 assert(SCIPexprGetOwnerData(expr) != NULL);
14645
14646 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14647}
14648
14649/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14650 *
14651 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14652 */
14654 SCIP_EXPR* expr /**< expression */
14655 )
14656{
14657 assert(expr != NULL);
14658 assert(SCIPexprGetOwnerData(expr) != NULL);
14659
14660 return SCIPexprGetOwnerData(expr)->nauxvaruses;
14661}
14662
14663/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14664 *
14665 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14666 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14667 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14668 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14669 * and also increments this count for all variables in the expression.
14670 *
14671 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14672 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14673 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14674 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14675 */
14677 SCIP* scip, /**< SCIP data structure */
14678 SCIP_EXPR* expr, /**< expression */
14679 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14680 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14681 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14682 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14683 )
14684{
14685 SCIP_EXPR_OWNERDATA* ownerdata;
14686
14687 assert(expr != NULL);
14688
14689 ownerdata = SCIPexprGetOwnerData(expr);
14690 assert(ownerdata != NULL);
14691
14692 /* do not store auxvar request for variable expressions */
14693 if( useauxvar && SCIPisExprVar(scip, expr) )
14694 useauxvar = FALSE;
14695
14696 if( ownerdata->nenfos >= 0 &&
14697 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14698 (ownerdata->nauxvaruses == 0 && useauxvar)
14699 ) )
14700 {
14701 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14702 * we require additional enforcement methods, that is,
14703 * - activity of expr was not used before but will be used now, or
14704 * - auxiliary variable of expr was not required before but will be used now
14705 */
14706 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14707 }
14708
14709 if( useauxvar )
14710 ++ownerdata->nauxvaruses;
14711
14712 if( useactivityforprop )
14713 ++ownerdata->nactivityusesprop;
14714
14715 if( useactivityforsepabelow || useactivityforsepaabove )
14716 ++ownerdata->nactivityusessepa;
14717
14718 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14719 * information is used in detectNlhdlr()
14720 */
14721 if( useactivityforsepabelow )
14722 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14723 if( useactivityforsepaabove )
14724 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14725
14726 if( useactivityforprop )
14727 {
14728 /* if activity will be used for propagation, then make sure there is a valid activity
14729 * this way, we can do a reversepropcall after detectNlhdlr
14730 */
14732 }
14733
14734 /* increase the nactivityusedsepa counter for all variables used in the given expression */
14735 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14736 {
14737 SCIP_EXPRITER* it;
14738
14739 /* create and initialize iterator */
14742
14743 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14744 if( SCIPisExprVar(scip, expr) )
14745 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14746
14747 /* free iterator */
14748 SCIPfreeExpriter(&it);
14749 }
14750
14751 return SCIP_OKAY;
14752}
14753
14754/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14755 *
14756 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14757 * Assume that f(x) is associated with auxiliary variable z.
14758 *
14759 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14760 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14761 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14762 *
14763 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14764 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14765 */
14767 SCIP* scip, /**< SCIP data structure */
14768 SCIP_EXPR* expr, /**< expression */
14769 SCIP_SOL* sol, /**< solution */
14770 SCIP_Longint soltag, /**< tag of solution */
14771 SCIP_Real* viol, /**< buffer to store computed violation */
14772 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14773 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14774 )
14775{
14776 assert(scip != NULL);
14777 assert(expr != NULL);
14778 assert(viol != NULL);
14779
14780 /* make sure expression has been evaluated */
14781 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14782
14783 /* get violation from internal method */
14784 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14785
14786 return SCIP_OKAY;
14787}
14788
14789/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14790 *
14791 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14792 * Assume that f(w) is associated with auxiliary variable z.
14793 *
14794 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14795 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14796 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14797 *
14798 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14799 * both `violover` and `violunder` are set to TRUE.
14800 */
14802 SCIP* scip, /**< SCIP data structure */
14803 SCIP_EXPR* expr, /**< expression */
14804 SCIP_Real auxvalue, /**< the value of f(w) */
14805 SCIP_SOL* sol, /**< solution that has been evaluated */
14806 SCIP_Real* viol, /**< buffer to store computed violation */
14807 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14808 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14809 )
14810{
14811 assert(scip != NULL);
14812 assert(expr != NULL);
14813 assert(viol != NULL);
14814
14815 /* get violation from internal method */
14816 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14817
14818 return SCIP_OKAY;
14819}
14820
14821
14822/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14823 *
14824 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14825 * Assume that f(w) is associated with auxiliary variable z.
14826 *
14827 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14828 * the absolute violation divided by max(1,|f(w)|).
14829 *
14830 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14831 * both `violover` and `violunder` are set to TRUE.
14832 */
14834 SCIP* scip, /**< SCIP data structure */
14835 SCIP_EXPR* expr, /**< expression */
14836 SCIP_Real auxvalue, /**< the value of f(w) */
14837 SCIP_SOL* sol, /**< solution that has been evaluated */
14838 SCIP_Real* viol, /**< buffer to store computed violation */
14839 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14840 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14841 )
14842{
14843 assert(scip != NULL);
14844 assert(expr != NULL);
14845 assert(viol != NULL);
14846
14847 /* get violation from internal method */
14848 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14849
14850 if( !SCIPisInfinity(scip, *viol) )
14851 {
14852 assert(auxvalue != SCIP_INVALID);
14853 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14854 *viol /= MAX(1.0, REALABS(auxvalue));
14855 }
14856
14857 return SCIP_OKAY;
14858}
14859
14860/** returns bounds on the expression
14861 *
14862 * This gives an intersection of bounds from
14863 * - activity calculation (SCIPexprGetActivity()), if valid,
14864 * - auxiliary variable, if present,
14865 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14866 *
14867 * @note The returned interval can be empty!
14868 */
14870 SCIP* scip, /**< SCIP data structure */
14871 SCIP_EXPR* expr /**< expression */
14872 )
14873{
14874 SCIP_EXPR_OWNERDATA* ownerdata;
14875 SCIP_CONSHDLRDATA* conshdlrdata;
14876 SCIP_INTERVAL bounds;
14877
14878 assert(scip != NULL);
14879 assert(expr != NULL);
14880
14881 ownerdata = SCIPexprGetOwnerData(expr);
14882 assert(ownerdata != NULL);
14883
14884 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14885 assert(conshdlrdata != NULL);
14886
14887 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14888
14889 /* start with propbounds if they belong to current propagation */
14890 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14891 {
14892 bounds = ownerdata->propbounds;
14893 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14894 }
14895 else
14897
14898 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14899 {
14900 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14901 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14903 }
14904
14905 if( ownerdata->auxvar != NULL )
14906 {
14907 /* apply auxiliary variable bounds to bounds */
14908 SCIP_INTERVAL auxvarbounds;
14909
14910 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14911 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14912 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14913 }
14914
14915 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14916
14917 return bounds;
14918}
14919
14920/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14921 * corresponding (auxiliary) variable (if any)
14922 *
14923 * @attention this function should only be called during domain propagation in cons_nonlinear
14924 */
14926 SCIP* scip, /**< SCIP data structure */
14927 SCIP_EXPR* expr, /**< expression to be tightened */
14928 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14929 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14930 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14931 )
14932{
14933 SCIP_EXPR_OWNERDATA* ownerdata;
14934 SCIP_CONSHDLRDATA* conshdlrdata;
14935
14936 assert(scip != NULL);
14937 assert(expr != NULL);
14938 assert(cutoff != NULL);
14939
14940 ownerdata = SCIPexprGetOwnerData(expr);
14941 assert(ownerdata != NULL);
14942 assert(ownerdata->conshdlr != NULL);
14943
14944 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14945 assert(conshdlrdata != NULL);
14946
14947 /* the code below assumes that current activity is valid
14948 * if it turns out that we cannot ensure that, then we should change code
14949 */
14950 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14952
14953 *cutoff = FALSE;
14954
14955#ifdef DEBUG_PROP
14956 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14957 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14958 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14959#endif
14960
14961 if( SCIPexprIsIntegral(expr) )
14962 {
14963 /* apply integrality to new bounds
14964 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14965 */
14966 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14967 newbounds.inf = SCIPceil(scip, newbounds.inf);
14968 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14969 newbounds.sup = SCIPfloor(scip, newbounds.sup);
14970#ifdef DEBUG_PROP
14971 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14972#endif
14973 }
14974
14976 {
14977 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14978
14979 *cutoff = TRUE;
14980 return SCIP_OKAY;
14981 }
14982
14983 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14984 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14985 {
14986 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14987
14988 *cutoff = TRUE;
14989 return SCIP_OKAY;
14990 }
14991
14992 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14993 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14994 {
14995 /* if already having propbounds in expr, then tighten newbounds by propbounds */
14996 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14997 }
14998 else
14999 {
15000 /* first time we have propbounds for expr in this propagation rounds:
15001 * intersect with activity (though don't let it become empty if very close intervals)
15002 */
15003 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
15004 }
15005#ifdef DEBUG_PROP
15006 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
15007#endif
15008
15009 /* check if the new bounds lead to an empty interval */
15011 {
15012 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
15013
15014 *cutoff = TRUE;
15015 return SCIP_OKAY;
15016 }
15017
15018 /* if expr is not constant or variable, then store newbounds in expr->propbounds
15019 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
15020 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
15021 */
15022 if( SCIPexprGetNChildren(expr) > 0 )
15023 {
15024 ownerdata->propbounds = newbounds;
15025 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
15026 }
15027
15028 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
15029 * propagation or update of auxvar bounds
15030 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
15031 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
15032 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
15033 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
15034 * one or should we not even update propbounds to newbounds if the update is small?
15035 */
15036 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
15037 {
15038#ifdef DEBUG_PROP
15039 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);
15040#endif
15041 return SCIP_OKAY;
15042 }
15043
15044 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
15045 {
15046 /* add expression to propagation queue if not there yet and not var or constant and
15047 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
15048 */
15049#ifdef DEBUG_PROP
15050 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
15051#endif
15052 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
15053 ownerdata->inpropqueue = TRUE;
15054 }
15055
15056 /* update bounds on variable or auxiliary variable */
15057 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
15058
15059 return SCIP_OKAY;
15060}
15061
15062/** mark constraints that include this expression to be propagated again
15063 *
15064 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
15065 * a change of variable bounds, e.g., because new information on the expression is available
15066 * that could potentially lead to tighter expression activity values.
15067 *
15068 * Note, that this call marks also constraints for propagation which only share some variable
15069 * with this expression.
15070 */
15072 SCIP* scip, /**< SCIP data structure */
15073 SCIP_EXPR* expr /**< expression to propagate again */
15074 )
15075{
15076 SCIP_EXPRITER* it;
15077 SCIP_CONSDATA* consdata;
15078 SCIP_EXPR_OWNERDATA* ownerdata;
15079 int c;
15080
15081 assert(scip != NULL);
15082 assert(expr != NULL);
15083
15084 ownerdata = SCIPexprGetOwnerData(expr);
15085 assert(ownerdata != NULL);
15086
15087 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
15088
15091
15092 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
15093 {
15094 if( !SCIPisExprVar(scip, expr) )
15095 continue;
15096
15097 ownerdata = SCIPexprGetOwnerData(expr);
15098 assert(ownerdata != NULL);
15099
15100 for( c = 0; c < ownerdata->nconss; ++c )
15101 {
15102 consdata = SCIPconsGetData(ownerdata->conss[c]);
15103 assert(consdata != NULL);
15104 consdata->ispropagated = FALSE;
15105 }
15106 }
15107
15108 SCIPfreeExpriter(&it);
15109
15110 return SCIP_OKAY;
15111}
15112
15113/** adds violation-branching score to an expression
15114 *
15115 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
15116 * The expression must either be a variable expression or have an aux-variable.
15117 * In the latter case, branching on auxiliary variables must have been enabled.
15118 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
15119 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
15120 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
15121 *
15122 * @see SCIPaddExprsViolScoreNonlinear()
15123 */
15125 SCIP* scip, /**< SCIP data structure */
15126 SCIP_EXPR* expr, /**< expression where to add branching score */
15127 SCIP_Real violscore /**< violation score to add to expression */
15128 )
15129{
15130 SCIP_EXPR_OWNERDATA* ownerdata;
15131 SCIP_CONSHDLRDATA* conshdlrdata;
15132
15133 assert(scip != NULL);
15134 assert(expr != NULL);
15135 assert(violscore >= 0.0);
15136
15137 ownerdata = SCIPexprGetOwnerData(expr);
15138 assert(ownerdata != NULL);
15139
15140 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15141 assert(conshdlrdata != NULL);
15142
15143 /* if not allowing to branch on auxvars, then expr must be a var-expr */
15144 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
15145 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
15146 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
15147
15148 /* reset branching score if we are in a different enfo round */
15149 if( ownerdata->violscoretag != conshdlrdata->enforound )
15150 {
15151 ownerdata->violscoresum = violscore;
15152 ownerdata->violscoremax = violscore;
15153 ownerdata->nviolscores = 1;
15154 ownerdata->violscoretag = conshdlrdata->enforound;
15155 return;
15156 }
15157
15158 ownerdata->violscoresum += violscore;
15159 if( violscore > ownerdata->violscoremax )
15160 ownerdata->violscoremax = violscore;
15161 ++ownerdata->nviolscores;
15162}
15163
15164/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
15165 *
15166 * Each expression must either be a variable expression or have an aux-variable.
15167 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
15168 * variables present in `exprs`.
15169 */
15171 SCIP* scip, /**< SCIP data structure */
15172 SCIP_EXPR** exprs, /**< expressions where to add branching score */
15173 int nexprs, /**< number of expressions */
15174 SCIP_Real violscore, /**< violation score to add to expression */
15175 SCIP_SOL* sol, /**< current solution */
15176 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
15177 )
15178{
15179 SCIP_EXPRITER* it;
15180 SCIP_EXPR** varexprs;
15181 SCIP_EXPR* e;
15182 int nvars;
15183 int varssize;
15184 int i;
15185
15186 assert(exprs != NULL || nexprs == 0);
15187 assert(success != NULL);
15188
15189 if( nexprs == 0 )
15190 {
15191 *success = FALSE;
15192 return SCIP_OKAY;
15193 }
15194
15195 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
15196 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
15197 {
15198 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
15199 return SCIP_OKAY;
15200 }
15201
15202 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
15203 nvars = 0;
15204 varssize = 5;
15205 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
15206
15209
15210 for( i = 0; i < nexprs; ++i )
15211 {
15212 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
15213 {
15214 assert(e != NULL);
15215
15216 if( SCIPisExprVar(scip, e) )
15217 {
15218 /* add variable expression to vars array */
15219 if( varssize == nvars )
15220 {
15221 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
15222 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
15223 }
15224 assert(varssize > nvars);
15225
15226 varexprs[nvars++] = e;
15227 }
15228 }
15229 }
15230
15231 SCIPfreeExpriter(&it);
15232
15233 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
15234
15235 SCIPfreeBufferArray(scip, &varexprs);
15236
15237 return SCIP_OKAY;
15238}
15239
15240/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
15242 SCIP_EXPR* expr /**< expression */
15243 )
15244{
15245 SCIP_EXPR_OWNERDATA* ownerdata;
15246 SCIP_CONSHDLRDATA* conshdlrdata;
15247
15248 assert(expr != NULL);
15249
15250 ownerdata = SCIPexprGetOwnerData(expr);
15251 assert(ownerdata != NULL);
15252
15253 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15254 assert(conshdlrdata != NULL);
15255
15256 if( conshdlrdata->enforound != ownerdata->violscoretag )
15257 return 0.0;
15258
15259 if( ownerdata->nviolscores == 0 )
15260 return 0.0;
15261
15262 switch( conshdlrdata->branchscoreagg )
15263 {
15264 case 'a' :
15265 /* average */
15266 return ownerdata->violscoresum / ownerdata->nviolscores;
15267
15268 case 'm' :
15269 /* maximum */
15270 return ownerdata->violscoremax;
15271
15272 case 's' :
15273 /* sum */
15274 return ownerdata->violscoresum;
15275
15276 default:
15277 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15278 SCIPABORT();
15279 return SCIP_INVALID;
15280 }
15281}
15282
15283/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15284 *
15285 * @see SCIPexprGetDerivative()
15286 */
15288 SCIP* scip, /**< SCIP data structure */
15289 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15290 SCIP_VAR* var /**< variable (needs to be in the expression) */
15291 )
15292{
15293 SCIP_EXPR_OWNERDATA* ownerdata;
15294 SCIP_CONSHDLRDATA* conshdlrdata;
15295 SCIP_EXPR* varexpr;
15296
15297 assert(scip != NULL);
15298 assert(expr != NULL);
15299 assert(var != NULL);
15300
15301 /* return 0.0 for value expression */
15302 if( SCIPisExprValue(scip, expr) )
15303 {
15304 assert(SCIPexprGetDerivative(expr) == 0.0);
15305 return 0.0;
15306 }
15307
15308 /* check if an error occurred during the last SCIPevalExprGradient() call */
15309 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15310 return SCIP_INVALID;
15311
15312 ownerdata = SCIPexprGetOwnerData(expr);
15313 assert(ownerdata != NULL);
15314
15315 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15316 assert(conshdlrdata != NULL);
15317
15318 /* use variable to expressions mapping which is stored in the constraint handler data */
15319 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15320
15321 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15322 assert(varexpr != NULL);
15323 assert(SCIPisExprVar(scip, varexpr));
15324
15325 /* use difftag to decide whether the variable belongs to the expression */
15326 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15327}
15328
15329/** 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)
15330 *
15331 * @see SCIPexprGetBardot()
15332 */
15334 SCIP* scip, /**< SCIP data structure */
15335 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15336 SCIP_VAR* var /**< variable (needs to be in the expression) */
15337 )
15338{
15339 SCIP_EXPR_OWNERDATA* ownerdata;
15340 SCIP_CONSHDLRDATA* conshdlrdata;
15341 SCIP_EXPR* varexpr;
15342
15343 assert(scip != NULL);
15344 assert(expr != NULL);
15345 assert(var != NULL);
15346
15347 /* return 0.0 for value expression */
15348 if( SCIPisExprValue(scip, expr) )
15349 return 0.0;
15350
15351 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15352 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15353 return SCIP_INVALID;
15354
15355 ownerdata = SCIPexprGetOwnerData(expr);
15356 assert(ownerdata != NULL);
15357
15358 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15359 assert(conshdlrdata != NULL);
15360
15361 /* use variable to expressions mapping which is stored in the constraint handler data;
15362 * if this fails it means that we are asking for the var's component of H*u for a var
15363 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15364 */
15365 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15366
15367 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15368 assert(varexpr != NULL);
15369 assert(SCIPisExprVar(scip, varexpr));
15370
15371 /* use difftag to decide whether the variable belongs to the expression */
15372 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15373}
15374
15375/** evaluates quadratic term in a solution w.r.t. auxiliary variables
15376 *
15377 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15378 */
15380 SCIP* scip, /**< SCIP data structure */
15381 SCIP_EXPR* expr, /**< quadratic expression */
15382 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15383 )
15384{
15385 SCIP_Real auxvalue;
15386 int nlinexprs;
15387 SCIP_Real* lincoefs;
15388 SCIP_EXPR** linexprs;
15389 int nquadexprs;
15390 int nbilinexprs;
15391 int i;
15392
15393 assert(scip != NULL);
15394 assert(expr != NULL);
15395
15396 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15397
15398 /* linear terms */
15399 for( i = 0; i < nlinexprs; ++i )
15400 {
15401 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15402 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15403 }
15404
15405 /* quadratic terms */
15406 for( i = 0; i < nquadexprs; ++i )
15407 {
15408 SCIP_EXPR* quadexprterm;
15409 SCIP_Real lincoef;
15410 SCIP_Real sqrcoef;
15411 SCIP_Real solval;
15412
15413 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15414
15415 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15416
15417 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15418 auxvalue += (lincoef + sqrcoef * solval) * solval;
15419 }
15420
15421 /* bilinear terms */
15422 for( i = 0; i < nbilinexprs; ++i )
15423 {
15424 SCIP_EXPR* expr1;
15425 SCIP_EXPR* expr2;
15426 SCIP_Real coef;
15427
15428 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15429
15430 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
15431 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
15432 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
15433 }
15434
15435 return auxvalue;
15436}
15437
15438/**@addtogroup PublicNlhdlrInterfaceMethods
15439 * @{
15440 */
15441
15442/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15444 SCIP* scip, /**< SCIP data structure */
15445 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15446 const char* name, /**< name of nonlinear handler (must not be NULL) */
15447 const char* desc, /**< description of nonlinear handler (can be NULL) */
15448 int detectpriority, /**< detection priority of nonlinear handler */
15449 int enfopriority, /**< enforcement priority of nonlinear handler */
15450 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15451 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15452 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15453 )
15454{
15455 SCIP_CONSHDLR* conshdlr;
15456 SCIP_CONSHDLRDATA* conshdlrdata;
15457
15458 assert(scip != NULL);
15459 assert(nlhdlr != NULL);
15460 assert(detect != NULL);
15461
15462 /* find myself */
15463 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15464 if( conshdlr == NULL )
15465 {
15466 SCIPerrorMessage("nonlinear constraint handler not found");
15467 return SCIP_PLUGINNOTFOUND;
15468 }
15469
15470 /* create nlhdlr */
15471 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15472
15473 /* include into constraint handler */
15474 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15475 assert(conshdlrdata != NULL);
15476
15477 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15478
15479 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15480 ++conshdlrdata->nnlhdlrs;
15481
15482 /* sort nonlinear handlers by detection priority, in decreasing order
15483 * will happen in INIT, so only do when called late
15484 */
15485 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15486 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15487
15488 return SCIP_OKAY;
15489}
15490
15491/** get number of nonlinear handler */
15493 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15494 )
15495{
15496 SCIP_CONSHDLRDATA* conshdlrdata;
15497
15498 assert(conshdlr != NULL);
15499
15500 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15501 assert(conshdlrdata != NULL);
15502
15503 return conshdlrdata->nnlhdlrs;
15504}
15505
15506/** get nonlinear handlers */
15508 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15509 )
15510{
15511 SCIP_CONSHDLRDATA* conshdlrdata;
15512
15513 assert(conshdlr != NULL);
15514
15515 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15516 assert(conshdlrdata != NULL);
15517
15518 return conshdlrdata->nlhdlrs;
15519}
15520
15521/** returns a nonlinear handler of a given name (or NULL if not found) */
15523 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15524 const char* name /**< name of nonlinear handler */
15525 )
15526{
15527 SCIP_CONSHDLRDATA* conshdlrdata;
15528 int h;
15529
15530 assert(conshdlr != NULL);
15531 assert(name != NULL);
15532
15533 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15534 assert(conshdlrdata != NULL);
15535
15536 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15537 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15538 return conshdlrdata->nlhdlrs[h];
15539
15540 return NULL;
15541}
15542
15543/** gives expression data that a given nonlinear handler stored in an expression
15544 *
15545 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15546 */
15548 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15549 SCIP_EXPR* expr /**< expression */
15550 )
15551{
15552 SCIP_EXPR_OWNERDATA* ownerdata;
15553 int e;
15554
15555 assert(nlhdlr != NULL);
15556 assert(expr != NULL);
15557
15558 ownerdata = SCIPexprGetOwnerData(expr);
15559 assert(ownerdata != NULL);
15560
15561 for( e = 0; e < ownerdata->nenfos; ++e )
15562 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15563 return ownerdata->enfos[e]->nlhdlrexprdata;
15564
15565 return NULL;
15566}
15567
15568/** @} */
SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
static GRAPHNODE ** active
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_VAR * w
Definition: circlepacking.c:67
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** y
Definition: circlepacking.c:64
SCIP_Real * r
Definition: circlepacking.c:59
SCIP_VAR ** x
Definition: circlepacking.c:63
Constraint handler for AND constraints, .
constraint handler for bound disjunction constraints
Constraint handler for linear constraints in their most general form, .
static SCIP_Bool isBinaryProduct(SCIP *scip, SCIP_EXPR *expr)
static SCIP_RETCODE createExprVar(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR **expr, SCIP_VAR *var)
static SCIP_Real computeVertexPolyhedralMaxFacetError(SCIP *scip, SCIP_Bool overestimate, SCIP_Real *funvals, SCIP_Real *box, int nallvars, int nvars, int *nonfixedpos, SCIP_Real *facetcoefs, SCIP_Real facetconstant)
static SCIP_Bool isEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *hasvalue, SCIP_Real *value)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_EXPRITER *it, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result, SCIP_Bool *success)
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
#define ENFOLOG(x)
#define DIALOG_DESC
static SCIP_RETCODE tryAddGadgetEvenOperatorVariable(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_Bool *success)
static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
#define CONSHDLR_NEEDSCONS
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE analyzeViolation(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *maxabsconsviol, SCIP_Real *maxrelconsviol, SCIP_Real *minauxviol, SCIP_Real *maxauxviol, SCIP_Real *maxvarboundviol)
static SCIP_RETCODE presolveRedundantConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss, int *nchgbds)
static SCIP_RETCODE enforceExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result)
static SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
static SCIP_RETCODE reversePropQueue(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool *infeasible, int *ntightenings)
#define BRANCH_RANDNUMINITSEED
static SCIP_RETCODE dropVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_DECL_CONSCHECK(consCheckNonlinear)
static SCIP_RETCODE forbidNonlinearVariablesMultiaggration(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE computeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
static SCIP_RETCODE propagateLocks(SCIP *scip, SCIP_EXPR *expr, int nlockspos, int nlocksneg)
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
#define CONSHDLR_CHECKPRIORITY
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
#define CONSHDLR_DESC
static SCIP_DECL_CONSENABLE(consEnableNonlinear)
static SCIP_RETCODE bilinTermAddAuxExpr(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSNONLINEAR_BILINTERM *term, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Bool *added)
static SCIP_RETCODE freeVarExprs(SCIP *scip, SCIP_CONSDATA *consdata)
#define DIALOG_NAME
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol)
#define consRespropNonlinear
static SCIP_DECL_CONSPARSE(consParseNonlinear)
static SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
static SCIP_RETCODE consSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
#define CONSHDLR_PROP_TIMING
static void addExprsViolScore(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE tightenAuxVarBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL bounds, SCIP_Bool *cutoff, int *ntightenings)
static SCIP_DECL_CONSLOCK(consLockNonlinear)
#define TABLE_DESC_NLHDLR
static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
static SCIP_RETCODE replaceBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_HASHMAP *exprmap, SCIP_EXPRITER *it, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE computeVertexPolyhedralFacetBivariate(SCIP *scip, SCIP_Bool overestimate, SCIP_Real p1[2], SCIP_Real p2[2], SCIP_Real p3[2], SCIP_Real p4[2], SCIP_Real p1val, SCIP_Real p2val, SCIP_Real p3val, SCIP_Real p4val, SCIP_Real xstar[2], SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
static SCIP_RETCODE tryAddGadgetEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
#define consInitpreNonlinear
static SCIP_RETCODE addExprViolScoresAuxVars(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore, SCIP_VAR **auxvars, int nauxvars, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_RETCODE detectNlhdlr(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE computeVertexPolyhedralFacetLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_Real *xstar, SCIP_Real *box, int nallvars, int *nonfixedpos, SCIP_Real *funvals, int nvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
static SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
#define TABLE_EARLIEST_STAGE_NLHDLR
#define VERTEXPOLY_RANDNUMINITSEED
static SCIP_DECL_CONSINIT(consInitNonlinear)
static SCIP_RETCODE getFactorizedBinaryQuadraticExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *sumexpr, int minterms, SCIP_EXPR **newexpr, int *naddconss)
#define consDelvarsNonlinear
static SCIP_RETCODE reformulateFactorizedBinaryQuadratic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_VAR *facvar, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_EXPR **newexpr, int *naddconss)
#define CONSHDLR_SEPAPRIORITY
static SCIP_RETCODE getConsRelViolation(SCIP *scip, SCIP_CONS *cons, SCIP_Real *viol, SCIP_SOL *sol, SCIP_Longint soltag)
#define consGetDiveBdChgsNonlinear
static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
static SCIP_RETCODE getBinaryProductExprDo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, SCIP_Bool empathy4and)
static SCIP_RETCODE registerBranchingCandidatesAllUnfixed(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
static SCIP_Bool isIntervalBetter(SCIP *scip, SCIP_Bool subsetsufficient, SCIP_INTERVAL newinterval, SCIP_INTERVAL oldinterval)
static SCIP_RETCODE detectNlhdlrs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define TABLE_EARLIEST_STAGE_NONLINEAR
static SCIP_RETCODE getBinaryProductExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *exprmap, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_EVENTEXEC(processVarEvent)
#define TABLE_DESC_NONLINEAR
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getViolSplitWeight(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var, SCIP_SOL *sol)
static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
static SCIP_RETCODE freeEnfoData(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool freeauxvar)
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE getBilinearBinaryTerms(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_VAR **xs, SCIP_VAR **ys, int *childidxs, int *nterms)
static SCIP_RETCODE storeVarExprs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata)
static SCIP_RETCODE buildVertexPolyhedralSeparationLP(SCIP *scip, int nvars, SCIP_LPI **lp)
static SCIP_RETCODE tryAddGadgetSquaredDifference(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_CONS *cons, SYM_GRAPH *graph, int sumnodeidx, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs)
static SCIP_RETCODE tryAddGadgetBilinearProductSignedPerm(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE propConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool force, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
static SCIP_RETCODE forwardPropExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *rootexpr, SCIP_Bool tightenauxvars, SCIP_Bool *infeasible, int *ntightenings)
static SCIP_RETCODE consEnfo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_Bool isSingleLockedCand(SCIP *scip, SCIP_EXPR *expr)
static SCIP_DECL_CONSCOPY(consCopyNonlinear)
static SCIP_Bool branchAuxNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE presolveImplint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nchgvartypes, SCIP_Bool *infeasible)
#define TABLE_NAME_NONLINEAR
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
#define TABLE_NAME_NLHDLR
static SCIP_RETCODE tryAddGadgetEvenOperatorSum(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
static SCIP_RETCODE deinitSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE ensureLocVarsArraySize(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **vals, int nelems, int *maxnelems)
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
static SCIP_RETCODE enforceExprNlhdlr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_Real auxvalue, SCIP_Bool overestimate, SCIP_Bool separated, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result)
static SCIP_RETCODE selectBranchingCandidate(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol, BRANCHCAND **selected)
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
static SCIP_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
static SCIP_DECL_CONSTRANS(consTransNonlinear)
static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
#define VERTEXPOLY_MAXPERTURBATION
static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
static SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
static SCIP_RETCODE catchVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define DIALOG_ISSUBMENU
static SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
static SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
static SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
#define VERTEXPOLY_USEDUALSIMPLEX
#define CONSHDLR_PROPFREQ
static SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
static SCIP_Bool varIsCenteredAt0(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE initSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *infeasible)
static SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(SCIP *scip, SCIP_Real left, SCIP_Real right, SCIP_Real funleft, SCIP_Real funright, SCIP_Bool *success, SCIP_Real *facetcoef, SCIP_Real *facetconstant)
#define POWEROFTWO(x)
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
static SCIP_RETCODE collectBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, BRANCHCAND *cands, int *ncands)
static SCIP_RETCODE branching(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_RESULT *result)
static SCIP_RETCODE bilinearTermsInsertAll(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define VERTEXPOLY_ADJUSTFACETFACTOR
#define TABLE_POSITION_NONLINEAR
static SCIP_RETCODE initSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
static SCIP_RETCODE removeSingleLockedVars(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRITER *it, SCIP_HASHMAP *exprcands)
#define CONSHDLR_EAGERFREQ
static SCIP_RETCODE branchingIntegralOrNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Longint soltag, SCIP_Real maxrelconsviol, SCIP_Bool *branchintegral, SCIP_Bool *cutoff)
static SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
static SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
static void findUnlockedLinearVar(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
static SCIP_RETCODE propExprDomains(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE freeAuxVar(SCIP *scip, SCIP_EXPR *expr)
static SCIP_Real getConsAbsViolation(SCIP_CONS *cons)
static SCIP_RETCODE bilinearTermsFree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
static SCIP_DECL_SORTINDCOMP(branchcandCompare)
static SCIP_Bool branchingIntegralFirst(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol)
static SCIP_RETCODE createCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool copyexpr, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE bilinearTermsInsertEntry(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, int nlockspos, int nlocksneg, int *idx, SCIP_Bool existing)
static SCIP_RETCODE notifyNlhdlrNewsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solisbest)
static SCIP_Real getExprAbsOrigViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
#define CONSHDLR_NAME
static SCIP_RETCODE presolveMergeConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
static SCIP_Real getDomainCenter(SCIP *scip, SCIP_VAR *var)
#define TABLE_POSITION_NLHDLR
static SCIP_RETCODE ensureOpenArraySizeSymdetect(SCIP *scip, int **openidx, int nelems, int *maxnelems)
static SCIP_RETCODE canonicalizeConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_PRESOLTIMING presoltiming, SCIP_Bool *infeasible, int *ndelconss, int *naddconss, int *nchgcoefs)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSFREE(consFreeNonlinear)
static SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
static SCIP_DECL_CONSEXIT(consExitNonlinear)
#define CONSHDLR_DELAYPROP
static SCIP_DECL_CONSPROP(consPropNonlinear)
static SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
#define BILIN_MAXNAUXEXPRS
constraint handler for nonlinear constraints specified by algebraic expressions
Constraint handler for variable bound constraints .
methods for debugging
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:312
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:311
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define EPSROUND(x, eps)
Definition: def.h:193
#define EPSISINT(x, eps)
Definition: def.h:195
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_INTERVAL_INFINITY
Definition: def.h:180
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define MAX3(x, y, z)
Definition: def.h:228
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define EPSFRAC(x, eps)
Definition: def.h:194
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL_ABORT(x)
Definition: def.h:334
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
default user interface dialog
absolute expression handler
power and signed power expression handlers
sum expression handler
handler for sin expressions
constant value expression handler
variable expression handler
handler for variable index expressions
SCIP_Real SCIPevalBilinAuxExprNonlinear(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_SOL *sol)
SCIP_RETCODE SCIPcheckQuadraticNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *isquadratic)
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
#define SCIP_DECL_NONLINCONSUPGD(x)
SCIP_RETCODE SCIPmarkExprPropagateNonlinear(SCIP *scip, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *z, SCIP_Real exponent, SCIP_Real xoffset, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPgetExprViolScoreNonlinear(SCIP_EXPR *expr)
unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
void SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
void SCIPgetExprEnfoDataNonlinear(SCIP_EXPR *expr, int idx, SCIP_NLHDLR **nlhdlr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_NLHDLR_METHOD *nlhdlrparticipation, SCIP_Bool *sepabelowusesactivity, SCIP_Bool *sepaaboveusesactivity, SCIP_Real *auxvalue)
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *coefs, SCIP_Real *offsets, SCIP_Real constant, SCIP_VAR *rhsvar, SCIP_Real rhscoeff, SCIP_Real rhsoffset)
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsBasicVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, SCIP_Real coefx, SCIP_Real coefy, SCIP_Real coefaux, SCIP_Real cst, SCIP_Bool overestimate)
void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_RETCODE SCIPgetAbsViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPassumeConvexNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
int SCIPgetBilinTermIdxNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
void SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, int nlockspos, int nlocksneg)
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
SCIP_RETCODE SCIPprocessRowprepNonlinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_VAR *auxvar, SCIP_Real auxvalue, SCIP_Bool allowweakcuts, SCIP_Bool branchscoresuccess, SCIP_Bool inenforcement, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
SCIP_RETCODE SCIPgetExprActivityNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Real SCIPgetExprPartialDiffNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPcollectBilinTermsNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_DECL_VERTEXPOLYFUN((*function)), void *fundata, SCIP_Real *xstar, SCIP_Real *box, int nallvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
#define SCIP_DECL_VERTEXPOLYFUN(f)
SCIP_RETCODE SCIPgetRelViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition: cons_and.c:5180
unsigned int SCIPgetExprNPropUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPchgExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr)
SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
void SCIPaddExprViolScoreNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore)
void SCIPincrementCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_Bool boundrelax)
SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_Real SCIPevalExprQuadraticAuxNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol)
#define SCIP_MAXVERTEXPOLYDIM
SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:398
SCIP_Bool SCIPisExprVaridx(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_varidx.c:252
SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_abs.c:546
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition: expr_sum.c:1154
SCIP_RETCODE SCIPcreateExprSignpower(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3209
SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_pow.c:3234
SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
Definition: expr_trig.c:1480
SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_sum.c:1117
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_value.c:274
SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3185
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:668
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
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,...)
Definition: scip_message.c:208
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:191
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:255
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:1937
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)
Definition: scip_branch.c:673
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
Definition: scip_branch.c:905
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1134
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:402
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:857
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17545
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17534
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition: lp.c:17509
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5112
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4778
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPincludeConshdlr(SCIP *scip, const char *name, const char *desc, int sepapriority, int enfopriority, int chckpriority, int sepafreq, int propfreq, int eagerfreq, int maxprerounds, SCIP_Bool delaysepa, SCIP_Bool delayprop, SCIP_Bool needscons, SCIP_PROPTIMING proptiming, SCIP_PRESOLTIMING presoltiming, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSFREE((*consfree)), SCIP_DECL_CONSINIT((*consinit)), SCIP_DECL_CONSEXIT((*consexit)), SCIP_DECL_CONSINITPRE((*consinitpre)), SCIP_DECL_CONSEXITPRE((*consexitpre)), SCIP_DECL_CONSINITSOL((*consinitsol)), SCIP_DECL_CONSEXITSOL((*consexitsol)), SCIP_DECL_CONSDELETE((*consdelete)), SCIP_DECL_CONSTRANS((*constrans)), SCIP_DECL_CONSINITLP((*consinitlp)), SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFORELAX((*consenforelax)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSPROP((*consprop)), SCIP_DECL_CONSPRESOL((*conspresol)), SCIP_DECL_CONSRESPROP((*consresprop)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_DECL_CONSACTIVE((*consactive)), SCIP_DECL_CONSDEACTIVE((*consdeactive)), SCIP_DECL_CONSENABLE((*consenable)), SCIP_DECL_CONSDISABLE((*consdisable)), SCIP_DECL_CONSDELVARS((*consdelvars)), SCIP_DECL_CONSPRINT((*consprint)), SCIP_DECL_CONSCOPY((*conscopy)), SCIP_DECL_CONSPARSE((*consparse)), SCIP_DECL_CONSGETVARS((*consgetvars)), SCIP_DECL_CONSGETNVARS((*consgetnvars)), SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)), SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)), SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:83
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4735
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition: cons.c:8507
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8688
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8486
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition: cons.c:8496
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:94
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:207
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
SCIP_RETCODE SCIPinsertDatatreeLong(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Longint value)
SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
Definition: scip_dialog.c:124
SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
Definition: dialog.c:436
SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
Definition: dialog.c: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)
Definition: scip_dialog.c:171
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
Definition: scip_dialog.c:157
int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
Definition: dialog.c:1046
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:111
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:241
SCIP_IMPLINTTYPE SCIPeventGetNewImpltype(SCIP_EVENT *event)
Definition: event.c:1513
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1194
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1567
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1217
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:293
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:333
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:545
SCIP_Bool SCIPexprhdlrHasGetSymData(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:685
SCIP_Bool SCIPexprhdlrHasMonotonicity(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:665
SCIP_Bool SCIPexprhdlrHasReverseProp(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:675
void SCIPexprSetActivity(SCIP_EXPR *expr, SCIP_INTERVAL activity, SCIP_Longint activitytag)
Definition: expr.c:4054
SCIP_RETCODE SCIPcreateExprQuadratic(SCIP *scip, SCIP_EXPR **expr, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1059
SCIP_IMPLINTTYPE SCIPexprGetIntegrality(SCIP_EXPR *expr)
Definition: expr.c:4091
SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
Definition: scip_expr.c:1817
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1661
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3872
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4226
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2040
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition: expr_pow.c:3448
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1490
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1692
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:969
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition: scip_expr.c:1677
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:930
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition: expr.c:3933
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3972
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1479
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition: scip_expr.c:2083
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition: expr.c:3959
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition: expr.c:4101
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4262
void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
Definition: expr.c:4141
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition: scip_expr.c:1274
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1554
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition: expriter.c:756
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1468
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2420
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1443
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition: expriter.c:683
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition: expriter.c:664
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1457
SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1406
SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition: expriter.c:630
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2362
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1512
SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:740
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition: expr_value.c:298
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:806
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1501
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3946
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:4044
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition: scip_expr.c:1845
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:858
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2402
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition: expr.c:4000
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3882
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1569
SCIP_RETCODE SCIPcopyExpr(SCIP *sourcescip, SCIP *targetscip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *valid)
Definition: scip_expr.c:1344
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:424
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:838
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:4028
void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
Definition: expr.c:4186
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:707
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2376
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:696
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_IMPLINTTYPE integrality)
Definition: expr.c:4111
SCIP_RETCODE SCIPduplicateExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_MAPEXPR((*mapexpr)), void *mapexprdata, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1307
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition: scip_expr.c:1435
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition: expriter.c:501
int SCIPexprGetNUses(SCIP_EXPR *expr)
Definition: expr.c:3862
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition: scip_expr.c:2121
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition: expr.c:4015
SCIP_RETCODE SCIPsimplifyExpr(SCIP *scip, SCIP_EXPR *rootexpr, SCIP_EXPR **simplified, SCIP_Bool *changed, SCIP_Bool *infeasible, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1798
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1742
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3895
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:721
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:263
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1467
void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
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:8483
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
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:4130
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:884
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:4259
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:608
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1506
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1719
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:2005
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_Real SCIPgetAvgPseudocostCount(SCIP *scip, SCIP_BRANCHDIR dir)
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:101
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:62
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:76
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:144
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:178
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:127
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:319
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:161
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Real SCIPgetHugeValue(SCIP *scip)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip_var.c:5176
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:11350
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
Definition: var.c:23506
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:23618
SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
Definition: scip_var.c:10218
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:225
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:5634
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:11188
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:5570
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:10113
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24642
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24653
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:11057
SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
Definition: var.c:23463
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:17274
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition: misc.c:1019
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition: misc.c:995
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition: misc.c:1081
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition: misc.c:1236
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition: misc.c:1132
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10245
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10223
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:639
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:699
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
Definition: misc_rowprep.c:972
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:649
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:709
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:689
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:669
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:913
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:629
void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:791
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
Definition: misc_rowprep.c:583
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
Definition: misc_rowprep.c:801
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c: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)
NLP local search primal heuristic using sub-SCIPs.
primal heuristic that tries a given solution
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1141
static volatile int nterms
Definition: interrupt.c:47
SCIP_Bool SCIPlapackIsAvailable(void)
Definition: lapack_calls.c:121
SCIP_RETCODE SCIPlapackSolveLinearEquations(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
Definition: lapack_calls.c:386
interface methods for lapack functions
static const char * paramname[]
Definition: lpi_msk.c:5172
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition: nlhdlr.c:402
SCIP_RETCODE SCIPnlhdlrCreate(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
Definition: nlhdlr.c:354
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition: nlhdlr.c:753
SCIP_RETCODE SCIPnlhdlrCollectStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, SCIP_DATATREE *datatree)
Definition: nlhdlr.c:797
private functions of nonlinear handlers of nonlinear constraints
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition: nlhdlr.h:140
#define SCIPnlhdlrResetNDetectionslast(nlhdlr)
Definition: nlhdlr.h:138
#define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
Definition: nlhdlr.h:139
nonlinear handlers for convex and concave expressions, respectively
SCIP_RETCODE SCIPgetSymOpNodeType(SCIP *scip, const char *opnodename, int *nodetype)
propagator for symmetry handling
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
#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.
Definition: sepa_flower.c:1221
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::@6 aux
int nlockspos[NLOCKTYPES]
Definition: struct_cons.h:64
SCIP_Real sup
Definition: intervalarith.h:57
SCIP_Real inf
Definition: intervalarith.h:56
structs for symmetry computations
methods for dealing with symmetry detection graphs
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:156
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition: type_cons.h:919
#define SCIP_DECL_CONSRESPROP(x)
Definition: type_cons.h:611
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h: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_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
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
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition: type_expr.h:80
SCIP_MONOTONE
Definition: type_expr.h:70
@ SCIP_MONOTONE_CONST
Definition: type_expr.h:74
@ SCIP_MONOTONE_UNKNOWN
Definition: type_expr.h:71
@ SCIP_MONOTONE_INC
Definition: type_expr.h:72
@ SCIP_MONOTONE_DEC
Definition: type_expr.h:73
@ SCIP_EXPRITER_BFS
Definition: type_expr.h:717
@ SCIP_EXPRITER_DFS
Definition: type_expr.h:718
@ SCIP_EXPRITER_RTOPOLOGIC
Definition: type_expr.h:716
#define SCIP_EXPRITER_LEAVEEXPR
Definition: type_expr.h:697
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:694
@ SCIP_BRANCHDIR_DOWNWARDS
Definition: type_history.h:43
@ SCIP_BRANCHDIR_UPWARDS
Definition: type_history.h:44
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:57
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
@ SCIP_LPPAR_LPINFO
Definition: type_lpi.h:55
@ SCIP_LPPAR_DUALFEASTOL
Definition: type_lpi.h:57
@ SCIP_LPPAR_FEASTOL
Definition: type_lpi.h:56
@ SCIP_LPPAR_LPITLIM
Definition: type_lpi.h:60
@ SCIP_LPPAR_OBJLIM
Definition: type_lpi.h:59
@ SCIP_OBJSEN_MAXIMIZE
Definition: type_lpi.h:42
@ SCIP_OBJSEN_MINIMIZE
Definition: type_lpi.h:43
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:52
#define SCIP_DECL_NLHDLREVALAUX(x)
Definition: type_nlhdlr.h:202
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:452
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:53
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition: type_nlhdlr.h:54
unsigned int SCIP_NLHDLR_METHOD
Definition: type_nlhdlr.h:57
#define SCIP_DECL_NLHDLRDETECT(x)
Definition: type_nlhdlr.h:177
#define SCIP_NLHDLR_METHOD_NONE
Definition: type_nlhdlr.h:50
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:453
#define SCIP_NLHDLR_METHOD_ALL
Definition: type_nlhdlr.h:55
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:51
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_BRANCHED
Definition: type_result.h:54
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SOLVELP
Definition: type_result.h:55
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_LPERROR
Definition: type_retcode.h:49
@ SCIP_READERROR
Definition: type_retcode.h:45
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PROBLEM
Definition: type_set.h:45
@ SCIP_STAGE_INITPRESOLVE
Definition: type_set.h:48
@ SCIP_STAGE_SOLVED
Definition: type_set.h:54
@ SCIP_STAGE_PRESOLVING
Definition: type_set.h:49
@ SCIP_STAGE_TRANSFORMED
Definition: type_set.h:47
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52
@ SCIP_STAGE_EXITPRESOLVE
Definition: type_set.h:50
@ SCIP_STAGE_EXITSOLVE
Definition: type_set.h:55
@ SCIP_STAGE_INIT
Definition: type_set.h:44
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53
@ SCIP_SOLORIGIN_LPSOL
Definition: type_sol.h:44
@ SCIP_STATUS_OPTIMAL
Definition: type_stat.h: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
Definition: type_symmetry.h:64
@ SYM_CONSOPTYPE_SUM
Definition: type_symmetry.h:83
@ SYM_CONSOPTYPE_COEF
Definition: type_symmetry.h:85
@ SYM_CONSOPTYPE_SQDIFF
Definition: type_symmetry.h:86
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:58
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
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