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 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,
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 }
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 */
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 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) */
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 */
336 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
346 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
350 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
358 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
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) */
402 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
405 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
425 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
522 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
566 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
575 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
639 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
672 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
759 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
772 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
778 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
786 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
792 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
883 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
906 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
921 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
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
932 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
938 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
946 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
988 assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED));
994 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
1008 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
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
1017 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1019 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
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
1023 if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1024 (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1027 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1043 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1044 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1077 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1079 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1123 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1131 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1140 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1142 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1176#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1191 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1192 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1197 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1201 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1213 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1248 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1250 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1272 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1274 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1321 * @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
1332 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1382 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1383 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1396 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1407 * If there are negative locks, then return the violation of z ≤ f(x) and sets `violover` to TRUE.
1408 * If there are positive locks, then return the violation of z ≥ f(x) and sets `violunder` to TRUE.
1410 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1412 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1470 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1473 * If there are negative locks, then return the violation of z ≤ f(w) and sets `violover` to TRUE.
1474 * If there are positive locks, then return the violation of z ≥ f(w) and sets `violunder` to TRUE.
1476 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1478 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1566 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1567 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1574 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1593 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1693 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1704/** checks for a linear variable that can be increased or decreased without harming feasibility */
1753 SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1758 * if we have already one candidate, then take the one where the loss in the objective function is less
1771 * if we have already one candidate, then take the one where the loss in the objective function is less
1788 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1792 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1796/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1797 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1799 * The method assumes that this is always possible and that not all constraints are feasible already.
1808 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1838 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1839 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1859 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1881 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1892 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1914 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1923 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1927 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1930 if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1932 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1947 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1949 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1950 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1955 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1956 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1978 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1992 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2017 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2024 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2074 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2075 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2081 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2083 SCIP_CALL( notifyNlhdlrNewsol(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol, (SCIPeventGetType(event) & SCIP_EVENTTYPE_BESTSOLFOUND) != 0) );
2088/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2090 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2115 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2125 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2133 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2137 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2147 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2151 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2155 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2163/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2172 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2173 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2193 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2195 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2209 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2211 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2219 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2220 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2224 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2249 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2269 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2275 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2280 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2285 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2321 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2322 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2325 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2333 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2344 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2353 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2362 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2374 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2376 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2378 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2389 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2390 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2391 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2392 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2395 if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2406 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2411 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2427 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2455/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2457 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2467 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2489 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2492 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2496 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2503/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2507 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2516 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2533 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2550 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2551 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2558 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2591 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2595 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2602 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2609 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2612 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2627 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2634 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2654 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2658 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2659 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2660 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2666 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2667 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2670 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2711#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2747 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2750 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2757 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2762 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2766 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2773 /* 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 */
2777 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2783 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2784 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2791 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2803 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2821 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2833 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2870/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2872 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2875 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2904#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2918 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2924 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2942 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2945 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2951 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3010 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3042 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3050 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3065 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3068 /* keep this assert for checking whether someone changed an expression without updating locks properly */
3082 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3085 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3129 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3131 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3132 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3133 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3134 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3135 * which implies that updating the monotonicity information during the next locking of this expression does not
3138 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3139 * locks from an expression and repropagating them after the structural changes have been applied.
3140 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3175 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3190/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3226 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3228 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3229 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3237 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3263 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3322 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3324 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3325 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3341 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3344 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3373 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3374 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3376 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3381 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3384 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3402 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3410 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3412 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3413 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3414 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3417 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3423 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3424 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3434 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3449 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3472 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 */
3482 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3483 * for example, this happens if globally valid nonlinear constraints are added during the tree search
3500 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3502 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3507 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3509 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3518 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3519 * this way we can treat the root expression like any other expression when enforcing via separation
3525 SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3534 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3544 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3547 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3550 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3559 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3560 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3561 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3567 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3583 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3594 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3602 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3617 /* check for a linear variable that can be increase or decreased without harming feasibility */
3638 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3653 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3658 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3661 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3726 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3728 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3730 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3732 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3741 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3742 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3762 /* forget about linear variables that can be increased or decreased without harming feasibility */
3775/** helper method to decide whether a given expression is product of at least two binary variables */
3828 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3899 /* 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 */
3909 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3910 SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3940 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3941 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3951 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3952 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3960 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3961 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3973 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3974 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3994/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4002 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4104 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4142 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4145 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4167 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4169 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4192/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4199 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4260 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4271 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4272 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4277 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4278 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4285 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4286 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4321/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4326 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4329 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4330 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4361 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4437 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4454 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4460 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4476 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4478 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4479 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4500 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4511 /* try to factorize variables in a sum expression that contains several products of binary variables */
4514 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4520 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4530 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4544 * 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}:
4549 * 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$.
4557 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4559 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4560 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4561 * contains large (≥ `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4571 * 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
4572 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4582 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4623 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4637 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4649 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4681 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4717 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4764 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4779 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4788 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4810 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4840 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4843 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4898 /* call this function before simplification because expressions might not be simplified after reformulating
4899 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4901 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4926 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4932 /* 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").
4933 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4962 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4966 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4969 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5008 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5009 * been changed after simplification; now we completely recollect all variable expression and variable events
5012 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5013 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.