cons_nonlinear.c
Go to the documentation of this file.
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
85 #define CONSHDLR_ENFOPRIORITY -60 /**< 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,
89 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
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? */
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*/
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) */
107 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
113 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
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 */
124 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
138 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
150 {
160 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
168 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
173 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
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 */
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 */
189 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
216 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
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 */
236 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
241 {
242 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
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() */
259 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
272 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
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 */
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 */
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 */
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 */
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" */
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) */
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 branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
313 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
314 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
315 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
316 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
317 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
318 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
319 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) */
324 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
325 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 */
326 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
327 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
328 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
334 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
344 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
348 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
355 {
376 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
377 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
398 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
401 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
421 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
482 {
518 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
562 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
571 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
575 {
599 {
635 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
668 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
755 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
768 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
774 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
782 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
788 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
836 {
878 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
901 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
916 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
920 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
921 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
927 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
933 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
941 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
963 {
983 assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED));
989 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
1003 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1005 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1006 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1012 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1014 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1016 * 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
1018 if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1019 (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1022 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1038 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1039 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1072 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1074 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1118 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1126 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1135 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1137 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1171 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1186 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1187 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1192 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1196 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1208 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1243 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1245 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1267 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1269 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1316 * @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
1327 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1377 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1378 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1391 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1402 * If there are negative locks, then return the violation of z ≤ f(x) and sets `violover` to TRUE.
1403 * If there are positive locks, then return the violation of z ≥ f(x) and sets `violunder` to TRUE.
1405 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1407 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1465 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1468 * If there are negative locks, then return the violation of z ≤ f(w) and sets `violover` to TRUE.
1469 * If there are positive locks, then return the violation of z ≥ f(w) and sets `violunder` to TRUE.
1471 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1473 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1561 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1562 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1569 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1588 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1688 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1699 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1748 SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1753 * if we have already one candidate, then take the one where the loss in the objective function is less
1766 * if we have already one candidate, then take the one where the loss in the objective function is less
1783 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1787 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1791 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1792 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1794 * The method assumes that this is always possible and that not all constraints are feasible already.
1803 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1833 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1834 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1854 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1876 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1887 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1909 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1918 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1922 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1925 if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1927 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1942 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1944 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1945 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1950 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1951 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1973 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1987 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2012 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2019 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2047 {
2069 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2070 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2076 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2078 SCIP_CALL( notifyNlhdlrNewsol(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol, (SCIPeventGetType(event) & SCIP_EVENTTYPE_BESTSOLFOUND) != 0) );
2083 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2085 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2110 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2120 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2128 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2132 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2142 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2146 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2150 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2158 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2167 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2168 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2188 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2190 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2204 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2206 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2214 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2215 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2219 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2244 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2264 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2270 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2275 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2280 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2316 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2317 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2320 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2328 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2339 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2348 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2357 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2369 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2371 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2373 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2384 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2385 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2386 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2387 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2390 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2401 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2406 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2422 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2450 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2452 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2462 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2484 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2487 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2491 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2498 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2502 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2511 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2528 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2545 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2546 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2553 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2586 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2590 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2597 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2604 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2607 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2622 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2629 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2649 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2653 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2654 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2655 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2661 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2662 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2665 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2706 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2742 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2745 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2752 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2757 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2761 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2768 /* 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 */
2772 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2778 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2779 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2786 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2798 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2816 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2828 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2865 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2867 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2870 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2899 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2913 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2919 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2937 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2940 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2946 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3005 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3037 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3045 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3060 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3063 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3077 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3080 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3124 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3126 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3127 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3128 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3129 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3130 * which implies that updating the monotonicity information during the next locking of this expression does not
3133 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3134 * locks from an expression and repropagating them after the structural changes have been applied.
3135 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3170 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3185 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3221 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3223 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3224 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3232 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3258 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3262 {
3317 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3319 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3320 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3336 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3339 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3368 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3369 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3371 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3376 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3379 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3397 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3405 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3407 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3408 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3409 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3412 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3418 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3419 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3429 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3444 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3467 assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3477 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3478 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3495 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3497 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3502 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3504 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3513 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3514 * this way we can treat the root expression like any other expression when enforcing via separation
3520 SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3529 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3539 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3542 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3545 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3554 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3555 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3556 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3562 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3578 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3589 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3597 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3612 /* check for a linear variable that can be increase or decreased without harming feasibility */
3633 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3648 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3653 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3656 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3721 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3723 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3725 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3727 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3736 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3737 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3757 /* forget about linear variables that can be increased or decreased without harming feasibility */
3770 /** helper method to decide whether a given expression is product of at least two binary variables */
3823 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3894 /* 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 */
3904 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3905 SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3911 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3912 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3922 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3923 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3931 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3932 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3944 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3945 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3965 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3973 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4075 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4113 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4116 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4138 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4140 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4163 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4170 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4212 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4223 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4224 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4229 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4230 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4237 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4238 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4273 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4278 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4281 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4282 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4313 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4389 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4406 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4412 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4428 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4430 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4431 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4452 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4463 /* try to factorize variables in a sum expression that contains several products of binary variables */
4466 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4472 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4482 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4496 * 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}:
4501 * 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$.
4509 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4511 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4512 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4513 * contains large (≥ `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4523 * 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
4524 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4534 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4575 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4589 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4601 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4633 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4669 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4716 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4731 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4740 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4762 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4792 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4795 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4850 /* call this function before simplification because expressions might not be simplified after reformulating
4851 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4853 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4878 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4884 /* 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").
4885 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4914 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4918 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4921 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4960 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
4961 * been changed after simplification; now we completely recollect all variable expression and variable events
4964 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
4965 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
4991 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5084 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5087 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5158 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5181 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5182 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5184 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5188 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5190 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5191 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5227 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5248 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5256 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5262 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5270 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5279 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);
5312 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5314 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5320 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5333 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5336 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5337 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5341 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5349 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5353 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5362 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5370 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5403 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5417 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5426 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5448 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5466 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5467 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5490 && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5495 /** removes all variable expressions that are contained in a given expression from a hash map */
5506 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5517 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5523 * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) ≤ rhs
5524 * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5525 * g(x) to \f$\sum_i [a_i,b_i] x^{p_i}\f$ for a single variable \f$x\f$ and try to conclude montonicity or convexity/concavity
5526 * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5590 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5619 /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5637 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5649 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )