1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   cons_abspower.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief  Constraint handler for absolute power constraints \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
19  * @author Stefan Vigerske
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #define SCIP_PRIVATE_ROWPREP
25 
26 #include <ctype.h>
27 #include "nlpi/pub_expr.h"
28 #include "nlpi/type_expr.h"
29 #include "nlpi/type_nlpi.h"
30 #include "scip/cons_abspower.h"
31 #include "scip/cons_indicator.h"
32 #include "scip/cons_linear.h"
33 #include "scip/cons_nonlinear.h"
34 #include "scip/cons_quadratic.h"
35 #include "scip/cons_varbound.h"
36 #include "scip/debug.h"
37 #include "scip/heur_subnlp.h"
38 #include "scip/heur_trysol.h"
39 #include "scip/intervalarith.h"
40 #include "scip/pub_cons.h"
41 #include "scip/pub_event.h"
42 #include "scip/pub_heur.h"
43 #include "scip/pub_lp.h"
44 #include "scip/pub_message.h"
45 #include "scip/pub_misc.h"
46 #include "scip/pub_nlp.h"
47 #include "scip/pub_sol.h"
48 #include "scip/pub_tree.h"
49 #include "scip/pub_var.h"
50 #include "scip/scip_branch.h"
51 #include "scip/scip_conflict.h"
52 #include "scip/scip_cons.h"
53 #include "scip/scip_copy.h"
54 #include "scip/scip_cut.h"
55 #include "scip/scip_event.h"
56 #include "scip/scip_general.h"
57 #include "scip/scip_heur.h"
58 #include "scip/scip_lp.h"
59 #include "scip/scip_mem.h"
60 #include "scip/scip_message.h"
61 #include "scip/scip_nlp.h"
62 #include "scip/scip_numerics.h"
63 #include "scip/scip_param.h"
64 #include "scip/scip_prob.h"
65 #include "scip/scip_probing.h"
66 #include "scip/scip_sepa.h"
67 #include "scip/scip_sol.h"
68 #include "scip/scip_tree.h"
69 #include "scip/scip_var.h"
70 #include <string.h>
71 
72 /* constraint handler properties */
73 #define CONSHDLR_NAME          "abspower"
74 #define CONSHDLR_DESC          "constraint handler for absolute power constraints lhs <= sign(x+offset)abs(x+offset)^n + c*z <= rhs"
75 #define CONSHDLR_SEPAPRIORITY         0 /**< priority of the constraint handler for separation */
76 #define CONSHDLR_ENFOPRIORITY       -30 /**< priority of the constraint handler for constraint enforcing */
77 #define CONSHDLR_CHECKPRIORITY -3500000 /**< priority of the constraint handler for checking feasibility */
78 #define CONSHDLR_SEPAFREQ             1 /**< frequency for separating cuts; zero means to separate only in the root node */
79 #define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
80 #define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
81                                          *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
82 #define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
83 #define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
84 #define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
85 #define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
86 
87 #define CONSHDLR_PRESOLTIMING  SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM
88 #define CONSHDLR_PROP_TIMING   SCIP_PROPTIMING_ALWAYS /**< when should the constraint handlers propagation routines be called? */
89 
90 #define QUADCONSUPGD_PRIORITY     50000 /**< priority of the constraint handler for upgrading of quadratic constraints */
91 #define NONLINCONSUPGD_PRIORITY   50000 /**< priority of the constraint handler for upgrading of nonlinear constraints and reformulating expression graph nodes */
92 
93 /*
94  * Local defines
95  */
96 
97 #define PROPVARTOL    SCIPepsilon(scip) /**< tolerance to add to variable bounds in domain propagation */
98 #define PROPSIDETOL   SCIPepsilon(scip) /**< tolerance to add to constraint sides in domain propagation */
99 #define INITLPMAXVARVAL          1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
100 
101 /** power function type to be used by a constraint instead of the general pow */
102 #define DECL_MYPOW(x) SCIP_Real x (SCIP_Real base, SCIP_Real exponent)
103 
104 /** sign of a value (-1 or +1)
105  *
106  * 0.0 has sign +1
107  */
108 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
109 
110 
111 /*
112  * Data structures
113  */
114 
115 #define ROOTS_KNOWN 10                  /**< up to which (integer) exponents precomputed roots have been stored */
116 
117 /** The positive root of the polynomial (n-1) y^n + n y^(n-1) - 1 is needed in separation.
118  *  Here we store these roots for small integer values of n.
119  */
120 static
121 SCIP_Real roots[ROOTS_KNOWN+1] = {
122    -1.0,                     /* no root for n=0 */
123    -1.0,                     /* no root for n=1 */
124    0.41421356237309504880,   /* root for n=2 (-1+sqrt(2)) */
125    0.5,                      /* root for n=3 */
126    0.56042566045031785945,   /* root for n=4 */
127    0.60582958618826802099,   /* root for n=5 */
128    0.64146546982884663257,   /* root for n=6 */
129    0.67033204760309682774,   /* root for n=7 */
130    0.69428385661425826738,   /* root for n=8 */
131    0.71453772716733489700,   /* root for n=9 */
132    0.73192937842370733350    /* root for n=10 */
133 };
134 
135 /** constraint data for absolute power constraints */
136 struct SCIP_ConsData
137 {
138    SCIP_VAR*             x;                  /**< variable x in sign(x+offset)|x+offset|^n term */
139    SCIP_VAR*             z;                  /**< linear variable in constraint */
140    SCIP_Real             exponent;           /**< exponent n of |x+offset| */
141    SCIP_Real             xoffset;            /**< offset in x+offset */
142    SCIP_Real             zcoef;              /**< coefficient of linear variable z */
143    SCIP_Real             lhs;                /**< left  hand side of constraint */
144    SCIP_Real             rhs;                /**< right hand side of constraint */
145 
146    SCIP_Real             root;               /**< root of polynomial */
147    DECL_MYPOW            ((*power));         /**< function for computing power*/
148 
149    SCIP_Real             lhsviol;            /**< current violation of left  hand side */
150    SCIP_Real             rhsviol;            /**< current violation of right hand side */
151 
152    int                   xeventfilterpos;    /**< position of x var event in SCIP event filter */
153    int                   zeventfilterpos;    /**< position of z var event in SCIP event filter */
154    unsigned int          propvarbounds:1;    /**< have variable bounds been propagated? */
155 
156    SCIP_NLROW*           nlrow;              /**< nonlinear row representation of constraint */
157 };
158 
159 /** constraint handler data */
160 struct SCIP_ConshdlrData
161 {
162    SCIP_Real             cutmaxrange;        /**< maximal coef range (maximal abs coef / minimal abs coef) of a cut in order to be added to LP */
163    SCIP_Bool             projectrefpoint;    /**< whether to project the reference point when linearizing a absolute power constraint in a convex region */
164    int                   preferzerobranch;   /**< how much we prefer to branch on 0.0 first */
165    SCIP_Bool             branchminconverror; /**< whether to compute branching point such that the convexification error is minimized after branching on 0.0 */
166    SCIP_Bool             addvarboundcons;    /**< should variable bound constraints be added? */
167    SCIP_Bool             linfeasshift;       /**< try linear feasibility shift heuristic in CONSCHECK */
168    SCIP_Bool             dualpresolve;       /**< should dual presolve be applied? */
169    SCIP_Bool             sepainboundsonly;   /**< should tangents only be generated in variable bounds during separation? */
170    SCIP_Real             sepanlpmincont;     /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
171    SCIP_Bool             enfocutsremovable;  /**< are cuts added during enforcement removable from the LP in the same node? */
172 
173    SCIP_HEUR*            subnlpheur;         /**< a pointer to the subnlp heuristic */
174    SCIP_HEUR*            trysolheur;         /**< a pointer to the trysol heuristic */
175    SCIP_EVENTHDLR*       eventhdlr;          /**< our handler for bound change events on variable x */
176    SCIP_CONSHDLR*        conshdlrindicator;  /**< a pointer to the indicator constraint handler */
177    int                   newsoleventfilterpos;/**< filter position of new solution event handler, if catched */
178    SCIP_Bool             comparedpairwise;   /**< did we compare absolute power constraints pairwise in this run? */
179    SCIP_Bool             sepanlp;            /**< where linearization of the NLP relaxation solution added? */
180    SCIP_NODE*            lastenfonode;       /**< the node for which enforcement was called the last time (and some constraint was violated) */
181    int                   nenforounds;        /**< counter on number of enforcement rounds for the current node */
182    unsigned int          nsecantcuts;        /**< number of secant cuts created so far */
183    unsigned int          ncuts;              /**< number of linearization cuts created so far */
184 };
185 
186 /*
187  * Propagation rules
188  */
189 
190 enum Proprule
191 {
192    PROPRULE_1,                               /**< left hand side and bounds on z -> lower bound on x */
193    PROPRULE_2,                               /**< left hand side and upper bound on x -> bound on z */
194    PROPRULE_3,                               /**< right hand side and bounds on z -> upper bound on x */
195    PROPRULE_4,                               /**< right hand side and lower bound on x -> bound on z */
196    PROPRULE_INVALID                          /**< propagation was applied without a specific propagation rule */
197 };
198 typedef enum Proprule PROPRULE;
199 
200 /*
201  * Local methods
202  */
203 
204 /** computes bounds on x in a absolute power constraints for given bounds on z */
205 static
206 void computeBoundsX(
207    SCIP*                 scip,               /**< SCIP data structure */
208    SCIP_CONS*            cons,               /**< constraint */
209    SCIP_INTERVAL         zbnds,              /**< bounds on x that are to be propagated */
210    SCIP_INTERVAL*        xbnds               /**< buffer to store corresponding bounds on z */
211    );
212 
213 /** power function for square, that should be faster than using pow(x, 2.0) */
214 static
DECL_MYPOW(square)215 DECL_MYPOW(square)
216 {
217    assert(exponent == 2.0);
218    return base*base;
219 }
220 
221 /** process variable event */
222 static
SCIP_DECL_EVENTEXEC(processVarEvent)223 SCIP_DECL_EVENTEXEC(processVarEvent)
224 {
225    SCIP_CONS* cons;
226 
227    assert(scip  != NULL);
228    assert(event != NULL);
229    assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_BOUNDTIGHTENED);
230 
231    cons = (SCIP_CONS*) eventdata;
232    assert(cons != NULL);
233 
234    assert(SCIPconsGetData(cons) != NULL);
235    assert(SCIPeventGetVar(event) == SCIPconsGetData(cons)->x || SCIPeventGetVar(event) == SCIPconsGetData(cons)->z);
236 
237    SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
238 
239    return SCIP_OKAY;
240 }  /*lint !e715*/
241 
242 /** catch variable bound tightening events */
243 static
catchVarEvents(SCIP * scip,SCIP_EVENTHDLR * eventhdlr,SCIP_CONS * cons)244 SCIP_RETCODE catchVarEvents(
245    SCIP*                 scip,               /**< SCIP data structure */
246    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler for variables */
247    SCIP_CONS*            cons                /**< constraint for which to catch bound change events */
248    )
249 {
250    SCIP_CONSDATA* consdata;
251    SCIP_EVENTTYPE eventtype;
252 
253    assert(scip != NULL);
254    assert(cons != NULL);
255    assert(eventhdlr != NULL);
256 
257    consdata = SCIPconsGetData(cons);
258    assert(consdata != NULL);
259 
260    /* if z is multiaggregated, then bound changes on x could not be propagated, so we do not need to catch them */
261    if( SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR )
262    {
263       eventtype = SCIP_EVENTTYPE_DISABLED;
264       if( !SCIPisInfinity(scip, -consdata->lhs) )
265          eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
266       if( !SCIPisInfinity(scip,  consdata->rhs) )
267          eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
268 
269       SCIP_CALL( SCIPcatchVarEvent(scip, consdata->x, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, &consdata->xeventfilterpos) );
270 
271       SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
272    }
273 
274    /* if x is multiaggregated, then bound changes on z could not be propagated, so we do not need to catch them */
275    if( SCIPvarGetStatus(consdata->x) != SCIP_VARSTATUS_MULTAGGR )
276    {
277       eventtype = SCIP_EVENTTYPE_DISABLED;
278       if( consdata->zcoef > 0.0 )
279       {
280          if( !SCIPisInfinity(scip, -consdata->lhs) )
281             eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
282          if( !SCIPisInfinity(scip,  consdata->rhs) )
283             eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
284       }
285       else
286       {
287          if( !SCIPisInfinity(scip, -consdata->lhs) )
288             eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
289          if( !SCIPisInfinity(scip,  consdata->rhs) )
290             eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
291       }
292 
293       SCIP_CALL( SCIPcatchVarEvent(scip, consdata->z, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, &consdata->zeventfilterpos) );
294 
295       SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
296    }
297 
298    return SCIP_OKAY;
299 }
300 
301 /** drop variable bound tightening events */
302 static
dropVarEvents(SCIP * scip,SCIP_EVENTHDLR * eventhdlr,SCIP_CONS * cons)303 SCIP_RETCODE dropVarEvents(
304    SCIP*                 scip,               /**< SCIP data structure */
305    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler for variables */
306    SCIP_CONS*            cons                /**< constraint for which to drop bound change events */
307    )
308 {
309    SCIP_CONSDATA* consdata;
310    SCIP_EVENTTYPE eventtype;
311 
312    assert(scip != NULL);
313    assert(cons != NULL);
314    assert(eventhdlr != NULL);
315 
316    consdata = SCIPconsGetData(cons);
317    assert(consdata != NULL);
318 
319    if( SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR )
320    {
321       eventtype = SCIP_EVENTTYPE_DISABLED;
322       if( !SCIPisInfinity(scip, -consdata->lhs) )
323          eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
324       if( !SCIPisInfinity(scip,  consdata->rhs) )
325          eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
326 
327       SCIP_CALL( SCIPdropVarEvent(scip, consdata->x, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, consdata->xeventfilterpos) );
328       consdata->xeventfilterpos = -1;
329    }
330 
331    if( SCIPvarGetStatus(consdata->x) != SCIP_VARSTATUS_MULTAGGR )
332    {
333       eventtype = SCIP_EVENTTYPE_DISABLED;
334       if( consdata->zcoef > 0.0 )
335       {
336          if( !SCIPisInfinity(scip, -consdata->lhs) )
337             eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
338          if( !SCIPisInfinity(scip,  consdata->rhs) )
339             eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
340       }
341       else
342       {
343          if( !SCIPisInfinity(scip, -consdata->lhs) )
344             eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
345          if( !SCIPisInfinity(scip,  consdata->rhs) )
346             eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
347       }
348 
349       SCIP_CALL( SCIPdropVarEvent(scip, consdata->z, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, consdata->zeventfilterpos) );
350       consdata->zeventfilterpos = -1;
351    }
352 
353    assert(consdata->xeventfilterpos == -1);
354    assert(consdata->zeventfilterpos == -1);
355 
356    return SCIP_OKAY;
357 }
358 
359 /** get key of hash element */
360 static
SCIP_DECL_HASHGETKEY(presolveFindDuplicatesGetKey)361 SCIP_DECL_HASHGETKEY(presolveFindDuplicatesGetKey)
362 {
363    return elem;
364 }  /*lint !e715*/
365 
366 /** checks if two constraints have the same x variable, the same exponent, and either the same offset or the same linear variable and are both equality constraint */
367 static
SCIP_DECL_HASHKEYEQ(presolveFindDuplicatesKeyEQ)368 SCIP_DECL_HASHKEYEQ(presolveFindDuplicatesKeyEQ)
369 {
370    SCIP_CONSDATA* consdata1;
371    SCIP_CONSDATA* consdata2;
372 
373    consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
374    consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
375    assert(consdata1 != NULL);
376    assert(consdata2 != NULL);
377 
378    if( consdata1->x != consdata2->x )
379       return FALSE;
380 
381    if( consdata1->exponent != consdata2->exponent )  /*lint !e777*/
382       return FALSE;
383 
384    if( consdata1->xoffset != consdata2->xoffset && consdata1->z != consdata2->z )  /*lint !e777*/
385       return FALSE;
386 
387    return TRUE;
388 }  /*lint !e715*/
389 
390 /** get value of hash element when comparing on x */
391 static
SCIP_DECL_HASHKEYVAL(presolveFindDuplicatesKeyVal)392 SCIP_DECL_HASHKEYVAL(presolveFindDuplicatesKeyVal)
393 {
394    SCIP_CONSDATA* consdata;
395 
396    consdata = SCIPconsGetData((SCIP_CONS*)key);
397    assert(consdata != NULL);
398 
399    return SCIPhashTwo(SCIPvarGetIndex(consdata->x),
400                       SCIPrealHashCode(consdata->exponent));
401 }  /*lint !e715*/
402 
403 /** checks if two constraints have the same z variable and the same exponent */
404 static
SCIP_DECL_HASHKEYEQ(presolveFindDuplicatesKeyEQ2)405 SCIP_DECL_HASHKEYEQ(presolveFindDuplicatesKeyEQ2)
406 {
407    SCIP_CONSDATA* consdata1;
408    SCIP_CONSDATA* consdata2;
409 
410    consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
411    consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
412    assert(consdata1 != NULL);
413    assert(consdata2 != NULL);
414 
415    if( consdata1->z != consdata2->z )
416       return FALSE;
417 
418    if( consdata1->exponent != consdata2->exponent )  /*lint !e777*/
419       return FALSE;
420 
421    return TRUE;
422 }  /*lint !e715*/
423 
424 /** get value of hash element when comparing on z */
425 static
SCIP_DECL_HASHKEYVAL(presolveFindDuplicatesKeyVal2)426 SCIP_DECL_HASHKEYVAL(presolveFindDuplicatesKeyVal2)
427 {
428    SCIP_CONSDATA* consdata;
429 
430    consdata = SCIPconsGetData((SCIP_CONS*)key);
431    assert(consdata != NULL);
432 
433    return SCIPhashTwo(SCIPvarGetIndex(consdata->z),
434                       SCIPrealHashCode(consdata->exponent));
435 }  /*lint !e715*/
436 
437 /** upgrades a signpower constraint to a linear constraint if a second signpower constraint with same nonlinear term is available */
438 static
presolveFindDuplicatesUpgradeCons(SCIP * scip,SCIP_CONS * cons1,SCIP_CONS * cons2,SCIP_Bool * infeas,int * nupgdconss,int * ndelconss,int * naggrvars)439 SCIP_RETCODE presolveFindDuplicatesUpgradeCons(
440    SCIP*                 scip,               /**< SCIP data structure */
441    SCIP_CONS*            cons1,              /**< constraint to upgrade to a linear constraint */
442    SCIP_CONS*            cons2,              /**< constraint which defines a relation for x|x|^{n-1} */
443    SCIP_Bool*            infeas,             /**< buffer where to indicate if infeasibility has been detected */
444    int*                  nupgdconss,         /**< buffer where to add number of upgraded conss */
445    int*                  ndelconss,          /**< buffer where to add number of deleted conss */
446    int*                  naggrvars           /**< buffer where to add number of aggregated variables */
447    )
448 {
449    SCIP_CONSDATA* consdata1;
450    SCIP_CONSDATA* consdata2;
451    SCIP_CONS* lincons;
452    SCIP_Real  lhs;
453    SCIP_Real  rhs;
454    SCIP_VAR*  vars[2];
455    SCIP_Real  coefs[2];
456 
457    assert(scip  != NULL);
458    assert(cons1 != NULL);
459    assert(cons2 != NULL);
460    assert(infeas != NULL);
461    assert(nupgdconss != NULL);
462    assert(ndelconss != NULL);
463    assert(naggrvars != NULL);
464 
465    consdata1 = SCIPconsGetData(cons1);
466    consdata2 = SCIPconsGetData(cons2);
467    assert(consdata1 != NULL);
468    assert(consdata2 != NULL);
469 
470    assert(SCIPisEQ(scip, consdata2->lhs, consdata2->rhs));
471    assert(!SCIPisInfinity(scip, consdata2->lhs));
472    assert(consdata1->x        == consdata2->x);
473    assert(consdata1->exponent == consdata2->exponent);  /*lint !e777*/
474    assert(consdata1->xoffset  == consdata2->xoffset);   /*lint !e777*/
475 
476    lhs = consdata1->lhs;
477    if( !SCIPisInfinity(scip, -lhs) )
478       lhs -= consdata2->lhs;
479    rhs = consdata1->rhs;
480    if( !SCIPisInfinity(scip,  rhs) )
481       rhs -= consdata2->lhs;
482 
483    vars[0] = consdata1->z;
484    vars[1] = consdata2->z;
485 
486    coefs[0] =  consdata1->zcoef;
487    coefs[1] = -consdata2->zcoef;
488 
489    if( SCIPisEQ(scip, lhs, rhs) )
490    {
491       SCIP_Bool redundant;
492       SCIP_Bool aggregated;
493 
494       /* try aggregation */
495       SCIP_CALL( SCIPaggregateVars(scip, consdata1->z, consdata2->z, consdata1->zcoef, -consdata2->zcoef, rhs, infeas, &redundant, &aggregated) );
496 
497       /* if infeasibility has been detected, stop here */
498       if( *infeas )
499          return SCIP_OKAY;
500 
501       if( redundant )
502       {
503          /* if redundant is TRUE, then either the aggregation has been done, or it was redundant */
504          if( aggregated )
505             ++*naggrvars;
506 
507          ++*ndelconss;
508 
509          SCIP_CALL( SCIPdelCons(scip, cons1) );
510          return SCIP_OKAY;
511       }
512    }
513 
514    /* if aggregation did not succeed, then either because some variable is multi-aggregated or due to numerics or because lhs != rhs
515     * we then add a linear constraint instead
516     */
517    vars[0] = consdata1->z;
518    vars[1] = consdata2->z;
519    coefs[0] =  consdata1->zcoef;
520    coefs[1] = -consdata2->zcoef;
521 
522    SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons1), 2, vars, coefs, lhs, rhs,
523          SCIPconsIsInitial(cons1), SCIPconsIsSeparated(cons1), SCIPconsIsEnforced(cons1),
524          SCIPconsIsChecked(cons1), SCIPconsIsPropagated(cons1),  SCIPconsIsLocal(cons1),
525          SCIPconsIsModifiable(cons1), SCIPconsIsDynamic(cons1), SCIPconsIsRemovable(cons1),
526          SCIPconsIsStickingAtNode(cons1)) );
527    SCIP_CALL( SCIPaddCons(scip, lincons) );
528    SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
529 
530    SCIP_CALL( SCIPdelCons(scip, cons1) );
531    ++*nupgdconss;
532 
533    return SCIP_OKAY;
534 }
535 
536 /** solves a system of two absolute power equations
537  * Given:   (x+xoffset1)|x+xoffset1|^{exponent-1} + zcoef1 * z == rhs1
538  *      and (x+xoffset2)|x+xoffset2|^{exponent-1} + zcoef2 * z == rhs2
539  * with xoffset1 != xoffset2 and zcoef1 * rhs2 == zcoef2 * rhs1 and exponent == 2,
540  * finds values for x and z that satisfy these equations, or reports infeasibility if no solution exists.
541  *
542  * Multiplying the second equation by -zcoef1/zcoef2 and adding it to the first one gives
543  *   (x+xoffset1)|x+xoffset1| - zcoef1/zcoef2 (x+offset2)|x+offset2| == 0
544  *
545  * If zcoef1 == zcoef2, then there exists, due to monotonicity of x|x|, no x such that
546  *   (x+xoffset1)|x+xoffset1| == (x+xoffset2)|x+xoffset2|.
547  *
548  * In general, for zcoef1 / zcoef2 > 0.0, we get
549  *   x = (xoffset2 - xoffset1) / (sqrt(zcoef2 / zcoef1) - 1.0) - xoffset1,
550  * and for zcoef1 / zcoef2 < 0.0, we get
551  *   x = (xoffset2 - xoffset1) / (-sqrt(-zcoef2 / zcoef1) - 1.0) - xoffset1.
552  *
553  * This then yields z = (rhs1 - (x+xoffset1)|x+xoffset1|) / zcoef1.
554  */
555 static
presolveFindDuplicatesSolveEquations(SCIP * scip,SCIP_Bool * infeas,SCIP_Real * xval,SCIP_Real * zval,SCIP_Real exponent,SCIP_Real xoffset1,SCIP_Real zcoef1,SCIP_Real rhs1,SCIP_Real xoffset2,SCIP_Real zcoef2,SCIP_Real rhs2)556 void presolveFindDuplicatesSolveEquations(
557    SCIP*                 scip,               /**< SCIP data structure */
558    SCIP_Bool*            infeas,             /**< buffer to indicate if the system of equations has no solution */
559    SCIP_Real*            xval,               /**< buffer to store value of x in the solution, if any */
560    SCIP_Real*            zval,               /**< buffer to store value of z in the solution, if any */
561    SCIP_Real             exponent,           /**< exponent in absolute power equations */
562    SCIP_Real             xoffset1,           /**< offset for x in first absolute power equation */
563    SCIP_Real             zcoef1,             /**< coefficient of z in first absolute power equation */
564    SCIP_Real             rhs1,               /**< right-hand-side in first absolute power equation */
565    SCIP_Real             xoffset2,           /**< offset for x in second absolute power equation */
566    SCIP_Real             zcoef2,             /**< coefficient of z in second absolute power equation */
567    SCIP_Real             rhs2                /**< right-hand-side in second absolute power equation */
568    )
569 {
570    assert(scip != NULL);
571    assert(infeas != NULL);
572    assert(xval != NULL);
573    assert(zval != NULL);
574    assert(exponent == 2.0);
575    assert(!SCIPisEQ(scip, xoffset1, xoffset2));
576    assert(SCIPisEQ(scip, zcoef1 * rhs2, zcoef2 * rhs1));
577    assert(zcoef1 != 0.0);
578    assert(zcoef2 != 0.0);
579 
580    if( xoffset2 < xoffset1 )
581    {
582       presolveFindDuplicatesSolveEquations(scip, infeas, xval, zval, exponent, xoffset2, zcoef2, rhs2, xoffset1, zcoef1, rhs1);
583       return;
584    }
585 
586    if( SCIPisEQ(scip, zcoef1, zcoef2) )
587    {
588       *infeas = TRUE;
589       return;
590    }
591 
592    *infeas = FALSE;
593 
594    if( SCIPisEQ(scip, zcoef1, -zcoef2) )
595    {
596       *xval = - (xoffset1 + xoffset2) / 2.0;
597    }
598    else if( zcoef2 * zcoef1 > 0.0 )
599    {
600       *xval = (xoffset2 - xoffset1) / (sqrt(zcoef2 / zcoef1) - 1.0) - xoffset1;
601    }
602    else
603    {
604       assert(zcoef2 * zcoef1 < 0.0);
605       *xval = (xoffset2 - xoffset1) / (-sqrt(-zcoef2 / zcoef1) - 1.0) - xoffset1;
606    }
607 
608    *zval = rhs1 - (*xval + xoffset1) * REALABS(*xval + xoffset1);
609    *zval /= zcoef1;
610 
611    assert(SCIPisFeasEQ(scip, (*xval + xoffset1) * REALABS(*xval + xoffset1) + zcoef1 * *zval, rhs1));
612    assert(SCIPisFeasEQ(scip, (*xval + xoffset2) * REALABS(*xval + xoffset2) + zcoef2 * *zval, rhs2));
613 }
614 
615 /** finds and removes duplicates in a set of absolute power constraints */
616 static
presolveFindDuplicates(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int * nupgdconss,int * ndelconss,int * naddconss,int * nfixedvars,int * naggrvars,SCIP_Bool * success,SCIP_Bool * infeas)617 SCIP_RETCODE presolveFindDuplicates(
618    SCIP*                 scip,               /**< SCIP data structure */
619    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler for absolute power constraints */
620    SCIP_CONS**           conss,              /**< constraints */
621    int                   nconss,             /**< number of constraints */
622    int*                  nupgdconss,         /**< pointer where to add number of upgraded constraints */
623    int*                  ndelconss,          /**< pointer where to add number of deleted constraints */
624    int*                  naddconss,          /**< pointer where to add number of added constraints */
625    int*                  nfixedvars,         /**< pointer where to add number of fixed variables */
626    int*                  naggrvars,          /**< pointer where to add number of aggregated variables */
627    SCIP_Bool*            success,            /**< pointer to store whether a duplicate was found (and removed) */
628    SCIP_Bool*            infeas              /**< pointer to store whether infeasibility was detected */
629    )
630 {
631    SCIP_MULTIHASH*     multihash;
632    SCIP_MULTIHASHLIST* multihashlist;
633    SCIP_CONSHDLRDATA*  conshdlrdata;
634    int c;
635 
636    assert(scip     != NULL);
637    assert(conshdlr != NULL);
638    assert(conss    != NULL || nconss == 0);
639    assert(nupgdconss != NULL);
640    assert(ndelconss != NULL);
641    assert(naddconss != NULL);
642    assert(nfixedvars != NULL);
643    assert(naggrvars != NULL);
644    assert(success  != NULL);
645    assert(infeas != NULL);
646 
647    *success = FALSE;
648    *infeas = FALSE;
649 
650    if( nconss <= 1 )
651       return SCIP_OKAY;
652 
653    conshdlrdata = SCIPconshdlrGetData(conshdlr);
654    assert(conshdlrdata != NULL);
655 
656    /* check all constraints in the given set for duplicates, dominance, or possible simplifications w.r.t. the x variable */
657 
658    SCIP_CALL( SCIPmultihashCreate(&multihash, SCIPblkmem(scip), SCIPcalcMultihashSize(nconss),
659          presolveFindDuplicatesGetKey, presolveFindDuplicatesKeyEQ, presolveFindDuplicatesKeyVal, (void*)scip) );
660 
661    for( c = 0; c < nconss && !*infeas; ++c )
662    {
663       SCIP_CONS* cons0;
664       SCIP_CONS* cons1;
665 
666       cons0 = conss[c];  /*lint !e613*/
667 
668       assert(!SCIPconsIsModifiable(cons0));  /* absolute power constraints aren't modifiable */
669       assert(!SCIPconsIsLocal(cons0));       /* shouldn't have local constraints in presolve */
670       assert(SCIPconsIsActive(cons0));       /* shouldn't get inactive constraints here */
671 
672       multihashlist = NULL;
673 
674       do
675       {
676          SCIP_CONSDATA* consdata0;
677          SCIP_CONSDATA* consdata1;
678 
679          /* get constraint from current hash table with same x variable as cons0 and same exponent */
680          cons1 = (SCIP_CONS*)(SCIPmultihashRetrieveNext(multihash, &multihashlist, (void*)cons0));
681          if( cons1 == NULL )
682          {
683             /* processed all constraints like cons0 from hash table, so insert cons0 and go to conss[c+1] */
684             SCIP_CALL( SCIPmultihashInsert(multihash, (void*) cons0) );
685             break;
686          }
687 
688          assert(cons0 != cons1);
689 
690          consdata0 = SCIPconsGetData(cons0);
691          consdata1 = SCIPconsGetData(cons1);
692          assert(consdata0 != NULL);
693          assert(consdata1 != NULL);
694 
695          SCIPdebugPrintCons(scip, cons0, NULL);
696          SCIPdebugPrintCons(scip, cons1, NULL);
697 
698          assert(consdata0->x        == consdata1->x);
699          assert(consdata0->exponent == consdata1->exponent);  /*lint !e777*/
700 
701          if( SCIPisEQ(scip, consdata0->xoffset, consdata1->xoffset) )
702          {
703             /* we have two constraints with the same (x+offset)|x+offset|^n term */
704 
705             /* if both constraints have the same functions; strengthen sides of cons1 and throw cons0 away */
706             if( consdata0->z == consdata1->z && SCIPisEQ(scip, consdata0->zcoef, consdata1->zcoef) )
707             {
708                /* check if side strenghtening would result in inconsistency */
709                if( SCIPisGT(scip, consdata0->lhs, consdata1->rhs) || SCIPisGT(scip, consdata1->lhs, consdata0->rhs) )
710                {
711                   SCIPdebugMsg(scip, "<%s> and <%s> are contradictory; declare infeasibility\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
712                   *infeas = TRUE;
713                   break;
714                }
715 
716                SCIPdebugMsg(scip, "<%s> and <%s> are equivalent; dropping the first\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
717 
718                /* if a side of cons1 gets finite via merging with cons0, then this changes locks and events */
719                if( (SCIPisInfinity(scip, -consdata1->lhs) && !SCIPisInfinity(scip, -consdata0->lhs)) ||
720                   ( SCIPisInfinity(scip,  consdata1->rhs) && !SCIPisInfinity(scip,  consdata0->rhs)) )
721                {
722                   SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons1) );
723                   SCIP_CALL( SCIPunlockVarCons(scip, consdata1->x, cons1, !SCIPisInfinity(scip, -consdata1->lhs), !SCIPisInfinity(scip, consdata1->rhs)) );
724                   if( consdata1->zcoef > 0.0 )
725                      SCIP_CALL( SCIPunlockVarCons(scip, consdata1->z, cons1, !SCIPisInfinity(scip, -consdata1->lhs), !SCIPisInfinity(scip,  consdata1->rhs)) );
726                   else
727                      SCIP_CALL( SCIPunlockVarCons(scip, consdata1->z, cons1, !SCIPisInfinity(scip,  consdata1->rhs), !SCIPisInfinity(scip, -consdata1->lhs)) );
728 
729                   consdata1->lhs = MAX(consdata0->lhs, consdata1->lhs);
730                   consdata1->rhs = MIN(consdata0->rhs, consdata1->rhs);
731 
732                   SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons1) );
733                   SCIP_CALL( SCIPlockVarCons(scip, consdata1->x, cons1, !SCIPisInfinity(scip, -consdata1->lhs), !SCIPisInfinity(scip, consdata1->rhs)) );
734                   if( consdata1->zcoef > 0.0 )
735                      SCIP_CALL( SCIPlockVarCons(scip, consdata1->z, cons1, !SCIPisInfinity(scip, -consdata1->lhs), !SCIPisInfinity(scip,  consdata1->rhs)) );
736                   else
737                      SCIP_CALL( SCIPlockVarCons(scip, consdata1->z, cons1, !SCIPisInfinity(scip,  consdata1->rhs), !SCIPisInfinity(scip, -consdata1->lhs)) );
738                }
739                else
740                {
741                   consdata1->lhs = MAX(consdata0->lhs, consdata1->lhs);
742                   consdata1->rhs = MIN(consdata0->rhs, consdata1->rhs);
743                }
744 
745                SCIP_CALL( SCIPdelCons(scip, cons0) );
746                ++*ndelconss;
747                *success = TRUE;
748 
749                break;
750             }
751 
752             /* if cons1 defines a linear expression for sign(x+offset)|x+offset|^n, use it to replace cons0 by a linear constraint */
753             if( SCIPisEQ(scip, consdata1->lhs, consdata1->rhs) )
754             {
755                SCIPdebugMsg(scip, "substitute <%s> in <%s> to make linear constraint\n", SCIPconsGetName(cons1), SCIPconsGetName(cons0));
756                SCIP_CALL( presolveFindDuplicatesUpgradeCons(scip, cons0, cons1, infeas, nupgdconss, ndelconss, naggrvars) );
757 
758                *success = TRUE;
759                break;
760             }
761 
762             /* if cons0 defines a linear expression for sign(x+offset)|x+offset|^n, use it to replace cons1 by a linear constraint */
763             if( SCIPisEQ(scip, consdata0->lhs, consdata0->rhs) )
764             {
765                SCIPdebugMsg(scip, "substitute <%s> in <%s> to make linear constraint\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
766                SCIP_CALL( presolveFindDuplicatesUpgradeCons(scip, cons1, cons0, infeas, nupgdconss, ndelconss, naggrvars) );
767 
768                SCIP_CALL( SCIPmultihashRemove(multihash, cons1) );
769                *success = TRUE;
770 
771                if( *infeas )
772                   break;
773             }
774             else
775             {
776                /* introduce a new equality constraint for sign(x+offset)|x+offset|^n and use it to replace cons0 and cons1 */
777                /* @todo maybe we could be more clever by looking which constraint sides are finite */
778                SCIP_VAR*  auxvar;
779                SCIP_CONS* auxcons;
780                char       name[SCIP_MAXSTRLEN];
781                SCIP_VAR*  vars[2];
782                SCIP_Real  coefs[2];
783 
784                SCIPdebugMsg(scip, "introduce new auxvar for signpower(%s+%g, %g) to make <%s> and <%s> linear constraint\n", SCIPvarGetName(consdata0->x), consdata0->exponent, consdata0->xoffset, SCIPconsGetName(cons0), SCIPconsGetName(cons1));
785 
786                /* create auxiliary variable to represent sign(x+offset)|x+offset|^n */
787                (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_abspower%s_%g_%g", SCIPvarGetName(consdata0->x), consdata0->exponent, consdata0->xoffset);
788                SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
789                      TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
790                SCIP_CALL( SCIPaddVar(scip, auxvar) );
791 
792                /* create auxiliary constraint auxvar = sign(x+offset)|x+offset|^n
793                 * as we introduced a new variable, the constraint that "defines" the value for this variable need to be enforced, that is, is not redundent
794                 */
795                (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxcons_abspower%s_%g_%g", SCIPvarGetName(consdata0->x), consdata0->exponent, consdata0->xoffset);
796                SCIP_CALL( SCIPcreateConsAbspower(scip, &auxcons, name, consdata0->x, auxvar, consdata0->exponent, consdata0->xoffset, -1.0, 0.0, 0.0,
797                      SCIPconsIsInitial(cons0) || SCIPconsIsInitial(cons1),
798                      SCIPconsIsSeparated(cons0) || SCIPconsIsSeparated(cons1),
799                      TRUE,
800                      TRUE,
801                      SCIPconsIsPropagated(cons0) || SCIPconsIsPropagated(cons1),
802                      FALSE,
803                      FALSE,
804                      SCIPconsIsDynamic(cons0) || SCIPconsIsDynamic(cons1),
805                      SCIPconsIsRemovable(cons0) || SCIPconsIsRemovable(cons1),
806                      SCIPconsIsStickingAtNode(cons0) || SCIPconsIsStickingAtNode(cons1)
807                      ) );
808                SCIP_CALL( SCIPaddCons(scip, auxcons) );
809                SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
810                ++*naddconss;
811 
812 #ifdef WITH_DEBUG_SOLUTION
813                if( SCIPdebugIsMainscip(scip) )
814                {
815                   SCIP_Real xval;
816 
817                   SCIP_CALL( SCIPdebugGetSolVal(scip, consdata0->x, &xval) );
818                   SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SIGN(xval + consdata0->xoffset) * pow(REALABS(xval + consdata0->xoffset), consdata0->exponent)) );
819                }
820 #endif
821 
822                /* create linear constraint equivalent for cons0 */
823                vars[0]  = auxvar;
824                vars[1]  = consdata0->z;
825                coefs[0] = 1.0;
826                coefs[1] = consdata0->zcoef;
827                SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, SCIPconsGetName(cons0), 2, vars, coefs, consdata0->lhs, consdata0->rhs,
828                      SCIPconsIsInitial(cons0), SCIPconsIsSeparated(cons0), SCIPconsIsEnforced(cons0),
829                      SCIPconsIsChecked(cons0), SCIPconsIsPropagated(cons0), SCIPconsIsLocal(cons0),
830                      SCIPconsIsModifiable(cons0), SCIPconsIsDynamic(cons0), SCIPconsIsRemovable(cons0),
831                      SCIPconsIsStickingAtNode(cons0)) );
832                SCIP_CALL( SCIPaddCons(scip, auxcons) );
833                SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
834                ++*nupgdconss;
835 
836                /* create linear constraint equivalent for cons1 */
837                vars[1]  = consdata1->z;
838                coefs[1] = consdata1->zcoef;
839                SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, SCIPconsGetName(cons1), 2, vars, coefs, consdata1->lhs, consdata1->rhs,
840                      SCIPconsIsInitial(cons1), SCIPconsIsSeparated(cons1), SCIPconsIsEnforced(cons1),
841                      SCIPconsIsChecked(cons1), SCIPconsIsPropagated(cons1), SCIPconsIsLocal(cons1),
842                      SCIPconsIsModifiable(cons1), SCIPconsIsDynamic(cons1), SCIPconsIsRemovable(cons1),
843                      SCIPconsIsStickingAtNode(cons1)) );
844                SCIP_CALL( SCIPaddCons(scip, auxcons) );
845                SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
846                ++*nupgdconss;
847 
848                SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
849 
850                SCIP_CALL( SCIPdelCons(scip, cons0) );
851                SCIP_CALL( SCIPdelCons(scip, cons1) );
852                SCIP_CALL( SCIPmultihashRemove(multihash, cons1) );
853                *success = TRUE;
854 
855                break;
856             }
857          }
858          else if( consdata0->z == consdata1->z &&
859             consdata0->exponent == 2.0 &&
860             !SCIPisZero(scip, consdata0->zcoef) &&
861             !SCIPisZero(scip, consdata1->zcoef) &&
862             SCIPisEQ(scip, consdata0->lhs, consdata0->rhs) &&
863             SCIPisEQ(scip, consdata1->lhs, consdata1->rhs) &&
864             SCIPisEQ(scip, consdata0->lhs * consdata1->zcoef, consdata1->lhs * consdata0->zcoef) )
865          {
866             /* If we have two equality constraints with the same variables and the same exponent and compatible constants,
867              * then this system of equations should have either no or a single solution.
868              * Thus, we can report cutoff or fix the variables to this solution, and forget about the constraints.
869              * @todo think about inequalities, differing exponents, and exponents != 2
870              */
871 
872             SCIP_Real xval;
873             SCIP_Real zval;
874 
875             assert(consdata0->x == consdata1->x);
876             assert(consdata0->exponent == consdata1->exponent);  /*lint !e777*/
877             assert(!SCIPisEQ(scip, consdata0->xoffset, consdata1->xoffset));
878 
879             presolveFindDuplicatesSolveEquations(scip, infeas, &xval, &zval,
880                consdata0->exponent,
881                consdata0->xoffset, consdata0->zcoef, consdata0->lhs,
882                consdata1->xoffset, consdata1->zcoef, consdata1->lhs);
883 
884             if( *infeas )
885             {
886                SCIPdebugMsg(scip, "infeasibility detected while solving the equations, no solution exists\n");
887                SCIPdebugPrintCons(scip, cons0, NULL);
888                SCIPdebugPrintCons(scip, cons1, NULL);
889                break;
890             }
891 
892             SCIPdebugMsg(scip, "fixing variables <%s>[%g, %g] to %g and <%s>[%g, %g] to %g due to equations\n",
893                SCIPvarGetName(consdata0->x), SCIPvarGetLbLocal(consdata0->x), SCIPvarGetUbLocal(consdata0->x), xval,
894                SCIPvarGetName(consdata0->z), SCIPvarGetLbLocal(consdata0->z), SCIPvarGetUbLocal(consdata0->z), zval);
895             SCIPdebugPrintCons(scip, cons0, NULL);
896             SCIPdebugPrintCons(scip, cons1, NULL);
897 
898             if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata0->x)) != SCIP_VARSTATUS_MULTAGGR )
899             {
900                SCIP_Bool fixed;
901 
902                SCIP_CALL( SCIPfixVar(scip, consdata0->x, xval, infeas, &fixed) );
903                ++*ndelconss;
904 
905                if( fixed )
906                   ++*nfixedvars;
907 
908                if( *infeas )
909                {
910                   SCIPdebugMsg(scip, "infeasibility detected after fixing <%s>\n", SCIPvarGetName(consdata0->x));
911                   break;
912                }
913             }
914             else
915             {
916                SCIP_CONS* lincons;
917                SCIP_Real  one;
918 
919                one = 1.0;
920                SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons0), 1, &consdata0->x, &one, xval, xval,
921                      TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
922                SCIP_CALL( SCIPaddCons(scip, lincons) );
923                SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
924                ++*nupgdconss;
925             }
926 
927             if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata0->z)) != SCIP_VARSTATUS_MULTAGGR )
928             {
929                SCIP_Bool fixed;
930 
931                SCIP_CALL( SCIPfixVar(scip, consdata0->z, zval, infeas, &fixed) );
932                ++*ndelconss;
933 
934                if( fixed )
935                   ++*nfixedvars;
936 
937                if( *infeas )
938                {
939                   SCIPdebugMsg(scip, "infeasibility detected after fixing <%s>\n", SCIPvarGetName(consdata0->z));
940                   break;
941                }
942             }
943             else
944             {
945                SCIP_CONS* lincons;
946                SCIP_Real  one;
947 
948                one = 1.0;
949                SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons1), 1, &consdata0->z, &one, zval, zval,
950                      TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
951                SCIP_CALL( SCIPaddCons(scip, lincons) );
952                SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
953                ++*nupgdconss;
954             }
955 
956             SCIP_CALL( SCIPdelCons(scip, cons0) );
957             SCIP_CALL( SCIPdelCons(scip, cons1) );
958             SCIP_CALL( SCIPmultihashRemove(multihash, cons1) );
959             *success = TRUE;
960 
961             break;
962          }
963 
964          if( multihashlist == NULL )
965          {
966             /* processed all constraints like cons0 from hash table, but cons0 could not be removed, so insert cons0 into hashmap and go to conss[c+1] */
967             SCIP_CALL( SCIPmultihashInsert(multihash, (void*) cons0) );
968             break;
969          }
970       }
971       while( TRUE );  /*lint !e506*/
972    }
973 
974    /* free hash table */
975    SCIPmultihashFree(&multihash);
976 
977    if( *infeas )
978       return SCIP_OKAY;
979 
980    /* check all constraints in the given set for duplicates, dominance, or possible simplifications w.r.t. the z variable */
981 
982    SCIP_CALL( SCIPmultihashCreate(&multihash, SCIPblkmem(scip), SCIPcalcMultihashSize(nconss),
983          presolveFindDuplicatesGetKey, presolveFindDuplicatesKeyEQ2, presolveFindDuplicatesKeyVal2, (void*) scip) );
984 
985    for( c = 0; c < nconss && !*infeas; ++c )
986    {
987       SCIP_CONS* cons0;
988       SCIP_CONS* cons1;
989       SCIP_CONSDATA* consdata0;
990 
991       cons0 = conss[c];  /*lint !e613*/
992 
993       assert(!SCIPconsIsModifiable(cons0));  /* absolute power constraints aren't modifiable */
994       assert(!SCIPconsIsLocal(cons0));       /* shouldn't have local constraints in presolve */
995 
996       /* do not consider constraints that we have deleted in the above loop */
997       if( SCIPconsIsDeleted(cons0) )
998          continue;
999       assert(SCIPconsIsActive(cons0));       /* shouldn't get inactive constraints here */
1000 
1001       consdata0 = SCIPconsGetData(cons0);
1002       assert(consdata0 != NULL);
1003 
1004       /* consider only equality constraints so far
1005        * @todo do also something with inequalities
1006        */
1007       if( !SCIPisEQ(scip, consdata0->lhs, consdata0->rhs) )
1008          continue;
1009 
1010       multihashlist = NULL;
1011 
1012       do
1013       {
1014          SCIP_CONSDATA* consdata1;
1015 
1016          /* get constraint from current hash table with same z variable as cons0 and same exponent */
1017          cons1 = (SCIP_CONS*)(SCIPmultihashRetrieveNext(multihash, &multihashlist, (void*)cons0));
1018          if( cons1 == NULL )
1019          {
1020             /* processed all constraints like cons0 from hash table, so insert cons0 and go to conss[c+1] */
1021             SCIP_CALL( SCIPmultihashInsert(multihash, (void*) cons0) );
1022             break;
1023          }
1024 
1025          assert(cons0 != cons1);
1026          assert(!SCIPconsIsDeleted(cons1));
1027 
1028          consdata1 = SCIPconsGetData(cons1);
1029          assert(consdata1 != NULL);
1030 
1031          SCIPdebugPrintCons(scip, cons0, NULL);
1032          SCIPdebugPrintCons(scip, cons1, NULL);
1033 
1034          assert(consdata0->z        == consdata1->z);
1035          assert(consdata0->exponent == consdata1->exponent);  /*lint !e777*/
1036          assert(SCIPisEQ(scip, consdata1->lhs, consdata1->rhs));
1037          assert(!SCIPisZero(scip, consdata1->zcoef));
1038 
1039          if( SCIPisEQ(scip, consdata0->lhs*consdata1->zcoef, consdata1->lhs*consdata0->zcoef) )
1040          {
1041             /* have two absolute power equations with same z and compatible constants
1042              * we can then reduce this to one absolute power and one linear equation
1043              * -> x0 + xoffset0 = signpower(zcoef0/zcoef1, 1/exponent) (x1 + xoffset1)
1044              * -> keep cons1
1045              * the latter can be realized as an aggregation (if x0 and x1 are not multiaggregated) or linear constraint
1046              */
1047             SCIP_Bool redundant;
1048             SCIP_Bool aggregated;
1049             SCIP_Real coef;
1050             SCIP_Real rhs;
1051 
1052             SCIPdebugMsg(scip, "<%s> and <%s> can be reformulated to one abspower and one aggregation\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
1053             SCIPdebugPrintCons(scip, cons0, NULL);
1054             SCIPdebugPrintCons(scip, cons1, NULL);
1055 
1056             if( consdata0->exponent == 2.0 )
1057                coef = SIGN(consdata0->zcoef / consdata1->zcoef) * sqrt(REALABS(consdata0->zcoef / consdata1->zcoef));
1058             else
1059                coef = SIGN(consdata0->zcoef / consdata1->zcoef) * pow(REALABS(consdata0->zcoef / consdata1->zcoef), 1.0/consdata0->exponent);
1060             rhs = coef * consdata1->xoffset - consdata0->xoffset;
1061 
1062             /* try aggregation */
1063             SCIP_CALL( SCIPaggregateVars(scip, consdata0->x, consdata1->x, 1.0, -coef, rhs, infeas, &redundant, &aggregated) );
1064             if( *infeas )
1065             {
1066                /* if infeasibility has been detected, stop here */
1067                break;
1068             }
1069             else if( redundant )
1070             {
1071                /* if redundant is TRUE, then either the aggregation has been done, or it was redundant */
1072                if( aggregated )
1073                   ++*naggrvars;
1074 
1075                ++*ndelconss;
1076             }
1077             else
1078             {
1079                /* if aggregation did not succeed, then either because some variable is multi-aggregated or due to numerics
1080                 * we then add a linear constraint instead
1081                 */
1082                SCIP_CONS* auxcons;
1083                SCIP_VAR* vars[2];
1084                SCIP_Real coefs[2];
1085 
1086                vars[0] = consdata0->x;
1087                vars[1] = consdata1->x;
1088                coefs[0] = 1.0;
1089                coefs[1] = -coef;
1090 
1091                /* create linear constraint equivalent for cons0 */
1092                SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, SCIPconsGetName(cons0), 2, vars, coefs, rhs, rhs,
1093                      SCIPconsIsInitial(cons0), SCIPconsIsSeparated(cons0), SCIPconsIsEnforced(cons0),
1094                      SCIPconsIsChecked(cons0), SCIPconsIsPropagated(cons0), SCIPconsIsLocal(cons0),
1095                      SCIPconsIsModifiable(cons0), SCIPconsIsDynamic(cons0), SCIPconsIsRemovable(cons0),
1096                      SCIPconsIsStickingAtNode(cons0)) );
1097                SCIP_CALL( SCIPaddCons(scip, auxcons) );
1098                SCIPdebugPrintCons(scip, auxcons, NULL);
1099                SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
1100 
1101                ++*nupgdconss;
1102             }
1103             SCIP_CALL( SCIPdelCons(scip, cons0) );
1104 
1105             *success = TRUE;
1106             break;
1107          }
1108 
1109          if( multihashlist == NULL )
1110          {
1111             /* processed all constraints like cons0 from hash table, but cons0 could not be removed, so insert cons0 into hashmap and go to conss[c+1] */
1112             SCIP_CALL( SCIPmultihashInsert(multihash, (void*) cons0) );
1113             break;
1114          }
1115       }
1116       while( TRUE );  /*lint !e506*/
1117    }
1118 
1119    /* free hash table */
1120    SCIPmultihashFree(&multihash);
1121 
1122    return SCIP_OKAY;
1123 }
1124 
1125 /** fix variables not appearing in any other constraint
1126  *
1127  * @todo generalize to inequalities
1128  * @todo generalize to support discrete variables
1129  * @todo generalize to arbitrary exponents also if z is in objective
1130  */
1131 static
presolveDual(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * ndelconss,int * nfixedvars)1132 SCIP_RETCODE presolveDual(
1133    SCIP*                 scip,               /**< SCIP data structure */
1134    SCIP_CONS*            cons,               /**< constraint */
1135    SCIP_Bool*            cutoff,             /**< buffer to indicate whether a cutoff was detected */
1136    int*                  ndelconss,          /**< buffer to increase with the number of deleted constraint */
1137    int*                  nfixedvars          /**< buffer to increase with the number of fixed variables */
1138    )
1139 {
1140    SCIP_CONSDATA* consdata;
1141    SCIP_Bool lhsexists;
1142    SCIP_Bool rhsexists;
1143 
1144    assert(scip != NULL);
1145    assert(cons != NULL);
1146    assert(cutoff != NULL);
1147    assert(nfixedvars != NULL);
1148    assert(ndelconss != NULL);
1149 
1150    /* only process checked constraints (for which the locks are increased);
1151     * otherwise we would have to check for variables with nlocks == 0, and these are already processed by the
1152     * dualfix presolver
1153     */
1154    if( !SCIPconsIsChecked(cons) )
1155       return SCIP_OKAY;
1156 
1157    consdata = SCIPconsGetData(cons);
1158    assert(consdata != NULL);
1159 
1160    /* skip dual presolve if multiaggregated variables are present for now (bounds are not updated, difficult to fix) */
1161    if( SCIPvarGetStatus(consdata->x) == SCIP_VARSTATUS_MULTAGGR )
1162       return SCIP_OKAY;
1163    if( SCIPvarGetStatus(consdata->z) == SCIP_VARSTATUS_MULTAGGR )
1164       return SCIP_OKAY;
1165 
1166    /* skip dual presolve if discrete variables are present for now (more difficult to compute fixing value) */
1167    if( SCIPvarGetType(consdata->x) <= SCIP_VARTYPE_INTEGER )
1168       return SCIP_OKAY;
1169    if( SCIPvarGetType(consdata->z) <= SCIP_VARTYPE_INTEGER )
1170       return SCIP_OKAY;
1171 
1172    /* we assume that domain propagation has been run and fixed variables were removed if possible */
1173    assert(!SCIPconsIsMarkedPropagate(cons));
1174    assert(consdata->zcoef != 0.0);
1175 
1176    lhsexists = !SCIPisInfinity(scip, -consdata->lhs);
1177    rhsexists = !SCIPisInfinity(scip,  consdata->rhs);
1178 
1179    if( SCIPvarGetNLocksDownType(consdata->x, SCIP_LOCKTYPE_MODEL) == (lhsexists ? 1 : 0) &&
1180        SCIPvarGetNLocksUpType(consdata->x, SCIP_LOCKTYPE_MODEL)   == (rhsexists ? 1 : 0) &&
1181        (consdata->zcoef > 0.0 ? SCIPvarGetNLocksDownType(consdata->z, SCIP_LOCKTYPE_MODEL) :
1182          SCIPvarGetNLocksUpType(consdata->z, SCIP_LOCKTYPE_MODEL)) == (lhsexists ? 1 : 0) &&
1183        (consdata->zcoef > 0.0 ? SCIPvarGetNLocksUpType(consdata->z, SCIP_LOCKTYPE_MODEL) :
1184          SCIPvarGetNLocksDownType(consdata->z, SCIP_LOCKTYPE_MODEL)) == (rhsexists ? 1 : 0) )
1185    {
1186       /* x and z are only locked by cons, so we can fix them to an optimal solution of
1187        * min  xobj * x + zobj * z
1188        * s.t. lhs <= sign(x+offset)*abs(x+offset)^exponent + zcoef * z <= rhs
1189        *      xlb <= x <= xub
1190        *      zlb <= z <= zub
1191        */
1192       if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1193       {
1194          /* much simpler case where we can substitute z:
1195           * min xobj * x + zobj/zcoef * (rhs - sign(x+offset)*abs(x+offset)^exponent)
1196           * s.t. xlb <= x <= xub
1197           */
1198          SCIP_Real xfix;
1199          SCIP_Real xlb;
1200          SCIP_Real xub;
1201          SCIP_Real zfix;
1202          SCIP_INTERVAL xbnds;
1203          SCIP_INTERVAL zbnds;
1204          SCIP_Bool fixed;
1205 
1206          /* Since domain propagation has been applied, we would like to assume that for any valid value for x,
1207           * also the corresponding z value is valid. However, domain propagation only applies sufficiently
1208           * strong bound tightenings, so we better recompute the bounds on x.
1209           */
1210          SCIPintervalSetBounds(&zbnds, SCIPvarGetLbGlobal(consdata->z), SCIPvarGetUbGlobal(consdata->z));
1211          computeBoundsX(scip, cons, zbnds, &xbnds);
1212          xlb = MAX(SCIPvarGetLbGlobal(consdata->x), xbnds.inf); /*lint !e666*/
1213          xub = MIN(SCIPvarGetUbGlobal(consdata->x), xbnds.sup); /*lint !e666*/
1214 
1215          /* with our own "local" boundtightening, xlb might end slightly above xub,
1216           * which can result in xfix being outside bounds below, see also #2202
1217           */
1218          assert(SCIPisFeasLE(scip, xlb, xub));
1219          if( xub < xlb )
1220             xlb = xub = (xlb + xub)/2.0;
1221 
1222          if( SCIPisZero(scip, SCIPvarGetObj(consdata->z)) )
1223          {
1224             /* even simpler case where objective is linear in x */
1225             if( SCIPisZero(scip, SCIPvarGetObj(consdata->x)) )
1226             {
1227                /* simplest case where objective is zero:
1228                 * if zero is within bounds, fix to zero, otherwise
1229                 * fix x to middle of bounds for numerical stability. */
1230                 if(SCIPisLT(scip, xlb, 0.0) && SCIPisGT(scip, xub, 0.0))
1231                     xfix = 0.0;
1232                 else
1233                     xfix = 0.5 * (xlb + xub);
1234             }
1235             else
1236             {
1237                /* fix x to best bound */
1238                xfix = (SCIPvarGetObj(consdata->x) >= 0.0) ? xlb : xub;
1239             }
1240          }
1241          else if( consdata->exponent == 2.0 )
1242          {
1243             /* consider cases x <= -offset and x >= -offset separately */
1244             SCIP_Real a;
1245             SCIP_Real b;
1246             SCIP_Real c;
1247             SCIP_Real cand;
1248             SCIP_Real xfixobjval;
1249 
1250             xfix = SCIP_INVALID;
1251             xfixobjval = SCIP_INVALID;
1252 
1253             if( SCIPisLT(scip, xlb, -consdata->xoffset) )
1254             {
1255                /* For x <= -offset, the objective is equivalent to
1256                 *      zobj/zcoef * x^2 + (xobj + 2 offset zobj/zcoef) * x + offset^2 * zobj/zcoef + other constant
1257                 * <->        a    * x^2 +               b              * x +          c
1258                 *
1259                 * critical values for x are xlb, MIN(xub,-offset), and -b/(2*a)
1260                 */
1261                a = SCIPvarGetObj(consdata->z) / consdata->zcoef;
1262                b = SCIPvarGetObj(consdata->x) + 2 * consdata->xoffset * SCIPvarGetObj(consdata->z) / consdata->zcoef;
1263                c = consdata->xoffset * consdata->xoffset * SCIPvarGetObj(consdata->z) / consdata->zcoef;
1264 
1265                if( a < 0.0 && SCIPisInfinity(scip, -xlb) )
1266                {
1267                   /* if a < 0.0, then a*x^2 is unbounded for x -> -infinity, thus fix x to -infinity */
1268                   xfix = -SCIPinfinity(scip);
1269                   xfixobjval = -SCIPinfinity(scip);
1270                }
1271                else
1272                {
1273                   /* initialize with value for x=xlb */
1274                   xfix = xlb;
1275                   xfixobjval = a * xlb * xlb + b * xlb + c;
1276 
1277                   /* compare with value for x=MIN(-offset,xub) */
1278                   cand = MIN(-consdata->xoffset, xub);
1279                   if( xfixobjval > a * cand * cand + b * cand + c )
1280                   {
1281                      xfix = cand;
1282                      xfixobjval = a * cand * cand + b * cand + c;
1283                   }
1284 
1285                   /* compare with value for x=-b/(2*a), if within bounds */
1286                   cand = -b/(2.0*a);
1287                   if( cand > xlb && cand < -consdata->xoffset && cand < xub && xfixobjval > -b*b/(4.0*a) + c )
1288                   {
1289                      xfix = cand;
1290                      xfixobjval = -b*b/(4.0*a) + c;
1291                   }
1292                }
1293             }
1294 
1295             if( SCIPisGT(scip, xub, -consdata->xoffset) )
1296             {
1297                /* For x >= -offset, the objective is equivalent to
1298                 *     -zobj/zcoef * x^2 + (xobj - 2 offset zobj/zcoef) * x - offset^2 * zobj/zcoef + constants
1299                 * <->        a    * x^2 +               b              * x +         c
1300                 *
1301                 * critical values for x are xub, MAX(xlb,-offset), and -b/(2*a)
1302                 */
1303                a = -SCIPvarGetObj(consdata->z) / consdata->zcoef;
1304                b = SCIPvarGetObj(consdata->x) - 2 * consdata->xoffset * SCIPvarGetObj(consdata->z) / consdata->zcoef;
1305                c = -consdata->xoffset * consdata->xoffset * SCIPvarGetObj(consdata->z) / consdata->zcoef;
1306 
1307                if( a < 0.0 && SCIPisInfinity(scip, xub) )
1308                {
1309                   /* if a < 0.0, then a*x^2 is unbounded for x -> infinity, thus fix x to infinity */
1310                   xfix = SCIPinfinity(scip);
1311                   /* not needed: xfixobjval = SCIPinfinity(scip); */
1312                }
1313                else
1314                {
1315                   if( xfix == SCIP_INVALID ) /*lint !e777*/
1316                   {
1317                      /* initialize with value for x=xub */
1318                      xfix = xub;
1319                      xfixobjval = a * xub * xub + b * xub + c;
1320                   }
1321                   else
1322                   {
1323                      /* compare with value for x=xub */
1324                      cand = xub;
1325                      if( xfixobjval > a * cand * cand + b * cand + c )
1326                      {
1327                         xfix = cand;
1328                         xfixobjval = a * cand * cand + b * cand + c;
1329                      }
1330                   }
1331 
1332                   /* compare with value for x=MAX(xlb,-offset) */
1333                   cand = MAX(xlb, -consdata->xoffset);
1334                   if( xfixobjval > a * cand * cand + b * cand + c )
1335                   {
1336                      xfix = cand;
1337                      xfixobjval = a * cand * cand + b * cand + c;
1338                   }
1339 
1340                   /* compare with value for x=-b/(2*a), if within bounds */
1341                   cand = -b/(2.0*a);
1342                   if( cand > xlb && cand > -consdata->xoffset && cand < xub && xfixobjval > -b*b/(4.0*a) + c )
1343                   {
1344                      xfix = cand;
1345                      /* not needed: xfixobjval = -b*b/(4.0*a) + c; */
1346                   }
1347                }
1348             }
1349             assert(xfix != SCIP_INVALID); /*lint !e777*/
1350             assert(SCIPisInfinity(scip, -xlb) || SCIPisLE(scip, xlb, xfix));
1351             assert(SCIPisInfinity(scip,  xub) || SCIPisGE(scip, xub, xfix));
1352          }
1353          else
1354          {
1355             /* skip dual presolve for exponents != 2 and z in objective for now */
1356             return SCIP_OKAY;
1357          }
1358 
1359          /* compute fixing value for z */
1360          if( SCIPisInfinity(scip, xfix) )
1361          {
1362             if( consdata->zcoef > 0.0 )
1363             {
1364                assert(SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->z)));
1365                zfix = -SCIPinfinity(scip);
1366             }
1367             else
1368             {
1369                assert(SCIPisInfinity(scip,  SCIPvarGetUbGlobal(consdata->z)));
1370                zfix = SCIPinfinity(scip);
1371             }
1372          }
1373          else if( SCIPisInfinity(scip, -xfix) )
1374          {
1375             if( consdata->zcoef > 0.0 )
1376             {
1377                assert(SCIPisInfinity(scip,  SCIPvarGetUbGlobal(consdata->z)));
1378                zfix =  SCIPinfinity(scip);
1379             }
1380             else
1381             {
1382                assert(SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->z)));
1383                zfix = -SCIPinfinity(scip);
1384             }
1385          }
1386          else
1387          {
1388             SCIP_Real zlb;
1389             SCIP_Real zub;
1390 
1391             zlb = SCIPvarGetLbGlobal(consdata->z);
1392             zub = SCIPvarGetUbGlobal(consdata->z);
1393             zfix = consdata->rhs - SIGN(xfix + consdata->xoffset) * consdata->power(ABS(xfix + consdata->xoffset), consdata->exponent);
1394             zfix /= consdata->zcoef;
1395 
1396             /* project zfix into box, it should be at least very close */
1397             assert(SCIPisFeasLE(scip, zlb, zfix));
1398             assert(SCIPisFeasGE(scip, zub, zfix));
1399             zfix = MAX(zlb, MIN(zub, zfix));
1400          }
1401 
1402          /* fix variables according to x=xfix */
1403          SCIPdebugMsg(scip, "dual presolve fixes x=<%s>[%g,%g] to %g and z=<%s>[%g,%g] to %g in cons <%s>\n",
1404             SCIPvarGetName(consdata->x), xlb, xub, xfix,
1405             SCIPvarGetName(consdata->z), SCIPvarGetLbGlobal(consdata->z), SCIPvarGetUbGlobal(consdata->z), zfix,
1406             SCIPconsGetName(cons));
1407          SCIPdebugPrintCons(scip, cons, NULL);
1408 
1409          /* fix x */
1410          SCIP_CALL( SCIPfixVar(scip, consdata->x, xfix, cutoff, &fixed) );
1411          if( *cutoff )
1412             return SCIP_OKAY;
1413          if( fixed )
1414             ++*nfixedvars;
1415 
1416          /* fix z */
1417          SCIP_CALL( SCIPfixVar(scip, consdata->z, zfix, cutoff, &fixed) );
1418          if( *cutoff )
1419             return SCIP_OKAY;
1420          if( fixed )
1421             ++*nfixedvars;
1422 
1423          /* delete constraint */
1424          SCIP_CALL( SCIPdelCons(scip, cons) );
1425          ++*ndelconss;
1426       }
1427    }
1428 
1429    return SCIP_OKAY;
1430 }
1431 
1432 /** given a variable and an interval, tightens the local bounds of this variable to the given interval */
1433 static
tightenBounds(SCIP * scip,SCIP_VAR * var,SCIP_INTERVAL bounds,SCIP_Bool force,SCIP_CONS * cons,SCIP_RESULT * result,int * nchgbds,int * nfixedvars,int * naddconss)1434 SCIP_RETCODE tightenBounds(
1435    SCIP*                 scip,               /**< SCIP data structure */
1436    SCIP_VAR*             var,                /**< variable which bounds to tighten */
1437    SCIP_INTERVAL         bounds,             /**< new bounds */
1438    SCIP_Bool             force,              /**< force tightening even if below bound strengthening tolerance */
1439    SCIP_CONS*            cons,               /**< constraint that is propagated */
1440    SCIP_RESULT*          result,             /**< pointer to store the result of the propagation call */
1441    int*                  nchgbds,            /**< buffer where to add the number of changed bounds */
1442    int*                  nfixedvars,         /**< buffer where to add the number of fixed variables, can be equal to nchgbds */
1443    int*                  naddconss           /**< buffer where to add the number of added constraints, can be NULL if force is FALSE */
1444    )
1445 {
1446    SCIP_Bool infeas;
1447    SCIP_Bool tightened;
1448 
1449    assert(scip    != NULL);
1450    assert(var     != NULL);
1451    assert(cons    != NULL);
1452    assert(result  != NULL);
1453    assert(nchgbds != NULL);
1454    assert(nfixedvars != NULL);
1455 
1456    *result = SCIP_DIDNOTFIND;
1457 
1458    if( SCIPisInfinity(scip, SCIPintervalGetInf(bounds)) || SCIPisInfinity(scip, -SCIPintervalGetSup(bounds)) )
1459    {
1460       /* domain outside [-infty, +infty] -> declare as infeasible */
1461       *result = SCIP_CUTOFF;
1462       return SCIP_OKAY;
1463    }
1464 
1465    /* if variable is not multiaggregated (or aggregated to a multiaggregated), then try SCIPfixVar or SCIPtightenVarLb/Ub
1466     * otherwise, if bound tightening is forced, add a linear constraint
1467     * otherwise, forget about the bound tightening
1468     */
1469    if( SCIPvarIsActive(SCIPvarGetProbvar(var)) )
1470    {
1471       /* check if variable can be fixed */
1472       if( SCIPisEQ(scip, bounds.inf, bounds.sup) )
1473       {
1474          if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
1475          {
1476             /* if variable not fixed yet, then do so now */
1477             SCIP_Real fixval;
1478 
1479             if( bounds.inf != bounds.sup ) /*lint !e777*/
1480                fixval = (bounds.inf + bounds.sup) / 2.0;
1481             else
1482                fixval = bounds.inf;
1483             SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeas, &tightened) );
1484 
1485             if( infeas )
1486             {
1487                SCIPdebugMsg(scip, "found <%s> infeasible due to fixing variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
1488                *result = SCIP_CUTOFF;
1489                return SCIP_OKAY;
1490             }
1491             if( tightened )
1492             {
1493                SCIPdebugMsg(scip, "fixed variable <%s> in constraint <%s> to %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), SCIPvarGetLbLocal(var));
1494                ++*nfixedvars;
1495                *result = SCIP_REDUCEDDOM;
1496             }
1497          }
1498          else
1499          {
1500             /* only check if new fixing value is consistent with variable bounds, otherwise cutoff */
1501             if( SCIPisLT(scip, bounds.sup, SCIPvarGetUbLocal(var)) || SCIPisGT(scip, bounds.inf, SCIPvarGetLbLocal(var)) )
1502             {
1503                SCIPdebugMsg(scip, "found <%s> infeasible due to fixing fixed variable <%s>[%.15g,%.15g] to [%.15g,%.15g]\n",
1504                   SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bounds.inf, bounds.sup);
1505                *result = SCIP_CUTOFF;
1506                return SCIP_OKAY;
1507             }
1508          }
1509 
1510          return SCIP_OKAY;
1511       }
1512 
1513       /* check if lower bound can be tightened */
1514       if( SCIPintervalGetInf(bounds) > SCIPvarGetLbLocal(var) )
1515       {
1516          assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(bounds)));
1517          SCIP_CALL( SCIPtightenVarLb(scip, var, SCIPintervalGetInf(bounds), force, &infeas, &tightened) );
1518          if( infeas )
1519          {
1520             SCIPdebugMsg(scip, "found %s infeasible due to domain propagation for variable %s in constraint %s\n", SCIPconsGetName(cons), SCIPvarGetName(var), SCIPconsGetName(cons));
1521             *result = SCIP_CUTOFF;
1522             return SCIP_OKAY;
1523          }
1524          if( tightened )
1525          {
1526             SCIPdebugMsg(scip, "tightened lower bound of variable %s in constraint %s to %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), SCIPvarGetLbLocal(var));
1527             ++*nchgbds;
1528             *result = SCIP_REDUCEDDOM;
1529          }
1530       }
1531 
1532       /* check if upper bound can be tightened */
1533       if( SCIPintervalGetSup(bounds) < SCIPvarGetUbLocal(var) )
1534       {
1535          assert(!SCIPisInfinity(scip, SCIPintervalGetSup(bounds)));
1536          SCIP_CALL( SCIPtightenVarUb(scip, var, SCIPintervalGetSup(bounds), force, &infeas, &tightened) );
1537          if( infeas )
1538          {
1539             SCIPdebugMsg(scip, "found %s infeasible due to domain propagation for linear variable %s in constraint %s\n", SCIPconsGetName(cons), SCIPvarGetName(var), SCIPconsGetName(cons));
1540             *result = SCIP_CUTOFF;
1541             return SCIP_OKAY;
1542          }
1543          if( tightened )
1544          {
1545             SCIPdebugMsg(scip, "tightened upper bound of variable %s in constraint %s to %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), SCIPvarGetUbLocal(var));
1546             ++*nchgbds;
1547             *result = SCIP_REDUCEDDOM;
1548          }
1549       }
1550    }
1551    else if( force && (SCIPisLT(scip, SCIPvarGetLbLocal(var), bounds.inf) || SCIPisGT(scip, SCIPvarGetUbLocal(var), bounds.sup)) )
1552    {
1553       /* add a linear constraint bounds.inf <= x <= bounds.sup */
1554       SCIP_CONS* auxcons;
1555       SCIP_Bool local;
1556       SCIP_Real one;
1557 
1558       assert(naddconss != NULL);
1559 
1560       /* we add constraint as local constraint if we are during probing or if we are during solve and not at the root node */
1561       local = SCIPinProbing(scip) || (SCIPgetStage(scip) == SCIP_STAGE_SOLVING && (SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0));
1562 
1563       one = 1.0;
1564       SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, SCIPconsGetName(cons), 1, &var, &one, bounds.inf, bounds.sup,
1565             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
1566             SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), local,
1567             FALSE, FALSE, TRUE, FALSE) );
1568 
1569       if( local )
1570       {
1571          SCIP_CALL( SCIPaddConsLocal(scip, auxcons, NULL) );
1572       }
1573       else
1574       {
1575          SCIP_CALL( SCIPaddCons(scip, auxcons) );
1576       }
1577       SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
1578 
1579       ++*naddconss;
1580       *result = SCIP_CONSADDED;
1581    }
1582 
1583    return SCIP_OKAY;
1584 }
1585 
1586 /** computes bounds on z in a absolute power constraints for given bounds on x */
1587 static
computeBoundsZ(SCIP * scip,SCIP_CONS * cons,SCIP_INTERVAL xbnds,SCIP_INTERVAL * zbnds)1588 void computeBoundsZ(
1589    SCIP*                 scip,               /**< SCIP data structure */
1590    SCIP_CONS*            cons,               /**< constraint */
1591    SCIP_INTERVAL         xbnds,              /**< bounds on x that are to be propagated */
1592    SCIP_INTERVAL*        zbnds               /**< buffer to store corresponding bounds on z */
1593    )
1594 {
1595    SCIP_CONSDATA* consdata;
1596    SCIP_Real bnd;
1597    SCIP_Real x;
1598 
1599    assert(scip  != NULL);
1600    assert(cons  != NULL);
1601    assert(zbnds != NULL);
1602    assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), xbnds));
1603 
1604    consdata = SCIPconsGetData(cons);
1605    assert(consdata != NULL);
1606 
1607    SCIPintervalSetEntire(SCIPinfinity(scip), zbnds);
1608 
1609    /* apply zcoef*z <= rhs - signedpow(xbnds.inf + offset, n) */
1610    if( !SCIPisInfinity(scip,  consdata->rhs) && !SCIPisInfinity(scip, -xbnds.inf) )
1611    {
1612       x = xbnds.inf - PROPVARTOL + consdata->xoffset;
1613       bnd = consdata->rhs + PROPSIDETOL - SIGN(x) * consdata->power(REALABS(x), consdata->exponent);
1614 
1615       if( consdata->zcoef > 0.0 )
1616          zbnds->sup = bnd / consdata->zcoef;
1617       else
1618          zbnds->inf = bnd / consdata->zcoef;
1619    }
1620 
1621    /* apply zcoef*z >= lhs - signedpow(xbnds.sup + offset, n) */
1622    if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip,  xbnds.sup) )
1623    {
1624       x = xbnds.sup + PROPVARTOL + consdata->xoffset;
1625       bnd = consdata->lhs - PROPSIDETOL - SIGN(x) * consdata->power(REALABS(x), consdata->exponent);
1626 
1627       if( consdata->zcoef > 0.0 )
1628          zbnds->inf = bnd / consdata->zcoef;
1629       else
1630          zbnds->sup = bnd / consdata->zcoef;
1631    }
1632 
1633    SCIPdebugMsg(scip, "given x = [%.15g, %.15g], computed z = [%.15g, %.15g] via", xbnds.inf, xbnds.sup, zbnds->inf, zbnds->sup);
1634    SCIPdebugPrintCons(scip, cons, NULL);
1635 
1636    assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), *zbnds));
1637 }
1638 
1639 /** computes bounds on x in a absolute power constraints for given bounds on z */
1640 static
computeBoundsX(SCIP * scip,SCIP_CONS * cons,SCIP_INTERVAL zbnds,SCIP_INTERVAL * xbnds)1641 void computeBoundsX(
1642    SCIP*                 scip,               /**< SCIP data structure */
1643    SCIP_CONS*            cons,               /**< constraint */
1644    SCIP_INTERVAL         zbnds,              /**< bounds on x that are to be propagated */
1645    SCIP_INTERVAL*        xbnds               /**< buffer to store corresponding bounds on z */
1646    )
1647 {
1648    SCIP_CONSDATA* consdata;
1649    SCIP_Real bnd;
1650    SCIP_Real z;
1651 
1652    assert(scip  != NULL);
1653    assert(cons  != NULL);
1654    assert(xbnds != NULL);
1655    assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), zbnds));
1656 
1657    consdata = SCIPconsGetData(cons);
1658    assert(consdata != NULL);
1659 
1660    SCIPintervalSetEntire(SCIPinfinity(scip), xbnds);
1661 
1662    /* apply signedpow(x+offset, n) <= rhs - (zcoef * zbnds).inf */
1663    z = (consdata->zcoef > 0.0 ? zbnds.inf : zbnds.sup);
1664    if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, REALABS(z)) )
1665    {
1666       bnd = consdata->rhs + PROPSIDETOL - consdata->zcoef * z + REALABS(consdata->zcoef) * PROPVARTOL;
1667       if( consdata->exponent == 2.0 )
1668          bnd = SIGN(bnd) * sqrt(REALABS(bnd));
1669       else
1670          bnd = SIGN(bnd) * pow(REALABS(bnd), 1.0/consdata->exponent);
1671       xbnds->sup = bnd - consdata->xoffset;
1672    }
1673 
1674    /* apply signedpow(x+offset, n) >= lhs - (zcoef * zbnds).sup */
1675    z = (consdata->zcoef > 0.0 ? zbnds.sup : zbnds.inf);
1676    if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, REALABS(z)) )
1677    {
1678       bnd = consdata->lhs - PROPSIDETOL - consdata->zcoef * z - REALABS(consdata->zcoef) * PROPVARTOL;
1679       if( consdata->exponent == 2.0 )
1680          bnd = SIGN(bnd) * sqrt(REALABS(bnd));
1681       else
1682          bnd = SIGN(bnd) * pow(REALABS(bnd), 1.0/consdata->exponent);
1683       xbnds->inf = bnd - consdata->xoffset;
1684    }
1685 
1686    SCIPdebugMsg(scip, "given z = [%.15g, %.15g], computed x = [%.15g, %.15g] via", zbnds.inf, zbnds.sup, xbnds->inf, xbnds->sup);
1687    SCIPdebugPrintCons(scip, cons, NULL);
1688 
1689    assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), *xbnds));
1690 }
1691 
1692 /** checks if x or z is fixed and replaces them or deletes constraint */
1693 static
checkFixedVariables(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS * cons,int * ndelconss,int * nupgdconss,int * nchgbds,int * nfixedvars,SCIP_RESULT * result)1694 SCIP_RETCODE checkFixedVariables(
1695    SCIP*                 scip,               /**< SCIP data structure */
1696    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler for absolute power constraints */
1697    SCIP_CONS*            cons,               /**< constraint */
1698    int*                  ndelconss,          /**< counter for number of deleted constraints */
1699    int*                  nupgdconss,         /**< counter for number of upgraded constraints */
1700    int*                  nchgbds,            /**< counter for number of variable bound changes */
1701    int*                  nfixedvars,         /**< counter for number of variable fixations */
1702    SCIP_RESULT*          result              /**< to store result if we detect infeasibility or remove constraint */
1703    )
1704 {
1705    SCIP_CONSHDLRDATA* conshdlrdata;
1706    SCIP_CONSDATA* consdata;
1707    SCIP_Real scalar;
1708    SCIP_Real constant;
1709    SCIP_Real factor;
1710    SCIP_VAR* var;
1711 
1712    assert(scip != NULL);
1713    assert(cons != NULL);
1714    assert(ndelconss  != NULL);
1715    assert(nupgdconss != NULL);
1716    assert(nchgbds    != NULL);
1717    assert(nfixedvars != NULL);
1718 
1719    conshdlrdata = SCIPconshdlrGetData(conshdlr);
1720    assert(conshdlrdata != NULL);
1721 
1722    consdata = SCIPconsGetData(cons);
1723    assert(consdata != NULL);
1724 
1725    *result = SCIP_DIDNOTFIND;
1726 
1727    if( !SCIPvarIsActive(consdata->x) && SCIPvarGetStatus(consdata->x) != SCIP_VARSTATUS_MULTAGGR )
1728    {
1729       /* replace x variable */
1730 
1731       /* get relation x = scalar * var + constant */
1732       var = consdata->x;
1733       scalar = 1.0;
1734       constant = 0.0;
1735       SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1736 
1737       if( scalar == 0.0 )
1738       {
1739          SCIP_INTERVAL xbnds;
1740          SCIP_INTERVAL zbnds;
1741          int naddconss;
1742 
1743          naddconss = 0;
1744 
1745          /* x has been fixed to constant */
1746          assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->x), constant));
1747          assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(consdata->x), constant));
1748 
1749          /* compute corresponding bounds on z */
1750          SCIPintervalSet(&xbnds, constant);
1751          computeBoundsZ(scip, cons, xbnds, &zbnds);
1752 
1753          SCIPdebugMsg(scip, "in cons <%s>: x = <%s> fixed to %g -> tighten <%s> to [%g, %g]\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->x), constant, SCIPvarGetName(consdata->z), zbnds.inf, zbnds.sup);
1754 
1755          if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1756          {
1757             /* if sides are equal, then we should either fix z, or declare infeasibility */
1758             if( SCIPisFeasLT(scip, SCIPvarGetUbGlobal(consdata->z), zbnds.inf) || SCIPisFeasGT(scip, SCIPvarGetLbGlobal(consdata->z), zbnds.sup) )
1759             {
1760                SCIPdebugMsg(scip, "bounds inconsistent -> cutoff\n");
1761                *result = SCIP_CUTOFF;
1762                return SCIP_OKAY;
1763             }
1764             else
1765             {
1766                /* compute fixing value for z as value corresponding to fixing of x, projected onto bounds of z */
1767                SCIP_Real zfix;
1768 
1769                zfix = consdata->rhs - SIGN(constant + consdata->xoffset) * consdata->power(REALABS(constant + consdata->xoffset), consdata->exponent);
1770                zfix /= consdata->zcoef;
1771                assert(SCIPisLE(scip, zbnds.inf, zfix));
1772                assert(SCIPisGE(scip, zbnds.sup, zfix));
1773                zfix = MIN(SCIPvarGetUbGlobal(consdata->z), MAX(SCIPvarGetLbGlobal(consdata->z), zfix));  /*lint !e666*/
1774 
1775                zbnds.inf = zfix;
1776                zbnds.sup = zfix;
1777                SCIP_CALL( tightenBounds(scip, consdata->z, zbnds, TRUE, cons, result, nchgbds, nfixedvars, &naddconss) );
1778             }
1779          }
1780          else
1781          {
1782             /* tighten bounds on z accordingly */
1783             SCIP_CALL( tightenBounds(scip, consdata->z, zbnds, TRUE, cons, result, nchgbds, nfixedvars, &naddconss) );
1784          }
1785 
1786          /* delete constraint */
1787          SCIP_CALL( SCIPdelCons(scip, cons) );
1788 
1789          /* if tightenBounds added a constraint (because z was multiaggregated), then count this as constraint upgrade, otherwise as constraint deletion */
1790          if( naddconss > 0 )
1791             ++*nupgdconss;
1792          else
1793             ++*ndelconss;
1794 
1795          return SCIP_OKAY;
1796       }
1797 
1798       SCIPdebugMsg(scip, "in cons <%s>: x = <%s> replaced by %g*<%s> + %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->x), scalar, SCIPvarGetName(var), constant);
1799 
1800       /* constraint will be divided by scalar*pow(|scalar|,exponent-1), if scalar is not 1.0 */
1801       if( scalar == 1.0 )
1802          factor = 1.0;
1803       else if( scalar > 0.0 )
1804          factor =  consdata->power( scalar, consdata->exponent);
1805       else
1806          factor = -consdata->power(-scalar, consdata->exponent);
1807 
1808       /* aggregate only if this would not lead to a vanishing or infinite coefficient for z */
1809       if( !SCIPisZero(scip, consdata->zcoef / factor) && !SCIPisInfinity(scip, REALABS(consdata->zcoef / factor)) )
1810       {
1811          /* we drop here the events for both variables, because if x is replaced by a multiaggregated variable here, then we do not need to catch bound tightenings on z anymore */
1812          SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1813          SCIP_CALL( SCIPunlockVarCons(scip, consdata->x, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
1814 
1815          consdata->x = var;
1816          if( SCIPvarIsActive(consdata->x) )
1817          {
1818             SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->x) );
1819          }
1820 
1821          /* add constant to offset */
1822          consdata->xoffset += constant;
1823 
1824          /* divide constraint by factor */
1825          if( scalar == 1.0 ) ;
1826          else if( scalar > 0.0 )
1827          {
1828             if( !SCIPisInfinity(scip, -consdata->lhs) )
1829                consdata->lhs /= factor;
1830             if( !SCIPisInfinity(scip,  consdata->rhs) )
1831                consdata->rhs /= factor;
1832             consdata->zcoef /= factor;
1833             consdata->xoffset /= scalar;
1834          }
1835          else
1836          {
1837             SCIP_Real oldlhs;
1838 
1839             assert(scalar < 0.0);
1840             assert(factor < 0.0);
1841 
1842             oldlhs = consdata->lhs;
1843 
1844             if( !SCIPisInfinity(scip,  consdata->rhs) )
1845                consdata->lhs = consdata->rhs / factor;
1846             else
1847                consdata->lhs = -SCIPinfinity(scip);
1848             if( !SCIPisInfinity(scip, -oldlhs) )
1849                consdata->rhs = oldlhs / factor;
1850             else
1851                consdata->rhs = SCIPinfinity(scip);
1852             consdata->zcoef /= factor;
1853             consdata->xoffset /= scalar;
1854             /* since we flip both constraint sides and the sign of zcoef, the events catched for z remain the same, so update necessary there */
1855          }
1856 
1857          SCIP_CALL( SCIPlockVarCons(scip, consdata->x, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
1858          SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1859 
1860          SCIPdebugPrintCons(scip, cons, NULL);
1861 
1862          /* rerun constraint comparison */
1863          conshdlrdata->comparedpairwise = FALSE;
1864       }
1865       else
1866       {
1867          SCIPwarningMessage(scip, "Skip resolving aggregation of variable <%s> in abspower constraint <%s> to avoid zcoef = %g\n",
1868             SCIPvarGetName(consdata->x), SCIPconsGetName(cons), consdata->zcoef / factor);
1869       }
1870    }
1871 
1872    if( !SCIPvarIsActive(consdata->z) && SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR )
1873    {
1874       /* replace z variable */
1875 
1876       /* get relation z = scalar * var + constant */
1877       var = consdata->z;
1878       scalar = 1.0;
1879       constant = 0.0;
1880       SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1881 
1882       if( scalar == 0.0 )
1883       {
1884          SCIP_INTERVAL xbnds;
1885          SCIP_INTERVAL zbnds;
1886          int naddconss;
1887 
1888          naddconss = 0;
1889 
1890          /* z has been fixed to constant */
1891          assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->z), constant));
1892          assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(consdata->z), constant));
1893 
1894          /* compute corresponding bounds on x */
1895          SCIPintervalSet(&zbnds, constant);
1896          computeBoundsX(scip, cons, zbnds, &xbnds);
1897 
1898          SCIPdebugMsg(scip, "in cons <%s>: z = <%s> fixed to %g -> tighten <%s> to [%g, %g]\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->z), constant, SCIPvarGetName(consdata->x), xbnds.inf, xbnds.sup);
1899 
1900          if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1901          {
1902             /* if sides are equal, then we should either fix x, or declare infeasibility */
1903             if( SCIPisFeasLT(scip, SCIPvarGetUbGlobal(consdata->x), xbnds.inf) || SCIPisFeasGT(scip, SCIPvarGetLbGlobal(consdata->x), xbnds.sup) )
1904             {
1905                SCIPdebugMsg(scip, "bounds inconsistent -> cutoff\n");
1906                *result = SCIP_CUTOFF;
1907                return SCIP_OKAY;
1908             }
1909             else
1910             {
1911                /* compute fixing value for x as value corresponding to fixing of z, projected onto bounds of x */
1912                SCIP_Real xfix;
1913 
1914                xfix = consdata->rhs - consdata->zcoef * constant;
1915                if( consdata->exponent == 2.0 )
1916                   xfix = SIGN(xfix) * sqrt(REALABS(xfix)) - consdata->xoffset;
1917                else
1918                   xfix = SIGN(xfix) * pow(REALABS(xfix), 1.0/consdata->exponent) - consdata->xoffset;
1919                assert(SCIPisLE(scip, xbnds.inf, xfix));
1920                assert(SCIPisGE(scip, xbnds.sup, xfix));
1921                xfix = MIN(SCIPvarGetUbGlobal(consdata->x), MAX(SCIPvarGetLbGlobal(consdata->x), xfix));  /*lint !e666*/
1922 
1923                xbnds.inf = xfix;
1924                xbnds.sup = xfix;
1925                SCIP_CALL( tightenBounds(scip, consdata->x, xbnds, TRUE, cons, result, nchgbds, nfixedvars, &naddconss) );
1926             }
1927          }
1928          else
1929          {
1930             /* tighten bounds on x accordingly */
1931             SCIP_CALL( tightenBounds(scip, consdata->x, xbnds, TRUE, cons, result, nchgbds, nfixedvars, &naddconss) );
1932          }
1933 
1934          /* delete constraint */
1935          SCIP_CALL( SCIPdelCons(scip, cons) );
1936 
1937          /* if tightenBounds added a constraint (because x was multiaggregated), then count this as constraint upgrade, otherwise as constraint deletion */
1938          if( naddconss > 0 )
1939             ++*nupgdconss;
1940          else
1941             ++*ndelconss;
1942 
1943          return SCIP_OKAY;
1944       }
1945 
1946       SCIPdebugMsg(scip, "in cons <%s>: z = <%s> replaced by %g*<%s> + %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->z), scalar, SCIPvarGetName(var), constant);
1947 
1948       /* we drop here the events for both variables, because if z is replaced by a multiaggregated variable here, then we do not need to catch bound tightenings on x anymore */
1949       SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1950       if( consdata->zcoef > 0.0 )
1951          SCIP_CALL( SCIPunlockVarCons(scip, consdata->z, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip,  consdata->rhs)) );
1952       else
1953          SCIP_CALL( SCIPunlockVarCons(scip, consdata->z, cons, !SCIPisInfinity(scip,  consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
1954 
1955       consdata->z = var;
1956       if( SCIPvarIsActive(consdata->z) )
1957       {
1958          SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->z) );
1959       }
1960 
1961       /* substract constant from constraint sides */
1962       if( !SCIPisInfinity(scip, -consdata->lhs) )
1963          consdata->lhs -= consdata->zcoef * constant;
1964       if( !SCIPisInfinity(scip,  consdata->rhs) )
1965          consdata->rhs -= consdata->zcoef * constant;
1966 
1967       /* multiply zcoef by scalar */
1968       consdata->zcoef *= scalar;
1969 
1970       if( consdata->zcoef > 0.0 )
1971          SCIP_CALL( SCIPlockVarCons(scip, consdata->z, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip,  consdata->rhs)) );
1972       else
1973          SCIP_CALL( SCIPlockVarCons(scip, consdata->z, cons, !SCIPisInfinity(scip,  consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
1974       SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1975 
1976       /* rerun constraint comparison */
1977       conshdlrdata->comparedpairwise = FALSE;
1978    }
1979 
1980    assert(SCIPvarIsActive(consdata->z) || SCIPvarGetStatus(consdata->z) == SCIP_VARSTATUS_MULTAGGR);
1981 
1982    return SCIP_OKAY;
1983 }
1984 
1985 /** computes violation of a constraint */
1986 static
computeViolation(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Real * viol,SCIP_Bool * solviolbounds)1987 SCIP_RETCODE computeViolation(
1988    SCIP*                 scip,               /**< SCIP data structure */
1989    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1990    SCIP_CONS*            cons,               /**< constraint */
1991    SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1992    SCIP_Real*            viol,               /**< pointer to store absolute (unscaled) constraint violation */
1993    SCIP_Bool*            solviolbounds       /**< buffer to store whether the solution violates bounds on x by more than feastol */
1994    )
1995 {
1996    SCIP_CONSDATA* consdata;
1997    SCIP_Real val;
1998    SCIP_Real xval;
1999    SCIP_Real zval;
2000    SCIP_Real relviol;
2001 
2002    assert(scip != NULL);
2003    assert(conshdlr != NULL);
2004    assert(cons != NULL);
2005    assert(viol != NULL);
2006    assert(solviolbounds != NULL);
2007 
2008    consdata = SCIPconsGetData(cons);
2009    assert(consdata != NULL);
2010 
2011    *solviolbounds = FALSE;
2012    xval = SCIPgetSolVal(scip, sol, consdata->x);
2013    zval = SCIPgetSolVal(scip, sol, consdata->z);
2014 
2015    if( SCIPisInfinity(scip, REALABS(xval)) )
2016    {
2017       consdata->lhsviol = (SCIPisInfinity(scip, -consdata->lhs) ? 0.0 : SCIPinfinity(scip));
2018       consdata->rhsviol = (SCIPisInfinity(scip,  consdata->rhs) ? 0.0 : SCIPinfinity(scip));
2019 
2020       return SCIP_OKAY;
2021    }
2022 
2023    if( sol == NULL )
2024    {
2025       SCIP_Real lb;
2026       SCIP_Real ub;
2027 
2028       lb = SCIPvarGetLbLocal(consdata->x);
2029       ub = SCIPvarGetUbLocal(consdata->x);
2030 
2031       /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might be outside bounds */
2032       if( (!SCIPisInfinity(scip, -lb) && !SCIPisFeasGE(scip, xval, lb)) || (!SCIPisInfinity(scip, ub) && !SCIPisFeasLE(scip, xval, ub)) )
2033          *solviolbounds = TRUE;
2034       else
2035          xval = MAX(lb, MIN(ub, xval));  /* project x onto local box if just slightly outside (or even not outside) */
2036    }
2037 
2038    xval += consdata->xoffset;
2039 
2040    val  = SIGN(xval) * consdata->power(REALABS(xval), consdata->exponent);
2041    val += consdata->zcoef * zval;
2042 
2043    *viol = 0.0;
2044    relviol = 0.0;
2045    if( val < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
2046    {
2047       consdata->lhsviol = *viol = consdata->lhs - val;
2048       relviol = SCIPrelDiff(consdata->lhs, val);
2049    }
2050    else
2051       consdata->lhsviol = 0.0;
2052 
2053    if( val > consdata->rhs && !SCIPisInfinity(scip,  consdata->rhs) )
2054    {
2055       consdata->rhsviol = *viol = val - consdata->rhs;
2056       relviol = SCIPrelDiff(val, consdata->rhs);
2057    }
2058    else
2059       consdata->rhsviol = 0.0;
2060 
2061    if( sol != NULL )
2062       SCIPupdateSolConsViolation(scip, sol, *viol, relviol);
2063 
2064    return SCIP_OKAY;
2065 }
2066 
2067 /** computes violation of a set of constraints */
2068 static
computeViolations(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,SCIP_SOL * sol,SCIP_Bool * solviolbounds,SCIP_CONS ** maxviolcon)2069 SCIP_RETCODE computeViolations(
2070    SCIP*                 scip,               /**< SCIP data structure */
2071    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2072    SCIP_CONS**           conss,              /**< constraints */
2073    int                   nconss,             /**< number of constraints */
2074    SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
2075    SCIP_Bool*            solviolbounds,      /**< buffer to store whether the solution violates bounds on x by more than feastol */
2076    SCIP_CONS**           maxviolcon          /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
2077    )
2078 {
2079    SCIP_CONSDATA* consdata;
2080    SCIP_Real      viol;
2081    SCIP_Real      maxviol;
2082    SCIP_Bool      solviolbounds1;
2083    int            c;
2084 
2085    assert(scip != NULL);
2086    assert(conss != NULL || nconss == 0);
2087    assert(solviolbounds != NULL);
2088    assert(maxviolcon != NULL);
2089 
2090    *solviolbounds = FALSE;
2091    *maxviolcon = NULL;
2092 
2093    maxviol = 0.0;
2094 
2095    for( c = 0; c < nconss; ++c )
2096    {
2097       assert(conss != NULL);
2098       assert(conss[c] != NULL);
2099 
2100       SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &viol, &solviolbounds1) );
2101       *solviolbounds |= solviolbounds1;
2102 
2103       consdata = SCIPconsGetData(conss[c]);
2104       assert(consdata != NULL);
2105 
2106       viol = MAX(consdata->lhsviol, consdata->rhsviol);
2107       if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
2108       {
2109          maxviol = viol;
2110          *maxviolcon = conss[c];
2111       }
2112    }
2113 
2114    return SCIP_OKAY;
2115 }
2116 
2117 /** proposes branching point for constraint */
2118 static
proposeBranchingPoint(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,int preferzero,SCIP_Bool branchminconverror)2119 SCIP_Real proposeBranchingPoint(
2120    SCIP*                 scip,               /**< SCIP data structure */
2121    SCIP_CONS*            cons,               /**< constraint which variable to get branching point for */
2122    SCIP_SOL*             sol,                /**< solution to branch on (NULL for LP or pseudosol) */
2123    int                   preferzero,         /**< how much we prefer branching on -xoffset (0, 1, or 2) if sign is not fixed */
2124    SCIP_Bool             branchminconverror  /**< whether to minimize convexification error if sign is fixed */
2125    )
2126 {
2127    SCIP_CONSDATA* consdata;
2128    SCIP_VAR*      x;
2129    SCIP_Real      xref;
2130    SCIP_Real      zref;
2131    SCIP_Real      xlb;
2132    SCIP_Real      xub;
2133 
2134    assert(scip != NULL);
2135    assert(cons != NULL);
2136 
2137    consdata = SCIPconsGetData(cons);
2138    assert(consdata != NULL);
2139 
2140    x = consdata->x;
2141    xlb = SCIPvarGetLbLocal(x);
2142    xub = SCIPvarGetUbLocal(x);
2143 
2144    /* check if sign of x is not fixed yet */
2145    if( SCIPisLT(scip, xlb, -consdata->xoffset) && SCIPisGT(scip, xub, -consdata->xoffset) )
2146    {
2147       /* if preferzero is 0, just return SCIP_INVALID
2148        * if preferzero is 1, then propose -xoffset if branching on -xoffset would cut off solution in both child nodes, otherwise return SCIP_INVALID
2149        * if preferzero is >1, then always propose -xoffset
2150        */
2151       assert(preferzero >= 0);
2152 
2153       if( preferzero == 0 )
2154          return SCIP_INVALID;
2155 
2156       if( preferzero > 1 || SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
2157          return -consdata->xoffset;
2158 
2159       xlb += consdata->xoffset;
2160       xub += consdata->xoffset;
2161 
2162       xref = SCIPgetSolVal(scip, sol, x) + consdata->xoffset;
2163       zref = SCIPgetSolVal(scip, sol, consdata->z);
2164       if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
2165       {
2166          /* signpow(x,n,offset) + c*z <= 0 is violated
2167           *  if we are close to or right of -offset, then branching on -offset gives a convex function on the right branch, this is good
2168           *  otherwise if branching on -offset yields a violated secant cut in left branch, then current solution would be cutoff there, this is also still good
2169           */
2170          if( !SCIPisFeasNegative(scip, xref) || SCIPisFeasPositive(scip, -consdata->power(-xlb, consdata->exponent)*xref/xlb + consdata->zcoef * zref) )
2171             return -consdata->xoffset;
2172          return SCIP_INVALID;
2173       }
2174 
2175       assert(SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) );
2176       /* signpow(x,n) + c*z >= 0 is violated
2177        *  if we are close to or left of zero, then branching on 0.0 gives a concave function on the left branch, this is good
2178        *  otherwise if branching on 0.0 yields a violated secant cut in right branch, then current solution would be cutoff there, this is also still good
2179        */
2180       if( !SCIPisFeasPositive(scip, xref) || SCIPisFeasNegative(scip, -consdata->power(xub, consdata->exponent)*xref/xub + consdata->zcoef * zref) )
2181          return -consdata->xoffset;
2182       return SCIP_INVALID;
2183    }
2184 
2185    if( branchminconverror )
2186    {
2187       /* given x^n with xlb <= x <= xub, then the sum of the integrals between the function and its secant on the left and right branches are minimized
2188        * for branching on ( (ub^n - lb^n) / (n*(ub - lb)) ) ^ (1/(n-1))
2189        */
2190       if( SCIPisGE(scip, xlb, -consdata->xoffset) )
2191       {
2192          SCIP_Real ref;
2193          xlb = MAX(0.0, xlb + consdata->xoffset);
2194          xub = MAX(0.0, xub + consdata->xoffset);
2195 
2196          ref = (consdata->power(xub, consdata->exponent) - consdata->power(xlb, consdata->exponent)) / (consdata->exponent * (xub - xlb));
2197          ref = pow(ref, 1.0/(consdata->exponent-1.0));
2198          ref -= consdata->xoffset;
2199          assert(SCIPisGE(scip, ref, SCIPvarGetLbLocal(x)));
2200          assert(SCIPisLE(scip, ref, SCIPvarGetUbLocal(x)));
2201 
2202          return ref;
2203       }
2204       else
2205       {
2206          SCIP_Real ref;
2207 
2208          assert(SCIPisLE(scip, xub, -consdata->xoffset));
2209 
2210          xlb = MIN(0.0, xlb + consdata->xoffset);
2211          xub = MIN(0.0, xub + consdata->xoffset);
2212 
2213          ref = (consdata->power(-xlb, consdata->exponent) - consdata->power(-xub, consdata->exponent)) / (consdata->exponent * (-xlb + xub));
2214          ref = -pow(ref, 1.0/(consdata->exponent-1.0));
2215          ref -= consdata->xoffset;
2216          assert(SCIPisGE(scip, ref, SCIPvarGetLbLocal(x)));
2217          assert(SCIPisLE(scip, ref, SCIPvarGetUbLocal(x)));
2218 
2219          return ref;
2220       }
2221    }
2222 
2223    return SCIP_INVALID;
2224 }
2225 
2226 /** registers branching variable candidates
2227  * registers x for all violated absolute power constraints where x is not in convex region
2228  */
2229 static
registerBranchingCandidates(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,SCIP_SOL * sol,int * nnotify)2230 SCIP_RETCODE registerBranchingCandidates(
2231    SCIP*                 scip,               /**< SCIP data structure */
2232    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2233    SCIP_CONS**           conss,              /**< constraints to check */
2234    int                   nconss,             /**< number of constraints to check */
2235    SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
2236    int*                  nnotify             /**< counter for number of notifications performed */
2237    )
2238 {
2239    SCIP_CONSHDLRDATA* conshdlrdata;
2240    SCIP_CONSDATA*     consdata;
2241    SCIP_Bool          onlynonfixedsign;
2242    int                c;
2243 
2244    assert(scip != NULL);
2245    assert(conshdlr != NULL);
2246    assert(conss != NULL || nconss == 0);
2247 
2248    conshdlrdata = SCIPconshdlrGetData(conshdlr);
2249    assert(conshdlrdata != NULL);
2250 
2251    *nnotify = 0;
2252 
2253    onlynonfixedsign = conshdlrdata->preferzerobranch == 3;
2254 
2255    do
2256    {
2257       for( c = 0; c < nconss; ++c )
2258       {
2259          assert(conss[c] != NULL);  /*lint !e613*/
2260 
2261          /* skip constraints that have been marked to be removed by propagateCons() */
2262          if( !SCIPconsIsEnabled(conss[c]) ) /*lint !e613*/
2263             continue;
2264 
2265          consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
2266          assert(consdata != NULL);
2267 
2268          SCIPdebugMsg(scip, "cons <%s> violation: %g %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);  /*lint !e613*/
2269 
2270          /* skip variables which sign is already fixed, if we are only interested in variables with unfixed sign here */
2271          if( onlynonfixedsign &&
2272             (  !SCIPisLT(scip, SCIPvarGetLbLocal(consdata->x), -consdata->xoffset) ||
2273                !SCIPisGT(scip, SCIPvarGetUbLocal(consdata->x),  consdata->xoffset)) )
2274             continue;
2275 
2276          /* if the value of x lies in a concave range (i.e., where a secant approximation is used), then register x as branching variable */
2277          if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && (SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->x)) || SCIPgetSolVal(scip, sol, consdata->x) + consdata->xoffset <= -consdata->root * (SCIPvarGetLbLocal(consdata->x) + consdata->xoffset))) ||
2278             ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && (SCIPisInfinity(scip,  SCIPvarGetUbLocal(consdata->x)) || SCIPgetSolVal(scip, sol, consdata->x) + consdata->xoffset >= -consdata->root * (SCIPvarGetUbLocal(consdata->x) + consdata->xoffset))) )
2279          {
2280             /* domain propagation should have removed constraints with fixed x, at least for violated constraints */
2281             assert(!SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->x), SCIPvarGetUbLocal(consdata->x)));
2282 
2283             SCIPdebugMsg(scip, "register var <%s> in cons <%s> with violation %g %g\n", SCIPvarGetName(consdata->x), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);  /*lint !e613*/
2284             SCIP_CALL( SCIPaddExternBranchCand(scip, consdata->x, MAX(consdata->lhsviol, consdata->rhsviol), proposeBranchingPoint(scip, conss[c], sol, conshdlrdata->preferzerobranch, conshdlrdata->branchminconverror)) );  /*lint !e613*/
2285             ++*nnotify;
2286          }
2287       }
2288 
2289       if( onlynonfixedsign && *nnotify == 0 )
2290       {
2291          /* if we could not a variable in a violated constraint which sign is not already fixed, do another round where we consider all variables again */
2292          onlynonfixedsign = FALSE;
2293          continue;
2294       }
2295       break;
2296    }
2297    while( TRUE );  /*lint !e506 */
2298 
2299    return SCIP_OKAY;  /*lint !e438*/
2300 }
2301 
2302 /** registers a variable from a violated constraint as branching candidate that has a large absolute value in the relaxation */
2303 static
registerLargeRelaxValueVariableForBranching(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_SOL * sol,SCIP_VAR ** brvar)2304 SCIP_RETCODE registerLargeRelaxValueVariableForBranching(
2305    SCIP*                 scip,               /**< SCIP data structure */
2306    SCIP_CONS**           conss,              /**< constraints */
2307    int                   nconss,             /**< number of constraints */
2308    SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
2309    SCIP_VAR**            brvar               /**< buffer to store branching variable */
2310    )
2311 {
2312    SCIP_CONSDATA*      consdata;
2313    SCIP_Real           val;
2314    SCIP_Real           brvarval;
2315    int                 c;
2316 
2317    assert(scip  != NULL);
2318    assert(conss != NULL || nconss == 0);
2319 
2320    *brvar = NULL;
2321    brvarval = -1.0;
2322 
2323    for( c = 0; c < nconss; ++c )
2324    {
2325       assert(conss != NULL);
2326       consdata = SCIPconsGetData(conss[c]);
2327       assert(consdata != NULL);
2328 
2329       /* skip constraints that have been marked to be removed by propagateCons() */
2330       if( !SCIPconsIsEnabled(conss[c]) )
2331          continue;
2332 
2333       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
2334          continue;
2335 
2336       val = SCIPgetSolVal(scip, sol, consdata->x) + consdata->xoffset;
2337       if( REALABS(val) > brvarval )
2338       {
2339          brvarval = ABS(val);
2340          *brvar   = consdata->x;
2341       }
2342    }
2343 
2344    if( *brvar != NULL )
2345    {
2346       SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
2347    }
2348 
2349    return SCIP_OKAY;
2350 }
2351 
2352 /* try to fix almost fixed x variable in violated constraint */
2353 static
fixAlmostFixedX(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool * infeasible,SCIP_Bool * reduceddom)2354 SCIP_RETCODE fixAlmostFixedX(
2355    SCIP*                 scip,               /**< SCIP data structure */
2356    SCIP_CONS**           conss,              /**< constraints */
2357    int                   nconss,             /**< number of constraints */
2358    SCIP_Bool*            infeasible,         /**< buffer to store whether infeasibility was detected */
2359    SCIP_Bool*            reduceddom          /**< buffer to store whether some variable bound was tightened */
2360    )
2361 {
2362    SCIP_CONSDATA* consdata;
2363    SCIP_Real lb;
2364    SCIP_Real ub;
2365    SCIP_Bool tightened;
2366    int c;
2367 
2368    assert(scip != NULL);
2369    assert(conss != NULL);
2370    assert(infeasible != NULL);
2371    assert(reduceddom != NULL);
2372 
2373    *infeasible = FALSE;
2374    *reduceddom = FALSE;
2375 
2376    for( c = 0; c < nconss; ++c )
2377    {
2378       consdata = SCIPconsGetData(conss[c]);
2379       assert(consdata != NULL);
2380 
2381       /* if constraint not violated, then continue */
2382       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
2383          continue;
2384 
2385       lb = SCIPvarGetLbLocal(consdata->x);
2386       ub = SCIPvarGetUbLocal(consdata->x);
2387 
2388       /* if x not almost fixed, then continue */
2389       if( !SCIPisRelEQ(scip, lb, ub) )
2390          continue;
2391 
2392       /* if x fixed already, then continue */
2393       if( SCIPisEQ(scip, lb, ub) )
2394          continue;
2395 
2396       assert(!SCIPisInfinity(scip, -lb));
2397       assert(!SCIPisInfinity(scip,  ub));
2398 
2399       /* try to fix variable */
2400       SCIP_CALL( SCIPtightenVarLb(scip, consdata->x, (lb+ub)/2.0, TRUE, infeasible, &tightened) );
2401       if( *infeasible )
2402       {
2403          SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(consdata->x));
2404          return SCIP_OKAY;
2405       }
2406       if( tightened )
2407       {
2408          SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(consdata->x));
2409          *reduceddom = TRUE;
2410       }
2411 
2412       SCIP_CALL( SCIPtightenVarUb(scip, consdata->x, (lb+ub)/2.0, TRUE, infeasible, &tightened) );
2413       if( *infeasible )
2414       {
2415          SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(consdata->x));
2416          return SCIP_OKAY;
2417       }
2418       if( tightened )
2419       {
2420          SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(consdata->x));
2421          *reduceddom = TRUE;
2422       }
2423 
2424       /* stop as soon as one variable has been fixed to start another enfo round */
2425       if( *reduceddom )
2426          break;
2427    }
2428 
2429    return SCIP_OKAY;
2430 }
2431 
2432 /** resolves a propagation on the given variable by supplying the variables needed for applying the corresponding
2433  *  propagation rule (see propagateCons()):
2434  *  see cons_varbound
2435  */
2436 static
resolvePropagation(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * infervar,PROPRULE proprule,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx)2437 SCIP_RETCODE resolvePropagation(
2438    SCIP*                 scip,               /**< SCIP data structure */
2439    SCIP_CONS*            cons,               /**< constraint that inferred the bound change */
2440    SCIP_VAR*             infervar,           /**< variable that was deduced */
2441    PROPRULE              proprule,           /**< propagation rule that deduced the bound change */
2442    SCIP_BOUNDTYPE        boundtype,          /**< the type of the changed bound (lower or upper bound) */
2443    SCIP_BDCHGIDX*        bdchgidx            /**< bound change index (time stamp of bound change), or NULL for current time */
2444    )
2445 {
2446    SCIP_CONSDATA* consdata;
2447 
2448    assert(scip != NULL);
2449    assert(cons != NULL);
2450    assert(infervar != NULL);
2451 
2452    consdata = SCIPconsGetData(cons);
2453    assert(consdata != NULL);
2454    assert(consdata->zcoef != 0.0);
2455 
2456    switch( proprule )
2457    {
2458    case PROPRULE_1:
2459       /* lhs <= sign(x+offset)|x+offset|^n + c*z: left hand side and bounds on z -> lower bound on x */
2460       assert(infervar == consdata->x);
2461       assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2462       assert(!SCIPisInfinity(scip, -consdata->lhs));
2463       if( consdata->zcoef > 0.0 )
2464       {
2465          SCIP_CALL( SCIPaddConflictUb(scip, consdata->z, bdchgidx) );
2466       }
2467       else
2468       {
2469          SCIP_CALL( SCIPaddConflictLb(scip, consdata->z, bdchgidx) );
2470       }
2471       break;
2472 
2473    case PROPRULE_2:
2474       /* lhs <= sign(x+offset)|x+offset|^n + c*z: left hand side and upper bound on x -> bound on z */
2475       assert(infervar == consdata->z);
2476       assert(!SCIPisInfinity(scip, -consdata->lhs));
2477       SCIP_CALL( SCIPaddConflictUb(scip, consdata->x, bdchgidx) );
2478       break;
2479 
2480    case PROPRULE_3:
2481       /* sign(x+offset)|x+offset|^n + c*z <= rhs: right hand side and bounds on z -> upper bound on x */
2482       assert(infervar == consdata->x);
2483       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
2484       assert(!SCIPisInfinity(scip, consdata->rhs));
2485       if( consdata->zcoef > 0.0 )
2486       {
2487          SCIP_CALL( SCIPaddConflictLb(scip, consdata->z, bdchgidx) );
2488       }
2489       else
2490       {
2491          SCIP_CALL( SCIPaddConflictUb(scip, consdata->z, bdchgidx) );
2492       }
2493       break;
2494 
2495    case PROPRULE_4:
2496       /* sign(x+offset)|x+offset|^n + c*z <= rhs: right hand side and lower bound on x -> bound on z */
2497       assert(infervar == consdata->z);
2498       assert(!SCIPisInfinity(scip, consdata->rhs));
2499       SCIP_CALL( SCIPaddConflictLb(scip, consdata->x, bdchgidx) );
2500       break;
2501 
2502    case PROPRULE_INVALID:
2503    default:
2504       SCIPerrorMessage("invalid inference information %d in absolute power constraint <%s>\n", proprule, SCIPconsGetName(cons));
2505       return SCIP_INVALIDDATA;
2506    }
2507 
2508    return SCIP_OKAY;
2509 }
2510 
2511 /** analyze infeasibility */
2512 static
analyzeConflict(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * infervar,PROPRULE proprule,SCIP_BOUNDTYPE boundtype)2513 SCIP_RETCODE analyzeConflict(
2514    SCIP*                 scip,               /**< SCIP data structure */
2515    SCIP_CONS*            cons,               /**< variable bound constraint */
2516    SCIP_VAR*             infervar,           /**< variable that was deduced */
2517    PROPRULE              proprule,           /**< propagation rule that deduced the bound change */
2518    SCIP_BOUNDTYPE        boundtype           /**< the type of the changed bound (lower or upper bound) */
2519    )
2520 {
2521    /* conflict analysis can only be applied in solving stage and if it turned on */
2522    if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
2523       return SCIP_OKAY;
2524 
2525    /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2526    SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
2527 
2528    /* add the bound which got violated */
2529    if( boundtype == SCIP_BOUNDTYPE_LOWER )
2530    {
2531       SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
2532    }
2533    else
2534    {
2535       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
2536       SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
2537    }
2538 
2539    /* add the reason for the violated of the bound */
2540    SCIP_CALL( resolvePropagation(scip, cons, infervar, proprule, boundtype, NULL) );
2541 
2542    /* analyze the conflict */
2543    SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2544 
2545    return SCIP_OKAY;
2546 }
2547 
2548 /** propagation method for absolute power constraint
2549  * SCIPinferVarXbCons to allow for repropagation
2550  */
2551 static
propagateCons(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS * cons,SCIP_Bool canaddcons,SCIP_Bool * cutoff,int * nchgbds,int * naddconss)2552 SCIP_RETCODE propagateCons(
2553    SCIP*                 scip,               /**< SCIP data structure */
2554    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2555    SCIP_CONS*            cons,               /**< variable bound constraint */
2556    SCIP_Bool             canaddcons,         /**< are we allowed to add a linear constraint when enforcing bounds for a multiaggregated variable? */
2557    SCIP_Bool*            cutoff,             /**< pointer to store whether the node can be cut off */
2558    int*                  nchgbds,            /**< pointer to count number of bound changes */
2559    int*                  naddconss           /**< pointer to count number of added constraints */
2560    )
2561 {
2562    SCIP_CONSDATA* consdata;
2563    SCIP_Real xlb;
2564    SCIP_Real xub;
2565    SCIP_Real zlb;
2566    SCIP_Real zub;
2567    SCIP_Real newlb;
2568    SCIP_Real newub;
2569    SCIP_Bool tightened;
2570    SCIP_Bool tightenedround;
2571    SCIP_Real minact;
2572    SCIP_Real maxact;
2573 
2574    assert(conshdlr != NULL);
2575    assert(cutoff != NULL);
2576    assert(nchgbds != NULL);
2577    assert(naddconss != NULL);
2578 
2579    consdata = SCIPconsGetData(cons);
2580    assert(consdata != NULL);
2581 
2582    SCIPdebugMsg(scip, "propagating absolute power constraint <%s>\n", SCIPconsGetName(cons));
2583 
2584    *cutoff = FALSE;
2585 
2586    /* get current bounds of variables */
2587    xlb = SCIPvarGetLbLocal(consdata->x);
2588    xub = SCIPvarGetUbLocal(consdata->x);
2589    zlb = SCIPvarGetLbLocal(consdata->z);
2590    zub = SCIPvarGetUbLocal(consdata->z);
2591 
2592    /* if some bound is not tightened, tighten bounds of variables as long as possible */
2593    tightenedround = SCIPconsIsMarkedPropagate(cons);
2594    while( tightenedround )
2595    {
2596       tightenedround = FALSE;
2597 
2598       /* propagate left hand side inequality: lhs <= (x+offset)*|x+offset|^n + c*z */
2599       if( !SCIPisInfinity(scip, -consdata->lhs) )
2600       {
2601          assert(!*cutoff);
2602 
2603          /* propagate bounds on x (if not multiaggregated):
2604           *  (1) left hand side and bounds on z -> lower bound on x
2605           */
2606          if( SCIPvarIsActive(SCIPvarGetProbvar(consdata->x)) && (!SCIPisFeasEQ(scip, zlb, zub) || !SCIPisInfinity(scip, REALABS(zlb))) )
2607          {
2608             /* if z is fixed, first compute new lower bound on x without tolerances
2609              * if that is feasible, project new lower bound onto current bounds
2610              *   otherwise, recompute with tolerances and continue as usual
2611              * do this only if variable is not essentially fixed to value of infinity
2612              */
2613             if( SCIPisFeasEQ(scip, zlb, zub) && !SCIPisInfinity(scip, zub) )
2614             {
2615                assert(!SCIPisInfinity(scip, -zlb));
2616 
2617                newlb = consdata->lhs - consdata->zcoef * (consdata->zcoef > 0.0 ? zub : zlb);
2618 
2619                /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2620                if( consdata->exponent == 2.0 )
2621                   newlb = SIGN(newlb) * sqrt(ABS(newlb));
2622                else
2623                   newlb = SIGN(newlb) * pow(ABS(newlb), 1.0/consdata->exponent);
2624                newlb -= consdata->xoffset;
2625 
2626                if( SCIPisFeasGT(scip, newlb, xub) )
2627                {
2628                   /* if new lower bound for x would yield cutoff, recompute with tolerances */
2629                   newlb = consdata->lhs - PROPSIDETOL - consdata->zcoef * (consdata->zcoef > 0.0 ? (zub + PROPVARTOL) : (zlb - PROPVARTOL));
2630 
2631                   /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2632                   if( consdata->exponent == 2.0 )
2633                      newlb = SIGN(newlb) * sqrt(ABS(newlb));
2634                   else
2635                      newlb = SIGN(newlb) * pow(ABS(newlb), 1.0/consdata->exponent);
2636                   newlb -= consdata->xoffset;
2637                }
2638                else
2639                {
2640                   /* project new lower bound onto current bounds */
2641                   newlb = MIN(newlb, xub);
2642                }
2643             }
2644             else
2645             {
2646                if( consdata->zcoef > 0.0 )
2647                {
2648                   if( !SCIPisInfinity(scip, zub) )
2649                      newlb = consdata->lhs - PROPSIDETOL - consdata->zcoef * (zub + PROPVARTOL);
2650                   else
2651                      newlb = -SCIPinfinity(scip);
2652                }
2653                else
2654                {
2655                   if( !SCIPisInfinity(scip, -zlb) )
2656                      newlb = consdata->lhs - PROPSIDETOL - consdata->zcoef * (zlb - PROPVARTOL);
2657                   else
2658                      newlb = -SCIPinfinity(scip);
2659                }
2660 
2661                if( !SCIPisInfinity(scip, -newlb) )
2662                {
2663                   /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2664                   if( consdata->exponent == 2.0 )
2665                      newlb = SIGN(newlb) * sqrt(ABS(newlb));
2666                   else
2667                      newlb = SIGN(newlb) * pow(ABS(newlb), 1.0/consdata->exponent);
2668                   newlb -= consdata->xoffset;
2669                }
2670             }
2671 
2672             if( SCIPisInfinity(scip, newlb) )
2673             {
2674                /* we cannot fix a variable to +infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
2675                SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->x), xlb, xub, newlb, xub);
2676 
2677                *cutoff = TRUE;
2678 
2679                /* analyze infeasibility */
2680                SCIP_CALL( analyzeConflict(scip, cons, consdata->x, PROPRULE_1, SCIP_BOUNDTYPE_LOWER) );
2681                break;
2682             }
2683 
2684             if( !SCIPisInfinity(scip, -newlb) )
2685             {
2686                if( SCIPisLbBetter(scip, newlb, xlb, xub) )
2687                {
2688                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
2689                      SCIPvarGetName(consdata->x), xlb, xub, newlb, xub);
2690                   SCIP_CALL( SCIPinferVarLbCons(scip, consdata->x, newlb, cons, (int)PROPRULE_1, FALSE, cutoff, &tightened) );
2691 
2692                   if( *cutoff )
2693                   {
2694                      assert(SCIPisInfinity(scip, newlb) || SCIPisGT(scip, newlb, SCIPvarGetUbLocal(consdata->x)));
2695 
2696                      /* analyze infeasibility */
2697                      SCIP_CALL( analyzeConflict(scip, cons, consdata->x, PROPRULE_1, SCIP_BOUNDTYPE_LOWER) );
2698                      break;
2699                   }
2700 
2701                   if( tightened )
2702                   {
2703                      tightenedround = TRUE;
2704                      (*nchgbds)++;
2705                   }
2706                   xlb = SCIPvarGetLbLocal(consdata->x);
2707                }
2708             }
2709          }
2710 
2711          assert(!*cutoff);
2712 
2713          /* propagate bounds on z:
2714           *  (2) left hand side and upper bound on x -> bound on z
2715           */
2716          if( SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR && !SCIPisInfinity(scip, xub) ) /* cannot change bounds of multaggr vars */
2717          {
2718             SCIP_Real newbd;
2719 
2720             /* if x is fixed, first compute new bound on z without tolerances
2721              * if that is feasible, project new bound onto current bounds
2722              *   otherwise, recompute with tolerances and continue as usual
2723              */
2724             if( SCIPisFeasEQ(scip, xlb, xub) )
2725             {
2726                newbd  = xub + consdata->xoffset;
2727                newbd  = consdata->lhs - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2728                newbd /= consdata->zcoef;
2729 
2730                if( SCIPisInfinity(scip, newbd) )
2731                   newbd = SCIPinfinity(scip);
2732                else if( SCIPisInfinity(scip, -newbd) )
2733                   newbd = -SCIPinfinity(scip);
2734 
2735                if( (consdata->zcoef > 0.0 && SCIPisFeasGT(scip, newbd, zub)) || (consdata->zcoef < 0.0 && SCIPisFeasLT(scip, newbd, zlb)) )
2736                {
2737                   /* if infeasible, recompute with tolerances */
2738                   newbd  = xub + PROPVARTOL + consdata->xoffset;
2739                   newbd  = consdata->lhs - PROPSIDETOL - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2740                   newbd /= consdata->zcoef;
2741                }
2742                else
2743                {
2744                   /* project onto current bounds of z */
2745                   newbd = MIN(zub, MAX(zlb, newbd) );
2746                }
2747             }
2748             else
2749             {
2750                newbd  = xub + PROPVARTOL + consdata->xoffset;
2751                newbd  = consdata->lhs - PROPSIDETOL - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2752                newbd /= consdata->zcoef;
2753             }
2754 
2755             if( consdata->zcoef > 0.0 )
2756             {
2757                newlb = newbd;
2758 
2759                if( SCIPisInfinity(scip, newlb) )
2760                {
2761                   /* we cannot fix a variable to +infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
2762                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->z), zlb, zub, newlb, zub);
2763 
2764                   *cutoff = TRUE;
2765 
2766                   /* analyze infeasibility */
2767                   SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_2, SCIP_BOUNDTYPE_LOWER) );
2768                   break;
2769                }
2770 
2771                if( SCIPisLbBetter(scip, newlb, zlb, zub) )
2772                {
2773                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
2774                      SCIPvarGetName(consdata->z), zlb, zub, newlb, zub);
2775                   SCIP_CALL( SCIPinferVarLbCons(scip, consdata->z, newlb, cons, (int)PROPRULE_2, FALSE, cutoff, &tightened) );
2776 
2777                   if( *cutoff )
2778                   {
2779                      assert(SCIPisInfinity(scip, newlb) || SCIPisGT(scip, newlb, SCIPvarGetUbLocal(consdata->z)));
2780 
2781                      /* analyze infeasibility */
2782                      SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_2, SCIP_BOUNDTYPE_LOWER) );
2783                      break;
2784                   }
2785 
2786                   if( tightened )
2787                   {
2788                      tightenedround = TRUE;
2789                      (*nchgbds)++;
2790                   }
2791                   zlb = SCIPvarGetLbLocal(consdata->z);
2792                }
2793             }
2794             else
2795             {
2796                newub = newbd;
2797 
2798                if( SCIPisInfinity(scip, -newub) )
2799                {
2800                   /* we cannot fix a variable to -infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
2801                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->z), zlb, zub, zlb, newub);
2802 
2803                   *cutoff = TRUE;
2804 
2805                   /* analyze infeasibility */
2806                   SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_2, SCIP_BOUNDTYPE_UPPER) );
2807                   break;
2808                }
2809 
2810                if( SCIPisUbBetter(scip, newub, zlb, zub) )
2811                {
2812                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
2813                      SCIPvarGetName(consdata->z), zlb, zub, zlb, newub);
2814                   SCIP_CALL( SCIPinferVarUbCons(scip, consdata->z, newub, cons, (int)PROPRULE_2, FALSE, cutoff, &tightened) );
2815 
2816                   if( *cutoff )
2817                   {
2818                      assert(SCIPisInfinity(scip, -newub) || SCIPisLT(scip, newub, SCIPvarGetLbLocal(consdata->z)));
2819 
2820                      /* analyze infeasibility */
2821                      SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_2, SCIP_BOUNDTYPE_UPPER) );
2822                      break;
2823                   }
2824 
2825                   if( tightened )
2826                   {
2827                      tightenedround = TRUE;
2828                      (*nchgbds)++;
2829                   }
2830                   zub = SCIPvarGetUbLocal(consdata->z);
2831                }
2832             }
2833          }
2834       }
2835 
2836       assert(!*cutoff);
2837 
2838       /* propagate right hand side inequality: sign(x+offset)|x+offset|^n + c*z <= rhs */
2839       if( !SCIPisInfinity(scip, consdata->rhs) )
2840       {
2841          /* propagate bounds on x:
2842           *  (3) right hand side and bounds on z -> upper bound on x
2843           */
2844          if( SCIPvarIsActive(SCIPvarGetProbvar(consdata->x)) && (!SCIPisFeasEQ(scip, zlb, zub) || !SCIPisInfinity(scip, REALABS(zlb))) ) /* cannot change bounds of multaggr or fixed vars */
2845          {
2846             /* if z is fixed, first compute new upper bound on x without tolerances
2847              * if that is feasible, project new upper bound onto current bounds
2848              *   otherwise, recompute with tolerances and continue as usual
2849              * do this only if variable is not essentially fixed to value of infinity
2850              */
2851             if( SCIPisFeasEQ(scip, zlb, zub) && !SCIPisInfinity(scip, zub) )
2852             {
2853                assert(!SCIPisInfinity(scip, -zlb));
2854 
2855                newub = consdata->rhs - consdata->zcoef * (consdata->zcoef > 0.0 ? zlb : zub);
2856 
2857                /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2858                if( consdata->exponent == 2.0 )
2859                   newub = SIGN(newub) * sqrt(ABS(newub));
2860                else
2861                   newub = SIGN(newub) * pow(ABS(newub), 1.0/consdata->exponent);
2862                newub -= consdata->xoffset;
2863 
2864                if( SCIPisFeasLT(scip, newub, xlb) )
2865                {
2866                   /* if new lower bound for x would yield cutoff, recompute with tolerances */
2867                   newub = consdata->rhs + PROPSIDETOL - consdata->zcoef * (consdata->zcoef > 0.0 ? (zlb - PROPVARTOL) : (zub + PROPVARTOL));
2868 
2869                   /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2870                   if( consdata->exponent == 2.0 )
2871                      newub = SIGN(newub) * sqrt(ABS(newub));
2872                   else
2873                      newub = SIGN(newub) * pow(ABS(newub), 1.0/consdata->exponent);
2874                   newub -= consdata->xoffset;
2875                }
2876                else
2877                {
2878                   /* project new upper bound onto current bounds */
2879                   newub = MAX(newub, xlb);
2880                }
2881             }
2882             else
2883             {
2884                if( consdata->zcoef > 0.0 )
2885                {
2886                   if( !SCIPisInfinity(scip, -zlb) )
2887                      newub = consdata->rhs + PROPSIDETOL - consdata->zcoef * (zlb - PROPVARTOL);
2888                   else
2889                      newub = SCIPinfinity(scip);
2890                }
2891                else
2892                {
2893                   if( !SCIPisInfinity(scip, zub) )
2894                      newub = consdata->rhs + PROPSIDETOL - consdata->zcoef * (zub + PROPVARTOL);
2895                   else
2896                      newub = SCIPinfinity(scip);
2897                }
2898                if( !SCIPisInfinity(scip, newub) )
2899                {
2900                   /* invert sign(x+offset)|x+offset|^(n-1) = y -> x = sign(y)|y|^(1/n) - offset */
2901                   if( consdata->exponent == 2.0 )
2902                      newub = SIGN(newub) * sqrt(ABS(newub));
2903                   else
2904                      newub = SIGN(newub) * pow(ABS(newub), 1.0/consdata->exponent);
2905                   newub -= consdata->xoffset;
2906                }
2907             }
2908 
2909             if( SCIPisInfinity(scip, -newub) )
2910             {
2911                /* we cannot fix a variable to -infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
2912                SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->x), xlb, xub, xlb, newub);
2913 
2914                *cutoff = TRUE;
2915 
2916                /* analyze infeasibility */
2917                SCIP_CALL( analyzeConflict(scip, cons, consdata->x, PROPRULE_3, SCIP_BOUNDTYPE_UPPER) );
2918                break;
2919             }
2920 
2921             if( !SCIPisInfinity(scip, newub) )
2922             {
2923                if( SCIPisUbBetter(scip, newub, xlb, xub) )
2924                {
2925                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
2926                      SCIPvarGetName(consdata->x), xlb, xub, xlb, newub);
2927                   SCIP_CALL( SCIPinferVarUbCons(scip, consdata->x, newub, cons, (int)PROPRULE_3, FALSE, cutoff, &tightened) );
2928 
2929                   if( *cutoff )
2930                   {
2931                      assert(SCIPisInfinity(scip, -newub) || SCIPisLT(scip, newub, SCIPvarGetLbLocal(consdata->x)));
2932 
2933                      /* analyze infeasibility */
2934                      SCIP_CALL( analyzeConflict(scip, cons, consdata->x, PROPRULE_3, SCIP_BOUNDTYPE_UPPER) );
2935                      break;
2936                   }
2937 
2938                   if( tightened )
2939                   {
2940                      tightenedround = TRUE;
2941                      (*nchgbds)++;
2942                   }
2943                   xub = SCIPvarGetUbLocal(consdata->x);
2944                }
2945             }
2946          }
2947 
2948          assert(!*cutoff);
2949 
2950          /* propagate bounds on z:
2951           *  (4) right hand side and lower bound on x -> bound on z
2952           */
2953          if( SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR && !SCIPisInfinity(scip, -xlb) ) /* cannot change bounds of multaggr vars */
2954          {
2955             SCIP_Real newbd;
2956 
2957             /* if x is fixed, first compute new bound on z without tolerances
2958              * if that is feasible, project new bound onto current bounds
2959              *   otherwise, recompute with tolerances and continue as usual
2960              */
2961             if( SCIPisFeasEQ(scip, xlb, xub) )
2962             {
2963                newbd  = xlb + consdata->xoffset;
2964                newbd  = consdata->rhs - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2965                newbd /= consdata->zcoef;
2966 
2967                if( SCIPisInfinity(scip, newbd) )
2968                   newbd = SCIPinfinity(scip);
2969                else if( SCIPisInfinity(scip, -newbd) )
2970                   newbd = -SCIPinfinity(scip);
2971 
2972                if( (consdata->zcoef > 0.0 && SCIPisFeasLT(scip, newbd, zlb)) || (consdata->zcoef < 0.0 && SCIPisFeasGT(scip, newbd, zub)) )
2973                {
2974                   /* if infeasible, recompute with tolerances */
2975                   newbd  = xlb - PROPVARTOL + consdata->xoffset;
2976                   newbd  = consdata->rhs + PROPSIDETOL - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2977                   newbd /= consdata->zcoef;
2978                }
2979                else
2980                {
2981                   /* project onto current bounds of z */
2982                   newbd = MIN(zub, MAX(zlb, newbd) );
2983                }
2984             }
2985             else
2986             {
2987                newbd  = xlb - PROPVARTOL + consdata->xoffset;
2988                newbd  = consdata->rhs + PROPSIDETOL - SIGN(newbd) * consdata->power(REALABS(newbd), consdata->exponent);
2989                newbd /= consdata->zcoef;
2990             }
2991 
2992             if( consdata->zcoef > 0.0 )
2993             {
2994                newub = newbd;
2995 
2996                if( SCIPisInfinity(scip, -newub) )
2997                {
2998                   /* we cannot fix a variable to -infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
2999                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->z), zlb, zub, zlb, newub);
3000 
3001                   *cutoff = TRUE;
3002 
3003                   /* analyze infeasibility */
3004                   SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_4, SCIP_BOUNDTYPE_UPPER) );
3005                   break;
3006                }
3007 
3008                if( SCIPisUbBetter(scip, newub, zlb, zub) )
3009                {
3010                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
3011                      SCIPvarGetName(consdata->z), zlb, zub, zlb, newub);
3012                   SCIP_CALL( SCIPinferVarUbCons(scip, consdata->z, newub, cons, (int)PROPRULE_4, FALSE, cutoff, &tightened) );
3013 
3014                   if( *cutoff )
3015                   {
3016                      assert(SCIPisInfinity(scip, -newub) || SCIPisLT(scip, newub, SCIPvarGetLbLocal(consdata->z)));
3017 
3018                      /* analyze infeasibility */
3019                      SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_4, SCIP_BOUNDTYPE_UPPER) );
3020                      break;
3021                   }
3022 
3023                   if( tightened )
3024                   {
3025                      tightenedround = TRUE;
3026                      (*nchgbds)++;
3027                   }
3028                   zub = SCIPvarGetUbLocal(consdata->z);
3029                }
3030             }
3031             else
3032             {
3033                newlb = newbd;
3034 
3035                if( SCIPisInfinity(scip, newlb) )
3036                {
3037                   /* we cannot fix a variable to +infinity, so let's report cutoff (there is no solution within SCIPs limitations to infinity) */
3038                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g] -> cutoff\n", SCIPvarGetName(consdata->z), zlb, zub, newlb, zub);
3039 
3040                   *cutoff = TRUE;
3041 
3042                   /* analyze infeasibility */
3043                   SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_4, SCIP_BOUNDTYPE_LOWER) );
3044                   break;
3045                }
3046 
3047                if( SCIPisLbBetter(scip, newlb, zlb, zub) )
3048                {
3049                   SCIPdebugMsg(scip, " -> tighten <%s>[%.15g,%.15g] -> [%.15g,%.15g]\n",
3050                      SCIPvarGetName(consdata->z), zlb, zub, newlb, zub);
3051                   SCIP_CALL( SCIPinferVarLbCons(scip, consdata->z, newlb, cons, (int)PROPRULE_4, FALSE, cutoff, &tightened) );
3052 
3053                   if( *cutoff )
3054                   {
3055                      assert(SCIPisInfinity(scip, newlb) || SCIPisGT(scip, newlb, SCIPvarGetUbLocal(consdata->z)));
3056 
3057                      /* analyze infeasibility */
3058                      SCIP_CALL( analyzeConflict(scip, cons, consdata->z, PROPRULE_4, SCIP_BOUNDTYPE_LOWER) );
3059                      break;
3060                   }
3061 
3062                   if( tightened )
3063                   {
3064                      tightenedround = TRUE;
3065                      (*nchgbds)++;
3066                   }
3067                   zlb = SCIPvarGetLbLocal(consdata->z);
3068                }
3069             }
3070          }
3071       }
3072 
3073       assert(!*cutoff);
3074    }
3075 
3076    /* mark the constraint propagated */
3077    SCIP_CALL( SCIPunmarkConsPropagate(scip, cons) );
3078 
3079    if( *cutoff )
3080       return SCIP_OKAY;
3081 
3082    /* check for redundancy */
3083    if( !SCIPisInfinity(scip, -xlb) && !SCIPisInfinity(scip, consdata->zcoef > 0.0 ? -zlb :  zub) )
3084       minact = SIGN(xlb + consdata->xoffset) * consdata->power(REALABS(xlb + consdata->xoffset), consdata->exponent) + consdata->zcoef * (consdata->zcoef > 0.0 ? zlb : zub);
3085    else
3086       minact = -SCIPinfinity(scip);
3087 
3088    if( !SCIPisInfinity(scip,  xub) && !SCIPisInfinity(scip, consdata->zcoef > 0.0 ?  zub : -zlb) )
3089       maxact = SIGN(xub + consdata->xoffset) * consdata->power(REALABS(xub + consdata->xoffset), consdata->exponent) + consdata->zcoef * (consdata->zcoef > 0.0 ? zub : zlb);
3090    else
3091       maxact = SCIPinfinity(scip);
3092 
3093    if( (SCIPisInfinity(scip, -consdata->lhs) || SCIPisGE(scip, minact, consdata->lhs)) &&
3094        (SCIPisInfinity(scip,  consdata->rhs) || SCIPisLE(scip, maxact, consdata->rhs)) )
3095    {
3096       SCIPdebugMsg(scip, "absolute power constraint <%s> is redundant: <%s>[%.15g,%.15g], <%s>[%.15g,%.15g]\n",
3097          SCIPconsGetName(cons),
3098          SCIPvarGetName(consdata->x), SCIPvarGetLbLocal(consdata->x), SCIPvarGetUbLocal(consdata->x),
3099          SCIPvarGetName(consdata->z), SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z));
3100 
3101       SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3102 
3103       return SCIP_OKAY;
3104    }
3105 
3106    /* delete constraint if x has been fixed */
3107    if( SCIPisRelEQ(scip, xlb, xub) && (SCIPvarIsActive(consdata->z) || canaddcons) )
3108    {
3109       SCIP_RESULT tightenresult;
3110       SCIP_INTERVAL xbnds;
3111       SCIP_INTERVAL zbnds;
3112 
3113       SCIPdebugMsg(scip, "x-variable in constraint <%s> is fixed: x = <%s>[%.15g,%.15g], z = <%s>[%.15g,%.15g]\n",
3114          SCIPconsGetName(cons), SCIPvarGetName(consdata->x), xlb, xub, SCIPvarGetName(consdata->z), zlb, zub);
3115 
3116       SCIPintervalSetBounds(&xbnds, MIN(xlb, xub), MAX(xlb, xub));
3117       computeBoundsZ(scip, cons, xbnds, &zbnds);
3118 
3119       /* in difference to the loop above, here we enforce a possible bound tightening on z, and may add a linear cons if z is multiaggregated */
3120       SCIP_CALL( tightenBounds(scip, consdata->z, zbnds, TRUE, cons, &tightenresult, nchgbds, nchgbds, naddconss) );
3121       if( tightenresult == SCIP_CUTOFF )
3122          *cutoff = TRUE;
3123 
3124       SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3125 
3126       return SCIP_OKAY;
3127    }
3128 
3129    /* delete constraint if z has been fixed */
3130    if( SCIPisRelEQ(scip, zlb, zub) && (SCIPvarIsActive(consdata->x) || canaddcons) )
3131    {
3132       SCIP_RESULT tightenresult;
3133       SCIP_INTERVAL xbnds;
3134       SCIP_INTERVAL zbnds;
3135 
3136       SCIPdebugMsg(scip, "z-variable in constraint <%s> is fixed: x = <%s>[%.15g,%.15g], z = <%s>[%.15g,%.15g]\n",
3137          SCIPconsGetName(cons), SCIPvarGetName(consdata->x), xlb, xub, SCIPvarGetName(consdata->z), zlb, zub);
3138 
3139       SCIPintervalSetBounds(&zbnds, MIN(zlb, zub), MAX(zlb, zub));
3140       computeBoundsX(scip, cons, zbnds, &xbnds);
3141 
3142       /* in difference to the loop above, here we enforce a possible bound tightening on x, and may add a linear cons if x is multiaggregated */
3143       SCIP_CALL( tightenBounds(scip, consdata->x, xbnds, TRUE, cons, &tightenresult, nchgbds, nchgbds, naddconss) );
3144       if( tightenresult == SCIP_CUTOFF )
3145          *cutoff = TRUE;
3146 
3147       SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3148 
3149       return SCIP_OKAY;
3150    }
3151 
3152    return SCIP_OKAY;
3153 }
3154 
3155 /** notifies SCIP about a variable bound lhs <= x + c*y <= rhs */
3156 static
addVarbound(SCIP * scip,SCIP_CONS * cons,SCIP_Bool addcons,SCIP_VAR * var,SCIP_VAR * vbdvar,SCIP_Real vbdcoef,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool * infeas,int * nbdchgs,int * naddconss)3157 SCIP_RETCODE addVarbound(
3158    SCIP*                 scip,               /**< SCIP data structure */
3159    SCIP_CONS*            cons,               /**< absolute power constraint this variable bound is derived form */
3160    SCIP_Bool             addcons,            /**< should the variable bound be added as constraint to SCIP? */
3161    SCIP_VAR*             var,                /**< variable x for which we want to add a variable bound */
3162    SCIP_VAR*             vbdvar,             /**< variable y which makes the bound a variable bound */
3163    SCIP_Real             vbdcoef,            /**< coefficient c of bounding variable vbdvar */
3164    SCIP_Real             lhs,                /**< left  hand side of varbound constraint */
3165    SCIP_Real             rhs,                /**< right hand side of varbound constraint */
3166    SCIP_Bool*            infeas,             /**< pointer to store whether an infeasibility was detected */
3167    int*                  nbdchgs,            /**< pointer where to add number of performed bound changes */
3168    int*                  naddconss           /**< pointer where to add number of added constraints */
3169    )
3170 {
3171    int nbdchgs_local;
3172 
3173    assert(scip != NULL);
3174    assert(cons != NULL);
3175    assert(var  != NULL);
3176    assert(vbdvar != NULL);
3177    assert(!SCIPisZero(scip, vbdcoef));
3178    assert(!SCIPisInfinity(scip, ABS(vbdcoef)));
3179    assert(infeas != NULL);
3180 
3181    *infeas = FALSE;
3182 
3183    /* make sure vbdvar is active, so we can search for it in SCIPvarGetVxbdVars() */
3184    if( !SCIPvarIsActive(vbdvar) )
3185    {
3186       SCIP_Real constant;
3187 
3188       constant = 0.0;
3189       SCIP_CALL( SCIPgetProbvarSum(scip, &vbdvar, &vbdcoef, &constant) );
3190       if( !SCIPvarIsActive(vbdvar) || (vbdcoef == 0.0) )
3191          return SCIP_OKAY;
3192 
3193       if( !SCIPisInfinity(scip, -lhs) )
3194          lhs -= constant;
3195       if( !SCIPisInfinity(scip,  rhs) )
3196          rhs -= constant;
3197    }
3198 
3199    /* vbdvar should be a non-fixed binary variable */
3200    assert(SCIPvarIsIntegral(vbdvar));
3201    assert(SCIPisZero(scip, SCIPvarGetLbGlobal(vbdvar)));
3202    assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(vbdvar), 1.0));
3203 
3204    SCIPdebugMsg(scip, "-> %g <= <%s> + %g*<%s> <= %g\n", lhs, SCIPvarGetName(var), vbdcoef, SCIPvarGetName(vbdvar), rhs);
3205 
3206    if( addcons && SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
3207    {
3208       SCIP_CONS* vbdcons;
3209       char name[SCIP_MAXSTRLEN];
3210 
3211       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_vbnd", SCIPconsGetName(cons));
3212 
3213       SCIP_CALL( SCIPcreateConsVarbound(scip, &vbdcons, name, var, vbdvar, vbdcoef, lhs, rhs,
3214          FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3215       SCIP_CALL( SCIPaddCons(scip, vbdcons) );
3216       SCIP_CALL( SCIPreleaseCons(scip, &vbdcons) );
3217 
3218       ++*naddconss;
3219 
3220       return SCIP_OKAY;
3221    }
3222 
3223    if( !SCIPisInfinity(scip, -lhs) )
3224    {
3225       SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvar, -vbdcoef, lhs, infeas, &nbdchgs_local) );
3226       if( *infeas )
3227          return SCIP_OKAY;
3228       *nbdchgs += nbdchgs_local;
3229    }
3230 
3231    if( !SCIPisInfinity(scip,  rhs) )
3232    {
3233       SCIP_CALL( SCIPaddVarVub(scip, var, vbdvar, -vbdcoef, rhs, infeas, &nbdchgs_local) );
3234       if( *infeas )
3235          return SCIP_OKAY;
3236       *nbdchgs += nbdchgs_local;
3237    }
3238 
3239    return SCIP_OKAY;
3240 }
3241 
3242 /** propagates varbounds of variables
3243  * Let f(x) = sign(x+offset)|x+offset|^n,  f^{-1}(y) = sign(y)|y|^(1/n) - offset.
3244  * Thus, constraint is lhs <= f(x) + c*z <= rhs.
3245  *
3246  * Given a variable bound constraint x <= a*y + b with y a binary variable, one obtains
3247  * y = 0 -> f(x) <= f(b)   -> lhs <= f(b)   + c*z
3248  * y = 1 -> f(x) <= f(a+b) -> lhs <= f(a+b) + c*z
3249  * => lhs <= f(b) + y * (f(a+b)-f(b)) + c*z
3250  *
3251  * Given a variable bound constraint x >= a*y + b with y a binary variable, one obtains analogously
3252  * f(b) + y * (f(a+b)-f(b)) + c*z <= rhs
3253  *
3254  * Given a variable bound constraint c*z <= a*y + b with y a binary variable, one obtains
3255  * y = 0 -> lhs <= f(x) + b   -> x >= f^{-1}(lhs - b)
3256  * y = 1 -> lhs <= f(x) + a+b -> x >= f^{-1}(lhs - (a+b))
3257  * => x >= f^{-1}(lhs - b) + y * (f^{-1}(lhs - (a+b)) - f^{-1}(lhs - b))
3258  *
3259  * Given a variable bound constraint c*z >= a*y + b with y a binary variable, one obtains analogously
3260  *    x <= f^{-1}(rhs - b) + y * (f^{-1}(rhs - (a+b)) - f^{-1}(rhs - b))
3261  */
3262 static
propagateVarbounds(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS * cons,SCIP_Bool * infeas,int * nbdchgs,int * naddconss)3263 SCIP_RETCODE propagateVarbounds(
3264    SCIP*                 scip,               /**< SCIP data structure */
3265    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3266    SCIP_CONS*            cons,               /**< absolute power constraint */
3267    SCIP_Bool*            infeas,             /**< pointer to store whether an infeasibility was detected */
3268    int*                  nbdchgs,            /**< pointer where to add number of performed bound changes */
3269    int*                  naddconss           /**< pointer where to add number of added constraints */
3270    )
3271 {
3272    SCIP_CONSHDLRDATA* conshdlrdata;
3273    SCIP_CONSDATA* consdata;
3274    SCIP_VAR*      y;
3275    SCIP_Real      a;
3276    SCIP_Real      b;
3277    SCIP_Real      fb;
3278    SCIP_Real      fab;
3279    SCIP_Real      vbcoef;
3280    SCIP_Real      vbconst;
3281    int            i;
3282 
3283    assert(scip     != NULL);
3284    assert(conshdlr != NULL);
3285    assert(cons     != NULL);
3286    assert(infeas   != NULL);
3287    assert(nbdchgs  != NULL);
3288    assert(naddconss != NULL);
3289 
3290    *infeas =  FALSE;
3291 
3292    conshdlrdata = SCIPconshdlrGetData(conshdlr);
3293    assert(conshdlrdata != NULL);
3294 
3295    consdata = SCIPconsGetData(cons);
3296    assert(consdata != NULL);
3297    assert(consdata->z != NULL);
3298 
3299    /* don't do anything if it looks like we have numerical troubles */
3300    if( SCIPisZero(scip, consdata->zcoef) )
3301       return SCIP_OKAY;
3302 
3303    if( !SCIPisInfinity(scip, -consdata->lhs) )
3304    {
3305       /* propagate varbounds x <= a*y+b onto z
3306        *    lhs <= f(b) + y * (f(a+b)-f(b)) + c*z
3307        * -> c*z >= lhs-f(b) + y * (f(b)-f(a+b))
3308        */
3309       for( i = 0; i < SCIPvarGetNVubs(consdata->x); ++i )
3310       {
3311          y = SCIPvarGetVubVars(consdata->x)[i];
3312          a = SCIPvarGetVubCoefs(consdata->x)[i];
3313          b = SCIPvarGetVubConstants(consdata->x)[i];
3314 
3315          /* skip variable bound if y is not integer or its valid values are not {0,1}
3316           * @todo extend to arbitrary integer variables
3317           */
3318          if( !SCIPvarIsBinary(y) || SCIPvarGetLbGlobal(y) > 0.5 || SCIPvarGetUbGlobal(y) < 0.5 )
3319             continue;
3320 
3321          /* skip variable bound if coefficient is very small */
3322          if( SCIPisFeasZero(scip, consdata->power(a, consdata->exponent)) )
3323             continue;
3324 
3325          SCIPdebugMsg(scip, "propagate variable bound <%s> <= %g*<%s> + %g\n", SCIPvarGetName(consdata->x), a, SCIPvarGetName(y), b);
3326 
3327          fb  = SIGN(  b + consdata->xoffset) * consdata->power(  b + consdata->xoffset, consdata->exponent);  /* f(  b) = sign(  b) |  b|^n */
3328          fab = SIGN(a+b + consdata->xoffset) * consdata->power(a+b + consdata->xoffset, consdata->exponent);  /* f(a+b) = sign(a+b) |a+b|^n */
3329 
3330          vbcoef  = (fb - fab) / consdata->zcoef;
3331          vbconst = (consdata->lhs - fb) / consdata->zcoef;
3332 
3333          if( consdata->zcoef > 0.0 )
3334          {
3335             /* add varbound z >= (lhs-f(b))/c + y * (f(b)-f(a+b))/c */
3336             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->z, y, -vbcoef, vbconst,  SCIPinfinity(scip), infeas, nbdchgs, naddconss) );
3337          }
3338          else
3339          {
3340             /* add varbound z <= (lhs-f(b))/c + y * (f(b)-f(a+b))/c */
3341             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->z, y, -vbcoef, -SCIPinfinity(scip), vbconst, infeas, nbdchgs, naddconss) );
3342          }
3343          if( *infeas )
3344             return SCIP_OKAY;
3345       }
3346    }
3347 
3348    /* propagate varbounds x >= a*y+b onto z
3349     *    f(b) + y * (f(a+b)-f(b)) + c*z <= rhs
3350     * -> c*z <= rhs-f(b) + y * (f(b)-f(a+b))
3351     */
3352    if( !SCIPisInfinity(scip, consdata->rhs) )
3353    {
3354       for( i = 0; i < SCIPvarGetNVlbs(consdata->x); ++i )
3355       {
3356          y = SCIPvarGetVlbVars(consdata->x)[i];
3357          a = SCIPvarGetVlbCoefs(consdata->x)[i];
3358          b = SCIPvarGetVlbConstants(consdata->x)[i];
3359 
3360          /* skip variable bound if y is not integer or its valid values are not {0,1}
3361           * @todo extend to arbitrary integer variables
3362           */
3363          if( !SCIPvarIsBinary(y) || SCIPvarGetLbGlobal(y) > 0.5 || SCIPvarGetUbGlobal(y) < 0.5 )
3364             continue;
3365 
3366          /* skip variable bound if coefficient is very small */
3367          if( SCIPisFeasZero(scip, consdata->power(a, consdata->exponent)) )
3368             continue;
3369 
3370          SCIPdebugMsg(scip, "propagate variable bound <%s> >= %g*<%s> + %g\n", SCIPvarGetName(consdata->x), a, SCIPvarGetName(y), b);
3371 
3372          fb  = SIGN(  b + consdata->xoffset) * consdata->power(  b + consdata->xoffset, consdata->exponent);  /* f(  b) = sign(  b) |  b|^n */
3373          fab = SIGN(a+b + consdata->xoffset) * consdata->power(a+b + consdata->xoffset, consdata->exponent);  /* f(a+b) = sign(a+b) |a+b|^n */
3374 
3375          vbcoef  = (fb - fab) / consdata->zcoef;
3376          vbconst = (consdata->rhs - fb) / consdata->zcoef;
3377 
3378          if( consdata->zcoef > 0.0 )
3379          {
3380             /* add varbound z <= (rhs-f(b))/c + y * (f(b)-f(a+b))/c */
3381             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->z, y, -vbcoef, -SCIPinfinity(scip), vbconst, infeas, nbdchgs, naddconss) );
3382          }
3383          else
3384          {
3385             /* add varbound z >= (rhs-f(b))/c + y * (f(b)-f(a+b))/c */
3386             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->z, y, -vbcoef, vbconst,  SCIPinfinity(scip), infeas, nbdchgs, naddconss) );
3387          }
3388          if( *infeas )
3389             return SCIP_OKAY;
3390       }
3391    }
3392 
3393    /* propagate variable upper bounds on z onto x
3394     * c*z <= a*y+b -> x >= f^{-1}(lhs - b) + y * (f^{-1}(lhs - (a+b)) - f^{-1}(lhs - b))
3395     * c*z >= a*y+b -> x <= f^{-1}(rhs - b) + y * (f^{-1}(rhs - (a+b)) - f^{-1}(rhs - b))
3396     */
3397    if( (consdata->zcoef > 0.0 && !SCIPisInfinity(scip, -consdata->lhs)) ||
3398       ( consdata->zcoef < 0.0 && !SCIPisInfinity(scip,  consdata->rhs)) )
3399       for( i = 0; i < SCIPvarGetNVubs(consdata->z); ++i )
3400       {
3401          y = SCIPvarGetVubVars(consdata->z)[i];
3402          a = SCIPvarGetVubCoefs(consdata->z)[i] * consdata->zcoef;
3403          b = SCIPvarGetVubConstants(consdata->z)[i] * consdata->zcoef;
3404 
3405          SCIPdebugMsg(scip, "propagate variable bound %g*<%s> %c= %g*<%s> + %g\n", consdata->zcoef, SCIPvarGetName(consdata->z), consdata->zcoef > 0 ? '<' : '>', a, SCIPvarGetName(y), b);
3406 
3407          /* skip variable bound if y is not integer or its valid values are not {0,1}
3408           * @todo extend to arbitrary integer variables
3409           */
3410          if( !SCIPvarIsBinary(y) || SCIPvarGetLbGlobal(y) > 0.5 || SCIPvarGetUbGlobal(y) < 0.5 )
3411             continue;
3412 
3413          if( consdata->zcoef > 0.0 )
3414          {
3415             fb = consdata->lhs - b;
3416             fb = SIGN(fb) * pow(ABS(fb), 1.0/consdata->exponent);
3417             fab = consdata->lhs - (a+b);
3418             fab = SIGN(fab) * pow(ABS(fab), 1.0/consdata->exponent);
3419             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->x, y, fb - fab, fb - consdata->xoffset, SCIPinfinity(scip),  infeas, nbdchgs, naddconss) );
3420          }
3421          else
3422          {
3423             fb = consdata->rhs - b;
3424             fb = SIGN(fb) * pow(ABS(fb), 1.0/consdata->exponent);
3425             fab = consdata->rhs - (a+b);
3426             fab = SIGN(fab) * pow(ABS(fab), 1.0/consdata->exponent);
3427             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->x, y, fb - fab, -SCIPinfinity(scip), fb - consdata->xoffset, infeas, nbdchgs, naddconss) );
3428          }
3429          if( *infeas )
3430             return SCIP_OKAY;
3431       }
3432 
3433    /* propagate variable lower bounds on z onto x
3434     * c*z <= a*y+b -> x >= f^{-1}(lhs - b) + y * (f^{-1}(lhs - (a+b)) - f^{-1}(lhs - b))
3435     * c*z >= a*y+b -> x <= f^{-1}(rhs - b) + y * (f^{-1}(rhs - (a+b)) - f^{-1}(rhs - b))
3436     */
3437    if( (consdata->zcoef < 0.0 && !SCIPisInfinity(scip, -consdata->lhs)) ||
3438       ( consdata->zcoef > 0.0 && !SCIPisInfinity(scip,  consdata->rhs)) )
3439       for( i = 0; i < SCIPvarGetNVlbs(consdata->z); ++i )
3440       {
3441          y = SCIPvarGetVlbVars(consdata->z)[i];
3442          a = SCIPvarGetVlbCoefs(consdata->z)[i] * consdata->zcoef;
3443          b = SCIPvarGetVlbConstants(consdata->z)[i] * consdata->zcoef;
3444 
3445          SCIPdebugMsg(scip, "propagate variable bound %g*<%s> %c= %g*<%s> + %g\n", consdata->zcoef, SCIPvarGetName(consdata->z), consdata->zcoef > 0 ? '>' : '<', a, SCIPvarGetName(y), b);
3446 
3447          /* skip variable bound if y is not integer or its valid values are not {0,1}
3448           * @todo extend to arbitrary integer variables
3449           */
3450          if( !SCIPvarIsBinary(y) || SCIPvarGetLbGlobal(y) > 0.5 || SCIPvarGetUbGlobal(y) < 0.5 )
3451             continue;
3452 
3453          if( consdata->zcoef > 0.0 )
3454          {
3455             fb = consdata->rhs - b;
3456             fb = SIGN(fb) * pow(ABS(fb), 1.0/consdata->exponent);
3457             fab = consdata->rhs - (a+b);
3458             fab = SIGN(fab) * pow(ABS(fab), 1.0/consdata->exponent);
3459             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->x, y, fb - fab, -SCIPinfinity(scip), fb - consdata->xoffset, infeas, nbdchgs, naddconss) );
3460          }
3461          else
3462          {
3463             fb = consdata->lhs - b;
3464             fb = SIGN(fb) * pow(ABS(fb), 1.0/consdata->exponent);
3465             fab = consdata->lhs - (a+b);
3466             fab = SIGN(fab) * pow(ABS(fab), 1.0/consdata->exponent);
3467             SCIP_CALL( addVarbound(scip, cons, conshdlrdata->addvarboundcons, consdata->x, y, fb - fab, fb - consdata->xoffset,  SCIPinfinity(scip), infeas, nbdchgs, naddconss) );
3468          }
3469          if( *infeas )
3470             return SCIP_OKAY;
3471       }
3472 
3473    return SCIP_OKAY;
3474 }
3475 
3476 /** computes linear underestimator for (x+offset)^n + c*z <= rhs by linearization in x
3477  *
3478  * the generated cut is xmul * n * (refpoint+offset)^(n-1) * x + c*z <= rhs + ((n-1)*refpoint-offset) * (refpoint+offset)^(n-1)
3479  */
3480 static
generateLinearizationCut(SCIP * scip,SCIP_ROWPREP ** rowprep,SCIP_CONSHDLR * conshdlr,SCIP_Real refpoint,SCIP_Real exponent,SCIP_Real xoffset,SCIP_Real xmult,SCIP_Real zcoef,SCIP_Real rhs,SCIP_VAR * x,SCIP_VAR * z,SCIP_Bool islocal)3481 SCIP_RETCODE generateLinearizationCut(
3482    SCIP*                 scip,               /**< SCIP data structure */
3483    SCIP_ROWPREP**        rowprep,            /**< buffer to store rowprep */
3484    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3485    SCIP_Real             refpoint,           /**< base point for linearization */
3486    SCIP_Real             exponent,           /**< exponent n in sign(x)abs(x)^n */
3487    SCIP_Real             xoffset,            /**< offset of x */
3488    SCIP_Real             xmult,              /**< multiplier for coefficient of x */
3489    SCIP_Real             zcoef,              /**< coefficient of z */
3490    SCIP_Real             rhs,                /**< right hand side */
3491    SCIP_VAR*             x,                  /**< variable x */
3492    SCIP_VAR*             z,                  /**< variable z */
3493    SCIP_Bool             islocal             /**< whether the cut is valid only locally */
3494    )
3495 {
3496    SCIP_CONSHDLRDATA* conshdlrdata;
3497    SCIP_Real tmp;
3498 
3499    assert(scip != NULL);
3500    assert(rowprep != NULL);
3501    assert(!SCIPisFeasNegative(scip, refpoint+xoffset));
3502    assert(!SCIPisInfinity(scip, refpoint));
3503 
3504    conshdlrdata = SCIPconshdlrGetData(conshdlr);
3505    assert(conshdlrdata != NULL);
3506 
3507    if( refpoint < -xoffset )
3508       refpoint = -xoffset;
3509 
3510    tmp = exponent == 2.0 ? refpoint+xoffset : pow(refpoint+xoffset, exponent-1);
3511    if( SCIPisInfinity(scip, tmp) )
3512    {
3513       SCIPdebugMsg(scip, "skip linearization cut because (refpoint+offset)^(exponent-1) > infinity\n");
3514       *rowprep = NULL;
3515       return SCIP_OKAY;
3516    }
3517 
3518    rhs += ((exponent-1)*refpoint-xoffset)*tmp;   /* now rhs is the rhs of the cut */
3519    /* do not change the right hand side to a value > infinity (this would trigger an assertion in lp.c) */
3520    if( SCIPisInfinity(scip, rhs) )
3521    {
3522       SCIPdebugMsg(scip, "skip linearization cut because its rhs would be > infinity\n");
3523       *rowprep = NULL;
3524       return SCIP_OKAY;
3525    }
3526 
3527    SCIP_CALL( SCIPcreateRowprep(scip, rowprep, SCIP_SIDETYPE_RIGHT, islocal) );
3528    (void) SCIPsnprintf((*rowprep)->name, (int)sizeof((*rowprep)->name), "signpowlinearizecut_%u", ++(conshdlrdata->ncuts));
3529    SCIPaddRowprepSide(*rowprep, rhs);
3530    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, x, xmult*exponent*tmp) );
3531    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, z, zcoef) );
3532 
3533    return SCIP_OKAY;
3534 }
3535 
3536 /** computes linear underestimator for (x+xoffset)^n + c*z <= rhs by linearization in x
3537  *
3538  * the generated cut is xmul * n * (refpoint+offset)^(n-1) * x + c*z <= rhs + ((n-1)*refpoint-offset) * (refpoint+offset)^(n-1)
3539  * where refpoint is computed by projecting (xref, zref) onto the graph of (x+offset)^n w.r.t. euclidean norm
3540  *
3541  * Thus, the projection is computed by minimizing 1/2(x-xref)^2 + 1/2(((x+offset)^n-rhs)/(-c) - zref)^2.
3542  * I.e., we aim to find a root of
3543  *   g(x) = x - xref + n/c (x+offset)^(n-1) (zref - rhs/c) + n/c^2 (x+offset)^(2n-1)
3544  * We do this numerically by executing up to five newton iterations. It is
3545  *  g'(x) = 1 + n(n-1)/c (x+offset)^(n-2) (zref - rhs/c) + n(2n-1)/c^2 (x+offset)^(2n-2)
3546  */
3547 static
generateLinearizationCutProject(SCIP * scip,SCIP_ROWPREP ** rowprep,SCIP_CONSHDLR * conshdlr,SCIP_Real xref,SCIP_Real zref,SCIP_Real xmin,SCIP_Real exponent,SCIP_Real xoffset,SCIP_Real xmult,SCIP_Real zcoef,SCIP_Real rhs,SCIP_VAR * x,SCIP_VAR * z,SCIP_Bool islocal)3548 SCIP_RETCODE generateLinearizationCutProject(
3549    SCIP*                 scip,               /**< SCIP data structure */
3550    SCIP_ROWPREP**        rowprep,            /**< buffer to store rowprep */
3551    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3552    SCIP_Real             xref,               /**< reference point for x */
3553    SCIP_Real             zref,               /**< reference point for z */
3554    SCIP_Real             xmin,               /**< minimal value x is allowed to take */
3555    SCIP_Real             exponent,           /**< exponent n in sign(x+offset)abs(x+offset)^n */
3556    SCIP_Real             xoffset,            /**< offset of x */
3557    SCIP_Real             xmult,              /**< multiplier for coefficient of x */
3558    SCIP_Real             zcoef,              /**< coefficient of z */
3559    SCIP_Real             rhs,                /**< right hand side */
3560    SCIP_VAR*             x,                  /**< variable x */
3561    SCIP_VAR*             z,                  /**< variable z */
3562    SCIP_Bool             islocal             /**< whether the cut is valid only locally */
3563    )
3564 {
3565    SCIP_Real tmp;
3566    SCIP_Real xproj;
3567    SCIP_Real gval;
3568    SCIP_Real gderiv;
3569    int       iter;
3570 
3571    assert(scip != NULL);
3572    assert(!SCIPisFeasNegative(scip, xref+xoffset));
3573    assert(!SCIPisInfinity(scip, xref));
3574 
3575    if( xref < xmin )
3576       xref = xmin;
3577 
3578    xproj = xref;
3579    iter = 0;
3580    if( exponent == 2.0 )
3581    {
3582       do
3583       {
3584          tmp = (xproj+xoffset) * (xproj+xoffset);
3585          gval = xproj - xref + 2*(xproj+xoffset) / zcoef * ((tmp-rhs)/zcoef + zref);
3586          if( !SCIPisFeasPositive(scip, ABS(gval)) )
3587             break;
3588 
3589          gderiv = 1 + 6 * tmp / (zcoef*zcoef) + 2 / zcoef * (zref - rhs/zcoef);
3590          xproj -= gval / gderiv;
3591       }
3592       while( ++iter <= 5 );
3593    }
3594    else
3595    {
3596       do
3597       {
3598          tmp = pow(xproj + xoffset, exponent-1);
3599          gval = xproj - xref + exponent / zcoef * (pow(xproj+xoffset, 2*exponent-1)/zcoef + tmp * (zref-rhs/zcoef));
3600          if( !SCIPisFeasPositive(scip, ABS(gval)) )
3601             break;
3602 
3603          gderiv = 1 + exponent / zcoef * ( (2*exponent-1)*tmp*tmp/zcoef + (exponent-1)*pow(xproj+xoffset, exponent-2) * (zref-rhs/zcoef) );
3604          xproj -= gval / gderiv;
3605       }
3606       while( ++iter <= 5 );
3607    }
3608 
3609    if( xproj < xmin )
3610       xproj = xmin;
3611 
3612    SCIP_CALL( generateLinearizationCut(scip, rowprep, conshdlr, xproj, exponent, xoffset, xmult, zcoef, rhs, x, z, islocal) );
3613 
3614    return SCIP_OKAY;
3615 }
3616 
3617 /** computes secant underestimator for sign(x+offset)abs(x+offset)^n + c*z <= rhs
3618  *
3619  * the generated cut is slope*xmult*x + c*z <= rhs + (-xlb-offset)^n + slope*xlb,
3620  * where slope = (sign(xub+offset)*abs(xub+offset)^n + (-xlb-offset)^n) / (xub - xlb).
3621  *
3622  * the cut is not generated if the given solution (or the LP solution) would not be cutoff
3623  */
3624 static
generateSecantCut(SCIP * scip,SCIP_ROWPREP ** rowprep,SCIP_CONSHDLR * conshdlr,SCIP_SOL * sol,SCIP_Real xlb,SCIP_Real xub,SCIP_Real exponent,SCIP_Real xoffset,DECL_MYPOW ((* mypow)),SCIP_Real xmult,SCIP_Real zcoef,SCIP_Real rhs,SCIP_VAR * x,SCIP_VAR * z)3625 SCIP_RETCODE generateSecantCut(
3626    SCIP*                 scip,               /**< SCIP data structure */
3627    SCIP_ROWPREP**        rowprep,            /**< buffer to store rowprep */
3628    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3629    SCIP_SOL*             sol,                /**< point we want to cut off, or NULL for LP solution */
3630    SCIP_Real             xlb,                /**< lower bound of x */
3631    SCIP_Real             xub,                /**< upper bound of x */
3632    SCIP_Real             exponent,           /**< exponent n in sign(x+offset)abs(x+offset)^n */
3633    SCIP_Real             xoffset,            /**< offset of x */
3634    DECL_MYPOW            ((*mypow)),         /**< function to use for computing power */
3635    SCIP_Real             xmult,              /**< multiplier for coefficient of x */
3636    SCIP_Real             zcoef,              /**< coefficient of z */
3637    SCIP_Real             rhs,                /**< right hand side */
3638    SCIP_VAR*             x,                  /**< variable x */
3639    SCIP_VAR*             z                   /**< variable z */
3640    )
3641 {
3642    SCIP_CONSHDLRDATA* conshdlrdata;
3643    SCIP_Real slope, tmp, val;
3644 
3645    assert(scip != NULL);
3646    assert(SCIPisLE(scip, xlb, xub));
3647    assert(!SCIPisPositive(scip, xlb+xoffset));
3648 
3649    conshdlrdata = SCIPconshdlrGetData(conshdlr);
3650    assert(conshdlrdata != NULL);
3651 
3652    /* ignore constraints with fixed x (should be removed soon) */
3653    if( SCIPisRelEQ(scip, xlb, xub) )
3654    {
3655       SCIPdebugMsg(scip, "skip secant cut because <%s> is fixed [%.15g,%.15g]\n", SCIPvarGetName(x), SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x));
3656       return SCIP_OKAY;
3657    }
3658 
3659    if( xlb > -xoffset )
3660       xlb = -xoffset;
3661 
3662    tmp = mypow(-xlb-xoffset, exponent);
3663    slope  = SIGN(xub+xoffset) * mypow(ABS(xub+xoffset), exponent) + tmp;
3664    slope /= xub - xlb;
3665 
3666    /* check if cut would violated solution, check that slope is not above value of infinity */
3667    val = -tmp + slope * (xmult * SCIPgetSolVal(scip, sol, x) - xlb) + zcoef * SCIPgetSolVal(scip, sol, z) - rhs;
3668    if( !SCIPisFeasPositive(scip, val) || SCIPisInfinity(scip, REALABS(slope)) )
3669    {
3670       *rowprep = NULL;
3671       return SCIP_OKAY;
3672    }
3673 
3674    SCIP_CALL( SCIPcreateRowprep(scip, rowprep, SCIP_SIDETYPE_RIGHT, SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0 /* local */) );
3675    (void) SCIPsnprintf((*rowprep)->name, SCIP_MAXSTRLEN, "signpowsecantcut_%u", ++(conshdlrdata->nsecantcuts));
3676 
3677    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, x, xmult*slope) );
3678    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, z, zcoef) );
3679    SCIPaddRowprepSide(*rowprep, rhs + tmp + slope*xlb);
3680 
3681    return SCIP_OKAY;
3682 }
3683 
3684 /** computes secant underestimator for sign(x+xoffset)abs(x+xoffset)^n + c*z <= rhs
3685  *
3686  *  The generated cut is slope*xmult*x + c*z <= rhs + (-xlb-xoffset)^n + slope*xlb,
3687  *  where slope = (sign(xub+xoffset)*abs(xub+xoffset)^n + (-xlb-xoffset)^n) / (xub - xlb).
3688  */
3689 static
generateSecantCutNoCheck(SCIP * scip,SCIP_ROWPREP ** rowprep,SCIP_Real xlb,SCIP_Real xub,SCIP_Real exponent,SCIP_Real xoffset,DECL_MYPOW ((* mypow)),SCIP_Real xmult,SCIP_Real zcoef,SCIP_Real rhs,SCIP_VAR * x,SCIP_VAR * z)3690 SCIP_RETCODE generateSecantCutNoCheck(
3691    SCIP*                 scip,               /**< SCIP data structure */
3692    SCIP_ROWPREP**        rowprep,            /**< buffer to store rowprep */
3693    SCIP_Real             xlb,                /**< lower bound of x */
3694    SCIP_Real             xub,                /**< upper bound of x */
3695    SCIP_Real             exponent,           /**< exponent n in sign(x)abs(x)^n */
3696    SCIP_Real             xoffset,            /**< offset of x */
3697    DECL_MYPOW            ((*mypow)),         /**< function to use for computing power */
3698    SCIP_Real             xmult,              /**< multiplier for coefficient of x */
3699    SCIP_Real             zcoef,              /**< coefficient of z */
3700    SCIP_Real             rhs,                /**< right hand side */
3701    SCIP_VAR*             x,                  /**< variable x */
3702    SCIP_VAR*             z                   /**< variable z */
3703    )
3704 {
3705    SCIP_Real slope, tmp;
3706 
3707    assert(scip != NULL);
3708    assert(rowprep != NULL);
3709    assert(SCIPisLE(scip, xlb, xub));
3710    assert(!SCIPisPositive(scip, xlb + xoffset));
3711 
3712    /* ignore constraints with fixed x (should be removed soon) */
3713    if( SCIPisRelEQ(scip, xlb, xub) )
3714       return SCIP_OKAY;
3715 
3716    if( xlb > -xoffset )
3717       xlb = -xoffset;
3718 
3719    tmp = mypow(-xlb-xoffset, exponent);
3720    slope  = SIGN(xub+xoffset) * mypow(ABS(xub+xoffset), exponent) + tmp;
3721    slope /= xub - xlb;
3722 
3723    if( SCIPisInfinity(scip, REALABS(slope)) )
3724       return SCIP_OKAY;
3725 
3726    SCIP_CALL( SCIPcreateRowprep(scip, rowprep, SCIP_SIDETYPE_RIGHT, SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0 /* local */) );
3727    (void)SCIPmemccpy((*rowprep)->name, "signpowcut", '\0', 11);
3728    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, x, xmult*slope) );
3729    SCIP_CALL( SCIPaddRowprepTerm(scip, *rowprep, z, zcoef) );
3730    SCIPaddRowprepSide(*rowprep, rhs + tmp + slope*xlb);
3731 
3732    return SCIP_OKAY;
3733 }
3734 
3735 /** generates a cut
3736  *  based on Liberti and Pantelides, Convex Envelopes of Monomials of Odd Degree, J. Global Optimization 25, 157-168, 2003, and previous publications
3737  */
3738 static
generateCut(SCIP * scip,SCIP_CONS * cons,SCIP_SIDETYPE violside,SCIP_SOL * sol,SCIP_ROW ** row,SCIP_Bool onlyinbounds,SCIP_Real minviol)3739 SCIP_RETCODE generateCut(
3740    SCIP*                 scip,               /**< SCIP data structure */
3741    SCIP_CONS*            cons,               /**< constraint */
3742    SCIP_SIDETYPE         violside,           /**< side to separate */
3743    SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
3744    SCIP_ROW**            row,                /**< storage for cut */
3745    SCIP_Bool             onlyinbounds,       /**< whether linearization is allowed only in variable bounds */
3746    SCIP_Real             minviol             /**< a minimal violation in sol we hope to achieve */
3747    )
3748 {
3749    SCIP_CONSHDLRDATA* conshdlrdata;
3750    SCIP_CONSDATA* consdata;
3751    SCIP_ROWPREP*  rowprep = NULL;
3752    SCIP_Real      c;
3753    SCIP_Real      xlb;
3754    SCIP_Real      xglb;
3755    SCIP_Real      xub;
3756    SCIP_Real      xval;
3757    SCIP_Real      xoffset;
3758    SCIP_Real      xmult;
3759    SCIP_Real      zcoef;
3760    SCIP_Real      rhs;
3761 
3762    assert(scip != NULL);
3763    assert(cons != NULL);
3764    assert(row  != NULL);
3765 
3766    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
3767    assert(conshdlrdata != NULL);
3768 
3769    consdata = SCIPconsGetData(cons);
3770    assert(consdata != NULL);
3771 
3772    assert(SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)));
3773 
3774    *row = NULL;
3775 
3776    SCIPdebugMsg(scip, "generate cut for constraint <%s> with violated side %d\n", SCIPconsGetName(cons), violside);
3777    SCIPdebugPrintCons(scip, cons, NULL);
3778    SCIPdebugMsg(scip, "xlb = %g  xub = %g  xval = %g  zval = %.15g\n", SCIPvarGetLbLocal(consdata->x), SCIPvarGetUbLocal(consdata->x), SCIPgetSolVal(scip, sol, consdata->x), SCIPgetSolVal(scip, sol, consdata->z));
3779 
3780    if( violside == SCIP_SIDETYPE_RIGHT )
3781    {
3782       xglb  = SCIPvarGetLbGlobal(consdata->x);
3783       xlb   = SCIPvarGetLbLocal(consdata->x);
3784       xub   = SCIPvarGetUbLocal(consdata->x);
3785       xval  = SCIPgetSolVal(scip, sol, consdata->x);
3786       xoffset = consdata->xoffset;
3787       xmult = 1.0;
3788       zcoef = consdata->zcoef;
3789       rhs   = consdata->rhs;
3790    }
3791    else
3792    {
3793       xglb  = -SCIPvarGetUbGlobal(consdata->x);
3794       xlb   = -SCIPvarGetUbLocal(consdata->x);
3795       xub   = -SCIPvarGetLbLocal(consdata->x);
3796       xval  = -SCIPgetSolVal(scip, sol, consdata->x);
3797       xoffset = -consdata->xoffset;
3798       xmult = -1.0;
3799       zcoef = -consdata->zcoef;
3800       rhs   = -consdata->lhs;
3801    }
3802    /* move reference point onto local domain, if clearly (>eps) outside */
3803    if( SCIPisLT(scip, xval, xlb) )
3804       xval = xlb;
3805    else if( SCIPisGT(scip, xval, xub) )
3806       xval = xub;
3807 
3808    if( SCIPisInfinity(scip, REALABS(xval)) )
3809    {
3810       SCIPdebugMsg(scip, "skip separation since x is at infinity\n");
3811       return SCIP_OKAY;
3812    }
3813 
3814    if( !SCIPisNegative(scip, xlb+xoffset) )
3815    {
3816       /* [xlb, xub] completely in positive orthant -> function is convex on whole domain */
3817       SCIP_Bool islocal;
3818 
3819       islocal = (!SCIPconsIsGlobal(cons) || SCIPisNegative(scip, xglb+xoffset)) && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0;
3820       if( conshdlrdata->projectrefpoint && !onlyinbounds )
3821       {
3822          SCIP_CALL( generateLinearizationCutProject(scip, &rowprep, SCIPconsGetHdlr(cons), xval, SCIPgetSolVal(scip, sol, consdata->z), -xoffset, consdata->exponent,
3823                xoffset, xmult, zcoef, rhs, consdata->x, consdata->z, islocal) );
3824       }
3825       else if( !onlyinbounds )
3826       {
3827          SCIP_CALL( generateLinearizationCut(scip, &rowprep, SCIPconsGetHdlr(cons), xval, consdata->exponent, xoffset, xmult, zcoef, rhs,
3828                consdata->x, consdata->z, islocal) );
3829       }
3830       else
3831       {
3832          SCIP_CALL( generateLinearizationCut(scip, &rowprep, SCIPconsGetHdlr(cons), 2.0*xval > xlb + xub ? xub : xlb, consdata->exponent, xoffset, xmult, zcoef, rhs,
3833                consdata->x, consdata->z, islocal) );
3834       }
3835    }
3836    else if( !SCIPisPositive(scip, xub+xoffset) )
3837    {
3838       /* [xlb, xub] completely in negative orthant -> function is concave on whole domain */
3839       if( SCIPisInfinity(scip, -xlb) )
3840          return SCIP_OKAY;
3841       SCIP_CALL( generateSecantCut(scip, &rowprep, SCIPconsGetHdlr(cons), sol, xlb, xub, consdata->exponent, xoffset, consdata->power, xmult, zcoef, rhs, consdata->x, consdata->z) );
3842    }
3843    else if( (c = - consdata->root * (xlb+xoffset) - xoffset) > xub )
3844    {
3845       /* c is right of xub -> use secant */
3846       if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
3847          return SCIP_OKAY;
3848       SCIP_CALL( generateSecantCut(scip, &rowprep, SCIPconsGetHdlr(cons), sol, xlb, xub, consdata->exponent, xoffset, consdata->power, xmult, zcoef, rhs, consdata->x, consdata->z) );
3849    }
3850    else if( xval >= c )
3851    {
3852       /* xval is right of c -> use linearization */
3853       if( conshdlrdata->projectrefpoint && !onlyinbounds )
3854          SCIP_CALL( generateLinearizationCutProject(scip, &rowprep, SCIPconsGetHdlr(cons), xval, SCIPgetSolVal(scip, sol, consdata->z), c, consdata->exponent,
3855                xoffset, xmult, zcoef, rhs, consdata->x, consdata->z, SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0) );
3856       else if( !onlyinbounds )
3857          SCIP_CALL( generateLinearizationCut(scip, &rowprep, SCIPconsGetHdlr(cons), xval, consdata->exponent, xoffset, xmult, zcoef, rhs,
3858                consdata->x, consdata->z, xval+xoffset < - consdata->root * (xglb+xoffset) && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0) );
3859       else
3860          SCIP_CALL( generateLinearizationCut(scip, &rowprep, SCIPconsGetHdlr(cons), xub, consdata->exponent, xoffset, xmult, zcoef, rhs,
3861                consdata->x, consdata->z, xub+xoffset < - consdata->root * (xglb+xoffset) && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) > 0) );
3862    }
3863    else
3864    {
3865       /* xval between xlb and c -> use secant */
3866       if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, c) )
3867          return SCIP_OKAY;
3868       SCIP_CALL( generateSecantCut(scip, &rowprep, SCIPconsGetHdlr(cons), sol, xlb, c, consdata->exponent, xoffset, consdata->power, xmult, zcoef, rhs, consdata->x, consdata->z) );
3869    }
3870 
3871    /* check and improve numerics */
3872    if( rowprep != NULL )
3873    {
3874       SCIP_Real coefrange;
3875 
3876       SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
3877 
3878       /* we should not need SCIPmergeRowprep() with only 2 vars in the row */
3879       assert(rowprep->nvars <= 2);
3880 
3881       SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minviol, &coefrange, NULL) );
3882 
3883       if( coefrange >= conshdlrdata->cutmaxrange )
3884       {
3885          SCIPdebugMsg(scip, "skip cut for constraint <%s> because of very large range: %g\n", SCIPconsGetName(cons), coefrange);
3886       }
3887       else if( SCIPisInfinity(scip, REALABS(rowprep->side)) )
3888       {
3889          SCIPdebugMsg(scip, "skip cut for constraint <%s> because of very large side: %g\n", SCIPconsGetName(cons), rowprep->side);
3890       }
3891       else if( rowprep->nvars > 0 && SCIPisInfinity(scip, REALABS(rowprep->coefs[0])) )
3892       {
3893          SCIPdebugMsg(scip, "skip cut for constraint <%s> because of very large coef: %g\n", SCIPconsGetName(cons), rowprep->coefs[0]);
3894       }
3895       else
3896       {
3897          SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
3898       }
3899 
3900       SCIPfreeRowprep(scip, &rowprep);
3901    }
3902 
3903    return SCIP_OKAY;
3904 }
3905 
3906 /** tries to separate solution or LP solution by a linear cut
3907  *  assumes that constraint violations have been computed
3908  */
3909 static
separatePoint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_Real minefficacy,SCIP_Bool inenforcement,SCIP_Bool onlyinbounds,SCIP_Bool * success,SCIP_Bool * cutoff,SCIP_Real * bestefficacy)3910 SCIP_RETCODE separatePoint(
3911    SCIP*                 scip,               /**< SCIP data structure */
3912    SCIP_CONSHDLR*        conshdlr,           /**< quadratic constraints handler */
3913    SCIP_CONS**           conss,              /**< constraints */
3914    int                   nconss,             /**< number of constraints */
3915    int                   nusefulconss,       /**< number of constraints that seem to be useful */
3916    SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
3917    SCIP_Real             minefficacy,        /**< minimal efficacy of a cut if it should be added to the LP */
3918    SCIP_Bool             inenforcement,      /**< whether we are in constraint enforcement */
3919    SCIP_Bool             onlyinbounds,       /**< whether linearization is allowed only in variable bounds */
3920    SCIP_Bool*            success,            /**< result of separation: separated point (TRUE) or not (FALSE) */
3921    SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
3922    SCIP_Real*            bestefficacy        /**< buffer to store best efficacy of a cut that was added to the LP, if found; or NULL if not of interest */
3923    )
3924 {
3925    SCIP_CONSHDLRDATA* conshdlrdata;
3926    SCIP_CONSDATA*     consdata;
3927    SCIP_SIDETYPE      side;
3928    SCIP_Real          efficacy;
3929    int                c;
3930    SCIP_ROW*          row;
3931 
3932    assert(scip     != NULL);
3933    assert(conshdlr != NULL);
3934    assert(conss    != NULL || nconss == 0);
3935    assert(success  != NULL);
3936    assert(cutoff   != NULL);
3937 
3938    *success = FALSE;
3939    *cutoff = FALSE;
3940 
3941    conshdlrdata = SCIPconshdlrGetData(conshdlr);
3942    assert(conshdlrdata != NULL);
3943 
3944    if( bestefficacy != NULL )
3945       *bestefficacy = 0.0;
3946 
3947    for( c = 0, side = SCIP_SIDETYPE_LEFT; c < nconss && ! (*cutoff); c = (side == SCIP_SIDETYPE_RIGHT ? c+1 : c), side = (side == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT) )
3948    {
3949       assert(conss[c] != NULL);  /*lint !e613*/
3950 
3951       /* skip constraints that are not enabled, e.g., because they were already marked for deletion at this node */
3952       if( !SCIPconsIsEnabled(conss[c]) )  /*lint !e613*/
3953          continue;
3954 
3955       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
3956       assert(consdata != NULL);
3957 
3958       if( SCIPisGT(scip, side == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
3959       {
3960          /* try to generate a cut */
3961          SCIP_CALL( generateCut(scip, conss[c], side, sol, &row, onlyinbounds, minefficacy) );  /*lint !e613*/
3962          if( row == NULL ) /* failed to generate cut */
3963             continue;
3964 
3965          /* if cut is violated sufficiently, then add,
3966           * unless it corresponds to a bound change that is too weak (<eps) to be added
3967           */
3968          efficacy = -SCIPgetRowSolFeasibility(scip, row, sol);
3969          if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, row) )
3970          {
3971             SCIP_Bool infeasible;
3972 
3973             SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
3974             if ( infeasible )
3975                *cutoff = TRUE;
3976             else
3977                *success = TRUE;
3978             if( bestefficacy != NULL && efficacy > *bestefficacy )
3979                *bestefficacy = efficacy;
3980 
3981             /* notify indicator constraint handler about this cut */
3982             if( conshdlrdata->conshdlrindicator != NULL && !SCIProwIsLocal(row) )
3983             {
3984                SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
3985             }
3986 
3987             /* mark row as not removable from LP for current node, if in enforcement */
3988             if( inenforcement && !conshdlrdata->enfocutsremovable )
3989                SCIPmarkRowNotRemovableLocal(scip, row);
3990          }
3991 
3992          SCIP_CALL( SCIPreleaseRow (scip, &row) );
3993       }
3994 
3995       /* enforce only useful constraints
3996        * others are only checked and enforced if we are still feasible or have not found a separating cut yet
3997        */
3998       if( c >= nusefulconss && *success )
3999          break;
4000    }
4001 
4002    return SCIP_OKAY;
4003 }
4004 
4005 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
4006  * if separatedlpsol is not NULL, then a cut that separates the LP solution is added to the sepastore and is forced to enter the LP
4007  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
4008  * if separatedlpsol is NULL, then cut is added to cutpool only
4009  */
4010 static
addLinearizationCuts(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,SCIP_SOL * ref,SCIP_Bool * separatedlpsol,SCIP_Real minefficacy)4011 SCIP_RETCODE addLinearizationCuts(
4012    SCIP*                 scip,               /**< SCIP data structure */
4013    SCIP_CONSHDLR*        conshdlr,           /**< quadratic constraints handler */
4014    SCIP_CONS**           conss,              /**< constraints */
4015    int                   nconss,             /**< number of constraints */
4016    SCIP_SOL*             ref,                /**< reference point where to linearize, or NULL for LP solution */
4017    SCIP_Bool*            separatedlpsol,     /**< buffer to store whether a cut that separates the current LP solution was found and added to LP, or NULL if adding to cutpool only */
4018    SCIP_Real             minefficacy         /**< minimal efficacy of a cut when checking for separation of LP solution */
4019    )
4020 {
4021    SCIP_CONSDATA* consdata;
4022    SCIP_Bool addedtolp;
4023    SCIP_ROW* row;
4024    int c;
4025 
4026    assert(scip != NULL);
4027    assert(conshdlr != NULL);
4028    assert(conss != NULL || nconss == 0);
4029 
4030    if( separatedlpsol != NULL )
4031       *separatedlpsol = FALSE;
4032 
4033    for( c = 0; c < nconss; ++c )
4034    {
4035       assert(conss[c] != NULL);  /*lint !e613*/
4036 
4037       if( SCIPconsIsLocal(conss[c]) )  /*lint !e613*/
4038          continue;
4039 
4040       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
4041       assert(consdata != NULL);
4042 
4043       if( !SCIPisGT(scip, SCIPvarGetUbGlobal(consdata->x), -consdata->xoffset) && !SCIPisInfinity(scip, -consdata->lhs) )
4044       {
4045          /* constraint function is concave for x+offset <= 0.0, so can linearize w.r.t. lhs */
4046          consdata->lhsviol = 1.0;
4047          consdata->rhsviol = 0.0;
4048          SCIP_CALL( generateCut(scip, conss[c], SCIP_SIDETYPE_LEFT, ref, &row, FALSE, minefficacy) );  /*lint !e613*/
4049       }
4050       else if( !SCIPisLT(scip, SCIPvarGetLbGlobal(consdata->x), -consdata->xoffset) && !SCIPisInfinity(scip, -consdata->rhs) )
4051       {
4052          /* constraint function is convex for x+offset >= 0.0, so can linearize w.r.t. rhs */
4053          consdata->lhsviol = 0.0;
4054          consdata->rhsviol = 1.0;
4055          SCIP_CALL( generateCut(scip, conss[c], SCIP_SIDETYPE_RIGHT, ref, &row, FALSE, minefficacy) );  /*lint !e613*/
4056       }
4057       else
4058       {
4059          /* sign not fixed or nothing to linearize */
4060          continue;
4061       }
4062 
4063       if( row == NULL )
4064          continue;
4065 
4066       addedtolp = FALSE;
4067 
4068       /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
4069       if( separatedlpsol != NULL )
4070       {
4071          if( -SCIPgetRowLPFeasibility(scip, row) >= minefficacy )
4072          {
4073             SCIP_Bool infeasible;
4074 
4075             *separatedlpsol = TRUE;
4076             addedtolp = TRUE;
4077             SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
4078             assert( ! infeasible );
4079          }
4080       }
4081 
4082       if( !addedtolp && !SCIProwIsLocal(row) )
4083       {
4084          SCIP_CALL( SCIPaddPoolCut(scip, row) );
4085       }
4086 
4087       SCIP_CALL( SCIPreleaseRow(scip, &row) );
4088    }
4089 
4090    return SCIP_OKAY;
4091 }
4092 
4093 /** processes the event that a new primal solution has been found */
4094 static
SCIP_DECL_EVENTEXEC(processNewSolutionEvent)4095 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
4096 {
4097    SCIP_CONSHDLRDATA* conshdlrdata;
4098    SCIP_CONSHDLR* conshdlr;
4099    SCIP_CONS**    conss;
4100    int            nconss;
4101    SCIP_SOL*      sol;
4102 
4103    assert(scip != NULL);
4104    assert(event != NULL);
4105    assert(eventdata != NULL);
4106    assert(eventhdlr != NULL);
4107 
4108    assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
4109 
4110    conshdlr = (SCIP_CONSHDLR*)eventdata;
4111 
4112    nconss = SCIPconshdlrGetNConss(conshdlr);
4113 
4114    if( nconss == 0 )
4115       return SCIP_OKAY;
4116 
4117    sol = SCIPeventGetSol(event);
4118    assert(sol != NULL);
4119 
4120    conshdlrdata = SCIPconshdlrGetData(conshdlr);
4121    assert(conshdlrdata != NULL);
4122 
4123    /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
4124     * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
4125     * or are from the tree, but postprocessed via proposeFeasibleSolution
4126     */
4127    if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
4128       return SCIP_OKAY;
4129 
4130    conss = SCIPconshdlrGetConss(conshdlr);
4131    assert(conss != NULL);
4132 
4133    SCIPdebugMsg(scip, "catched new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
4134 
4135    SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
4136 
4137    return SCIP_OKAY;
4138 }
4139 
4140 /** given a solution, try to make absolute power constraints feasible by shifting the linear variable z and pass this solution to the trysol heuristic */
4141 static
proposeFeasibleSolution(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,SCIP_SOL * sol)4142 SCIP_RETCODE proposeFeasibleSolution(
4143    SCIP*                 scip,               /**< SCIP data structure */
4144    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4145    SCIP_CONS**           conss,              /**< constraints to process */
4146    int                   nconss,             /**< number of constraints */
4147    SCIP_SOL*             sol                 /**< solution to process */
4148    )
4149 {
4150    SCIP_CONSDATA* consdata;
4151    SCIP_SOL* newsol;
4152    SCIP_Real xtermval;
4153    SCIP_Real zval;
4154    SCIP_Real viol;
4155    SCIP_Bool solviolbounds;
4156    int c;
4157 
4158    assert(scip  != NULL);
4159    assert(conshdlr != NULL);
4160    assert(conss != NULL || nconss == 0);
4161 
4162    /* don't propose new solutions if not in presolve or solving */
4163    if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE || SCIPgetStage(scip) >= SCIP_STAGE_SOLVED )
4164       return SCIP_OKAY;
4165 
4166    if( sol != NULL )
4167    {
4168       SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
4169    }
4170    else
4171    {
4172       SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
4173    }
4174    SCIP_CALL( SCIPunlinkSol(scip, newsol) );
4175 
4176    for( c = 0; c < nconss; ++c )
4177    {
4178       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
4179       assert(consdata != NULL);
4180       assert(consdata->z != NULL);
4181       assert(consdata->zcoef != 0.0);
4182 
4183       /* recompute violation w.r.t. current solution */
4184       SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &viol, &solviolbounds) );  /*lint !e613*/
4185       assert(!solviolbounds);
4186 
4187       /* do nothing if constraint is satisfied */
4188       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4189          continue;
4190 
4191       /* if violation is at infinity, give up */
4192       if( SCIPisInfinity(scip, MAX(consdata->lhsviol, consdata->rhsviol)) )
4193          break;
4194 
4195       /* @todo could also adjust x while keeping z fixed */
4196 
4197       /* if variable is multiaggregated, then cannot set its solution value, so give up */
4198       if( SCIPvarGetStatus(consdata->z) == SCIP_VARSTATUS_MULTAGGR )
4199          break;
4200 
4201       /* compute value of x-term */
4202       xtermval  = SCIPgetSolVal(scip, newsol, consdata->x);
4203       xtermval += consdata->xoffset;
4204       xtermval  = SIGN(xtermval) * consdata->power(ABS(xtermval), consdata->exponent);
4205 
4206       /* if left hand side is violated, try to set z such that lhs is active */
4207       if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
4208       {
4209          assert(!SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip))); /* should only have one side violated (otherwise some variable is at infinity) */
4210 
4211          zval = (consdata->lhs - xtermval)/consdata->zcoef;
4212          /* bad luck: z would get value outside of its domain */
4213          if( SCIPisInfinity(scip, REALABS(zval)) || SCIPisFeasLT(scip, zval, SCIPvarGetLbGlobal(consdata->z)) || SCIPisFeasGT(scip, zval, SCIPvarGetUbGlobal(consdata->z)) )
4214             break;
4215          SCIP_CALL( SCIPsetSolVal(scip, newsol, consdata->z, zval) );
4216       }
4217 
4218       /* if right hand side is violated, try to set z such that rhs is active */
4219       if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4220       {
4221          zval = (consdata->rhs - xtermval)/consdata->zcoef;
4222          /* bad luck: z would get value outside of its domain */
4223          if( SCIPisInfinity(scip, REALABS(zval)) || SCIPisFeasLT(scip, zval, SCIPvarGetLbGlobal(consdata->z)) || SCIPisFeasGT(scip, zval, SCIPvarGetUbGlobal(consdata->z)) )
4224             break;
4225          SCIP_CALL( SCIPsetSolVal(scip, newsol, consdata->z, zval) );
4226       }
4227    }
4228 
4229    /* if we have a solution that should satisfy all absolute power constraints and has a better objective than the current upper bound, then pass it to the trysol heuristic */
4230    if( c == nconss )
4231    {
4232       SCIP_CONSHDLRDATA* conshdlrdata;
4233 
4234       SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
4235 
4236       conshdlrdata = SCIPconshdlrGetData(conshdlr);
4237       assert(conshdlrdata != NULL);
4238       assert(conshdlrdata->trysolheur != NULL);
4239 
4240       SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
4241    }
4242 
4243    SCIP_CALL( SCIPfreeSol(scip, &newsol) );
4244 
4245    return SCIP_OKAY;
4246 }
4247 
4248 /** create a nonlinear row representation of the constraint and stores them in consdata */
4249 static
createNlRow(SCIP * scip,SCIP_CONS * cons)4250 SCIP_RETCODE createNlRow(
4251    SCIP*                 scip,               /**< SCIP data structure */
4252    SCIP_CONS*            cons                /**< absolute power constraint */
4253    )
4254 {
4255    SCIP_CONSDATA* consdata;
4256    SCIP_EXPRTREE* exprtree;
4257    SCIP_EXPRCURV curv;
4258    SCIP_QUADELEM quadelem;
4259    SCIP_VAR* linvars[2];
4260    SCIP_Real lincoefs[2];
4261    SCIP_VAR* quadvar;
4262    SCIP_Real constant;
4263    SCIP_Bool expisint;
4264    int sign;
4265    int nlinvars;
4266    int nquadvars;
4267    int nquadelems;
4268    int n;
4269 
4270    assert(scip != NULL);
4271    assert(cons != NULL);
4272 
4273    consdata = SCIPconsGetData(cons);
4274    assert(consdata != NULL);
4275 
4276    if( consdata->nlrow != NULL )
4277    {
4278       SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4279    }
4280 
4281    nlinvars = 0;
4282    nquadvars = 0;
4283    nquadelems = 0;
4284    exprtree = NULL;
4285    constant = 0.0;
4286 
4287    /* check if sign of x is fixed, determine curvature of abspower function */
4288    if( !SCIPisNegative(scip, SCIPvarGetLbGlobal(consdata->x)+consdata->xoffset) )
4289    {
4290       sign =  1;
4291       curv = SCIP_EXPRCURV_CONVEX;
4292    }
4293    else if( !SCIPisPositive(scip, SCIPvarGetUbGlobal(consdata->x)+consdata->xoffset) )
4294    {
4295       sign = -1;
4296       curv = SCIP_EXPRCURV_CONCAVE;
4297    }
4298    else
4299    {
4300       sign =  0;
4301       curv = SCIP_EXPRCURV_UNKNOWN;
4302    }
4303 
4304    /* check if exponent is integral */
4305    expisint = SCIPisIntegral(scip, consdata->exponent);
4306    n = (int)SCIPround(scip, consdata->exponent);
4307 
4308    /* create quadelem or expression tree for nonlinear part sign(x+offset)abs(x+offset)^n */
4309    if( sign != 0 || (expisint && (n % 2 == 1)) )
4310    {
4311       /* sign is fixes or exponent is odd integer */
4312       if( expisint && n == 2 )
4313       {
4314          /* sign of x is clear and exponent is 2.0 -> generate quadratic, linear, and constant term for +/- (x+offset)^n */
4315          assert(sign == -1 || sign == 1);
4316          nquadelems = 1;
4317          quadelem.idx1 = 0;
4318          quadelem.idx2 = 0;
4319          quadelem.coef = (SCIP_Real)sign;
4320          nquadvars = 1;
4321          quadvar = consdata->x;
4322 
4323          if( consdata->xoffset != 0.0 )
4324          {
4325             linvars[0] = consdata->x;
4326             lincoefs[0] = sign * 2.0 * consdata->xoffset;
4327             nlinvars = 1;
4328             constant = sign * consdata->xoffset * consdata->xoffset;
4329          }
4330       }
4331       else
4332       {
4333          /* exponent is odd or sign of x is clear, generate expression tree for +/- (+/-(x+offset))^exponent */
4334          SCIP_EXPR* expr;
4335          SCIP_EXPR* expr2;
4336 
4337          SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* x */
4338          if( consdata->xoffset != 0.0 )
4339          {
4340             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->xoffset) );
4341             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, expr2) ); /* x + offset */
4342          }
4343          if( sign == -1 && !expisint )
4344          {
4345             /* if exponent is not integer and x is negative, then negate */
4346             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, -1.0) );         /* -1 */
4347             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr,  SCIP_EXPR_MUL,   expr, expr2) );  /* -(x+offset) */
4348          }
4349          /* use intpower for integer exponent and realpower for fractional exponent */
4350          if( expisint )
4351          {
4352             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_INTPOWER, expr, n) );  /* (x+offset)^n */
4353          }
4354          else
4355          {
4356             assert(sign == 1 || sign == -1);
4357             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_REALPOWER, expr, consdata->exponent) );  /* abs(x+offset)^exponent */
4358          }
4359          /* if exponent is even integer, then negate result; if it's an odd integer, then intpower already takes care of correct sign */
4360          if( sign == -1 && !(expisint && n % 2 == 1) )
4361          {
4362             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, -1.0) );         /* -1 */
4363             SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr,  SCIP_EXPR_MUL,   expr, expr2) );  /* -abs(x+offset)^exponent */
4364          }
4365          SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, 1, 0, NULL) );
4366       }
4367    }
4368    else
4369    {
4370       /* exponent is not odd integer and sign of x is not fixed -> generate expression tree for signpower(x+offset, n) */
4371       SCIP_EXPR* expr;
4372       SCIP_EXPR* expr2;
4373 
4374       SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* x */
4375       if( consdata->xoffset != 0.0 )
4376       {
4377          SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->xoffset) );
4378          SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, expr2) );   /* x + offset */
4379       }
4380       SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_SIGNPOWER, expr, (SCIP_Real)consdata->exponent) ); /* signpower(x+offset, n) */
4381 
4382       SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, 1, 0, NULL) );
4383    }
4384    assert(exprtree != NULL || nquadelems > 0);
4385 
4386    /* tell expression tree, which is its variable */
4387    if( exprtree != NULL )
4388    {
4389       SCIP_CALL( SCIPexprtreeSetVars(exprtree, 1, &consdata->x) );
4390    }
4391 
4392    assert(nlinvars < 2);
4393    linvars[nlinvars] = consdata->z;
4394    lincoefs[nlinvars] = consdata->zcoef;
4395    ++nlinvars;
4396 
4397    /* create nlrow */
4398    SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), constant,
4399          nlinvars, linvars, lincoefs,
4400          nquadvars, &quadvar, nquadelems, &quadelem,
4401          exprtree, consdata->lhs, consdata->rhs,
4402          curv
4403          ) );
4404 
4405    if( exprtree != NULL )
4406    {
4407       SCIP_CALL( SCIPexprtreeFree(&exprtree) );
4408    }
4409 
4410    return SCIP_OKAY;
4411 }
4412 
4413 /** upgrades a quadratic constraint where the quadratic part is only a single square term and the quadratic variable sign is fixed to a signpower constraint */
4414 static
SCIP_DECL_QUADCONSUPGD(quadconsUpgdAbspower)4415 SCIP_DECL_QUADCONSUPGD(quadconsUpgdAbspower)
4416 {  /*lint --e{715}*/
4417    SCIP_QUADVARTERM quadvarterm;
4418    SCIP_VAR* x;
4419    SCIP_VAR* z;
4420    SCIP_Real xoffset;
4421    SCIP_Real zcoef;
4422    SCIP_Real signpowcoef;
4423    SCIP_Real lhs;
4424    SCIP_Real rhs;
4425 
4426    *nupgdconss = 0;
4427 
4428    /* need at least one linear variable */
4429    if( SCIPgetNLinearVarsQuadratic(scip, cons) == 0 )
4430       return SCIP_OKAY;
4431 
4432    /* consider only quadratic constraints with a single square term */
4433    if( SCIPgetNQuadVarTermsQuadratic(scip, cons) != 1 )
4434       return SCIP_OKAY;
4435    assert(SCIPgetNBilinTermsQuadratic(scip, cons) == 0);
4436 
4437    quadvarterm = SCIPgetQuadVarTermsQuadratic(scip, cons)[0];
4438    if( SCIPisZero(scip, quadvarterm.sqrcoef) )
4439       return SCIP_OKAY;
4440 
4441    /* don't upgrade if upgrade would scale the constraint down (divide by |sqrcoef|)
4442     * @todo we could still allow this if we were keeping the scaling factor around for the feasibility check
4443     */
4444    if( REALABS(quadvarterm.sqrcoef) > 1.0 )
4445       return SCIP_OKAY;
4446 
4447    x = quadvarterm.var;
4448    xoffset = quadvarterm.lincoef / (2.0 * quadvarterm.sqrcoef);
4449 
4450    /* check that x has fixed sign */
4451    if( SCIPisNegative(scip, SCIPvarGetLbGlobal(x) + xoffset) && SCIPisPositive(scip, SCIPvarGetUbGlobal(x) + xoffset) )
4452       return SCIP_OKAY;
4453 
4454    /* check whether upgdconss array has enough space to store 1 or 2 constraints */
4455    if( SCIPgetNLinearVarsQuadratic(scip, cons) > 1 )
4456       *nupgdconss = -2;
4457    else
4458       *nupgdconss = -1;
4459    if( -*nupgdconss > upgdconsssize )
4460       return SCIP_OKAY;
4461 
4462    *nupgdconss = 0;
4463 
4464    SCIPdebugMsg(scip, "upgrade quadratic constraint <%s> to absolute power, x = [%g,%g], offset = %g\n", SCIPconsGetName(cons), SCIPvarGetLbGlobal(x), SCIPvarGetUbGlobal(x), xoffset);
4465    SCIPdebugPrintCons(scip, cons, NULL);
4466 
4467    lhs = SCIPgetLhsQuadratic(scip, cons);
4468    rhs = SCIPgetRhsQuadratic(scip, cons);
4469 
4470    /* get z and its coefficient */
4471    if( SCIPgetNLinearVarsQuadratic(scip, cons) > 1 )
4472    {
4473       /* create auxiliary variable and constraint for linear part, since we can handle only at most one variable in cons_signpower */
4474       char name[SCIP_MAXSTRLEN];
4475       SCIP_VAR* auxvar;
4476 
4477       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_linpart", SCIPconsGetName(cons));
4478       SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
4479             SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
4480       SCIP_CALL( SCIPaddVar(scip, auxvar) );
4481 
4482       SCIP_CALL( SCIPcreateConsLinear(scip, &upgdconss[0], name, SCIPgetNLinearVarsQuadratic(scip, cons),
4483             SCIPgetLinearVarsQuadratic(scip, cons), SCIPgetCoefsLinearVarsQuadratic(scip, cons),
4484             SCIPisInfinity(scip, -lhs) ? -SCIPinfinity(scip) : 0.0,
4485             SCIPisInfinity(scip,  rhs) ?  SCIPinfinity(scip) : 0.0,
4486             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), TRUE,
4487             TRUE, SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
4488             SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
4489             SCIPconsIsStickingAtNode(cons)) );
4490       SCIP_CALL( SCIPaddCoefLinear(scip, upgdconss[*nupgdconss], auxvar, -1.0) );
4491 
4492       z = auxvar;
4493       zcoef = 1.0;
4494 
4495       ++*nupgdconss;
4496 
4497       /* compute and set value of auxvar in debug solution */
4498 #ifdef WITH_DEBUG_SOLUTION
4499       if( SCIPdebugIsMainscip(scip) )
4500       {
4501          SCIP_Real debugval;
4502          SCIP_Real debugvarval;
4503          int i;
4504 
4505          debugval = 0.0;
4506          for( i = 0; i < SCIPgetNLinearVarsQuadratic(scip, cons); ++i )
4507          {
4508             SCIP_CALL( SCIPdebugGetSolVal(scip, SCIPgetLinearVarsQuadratic(scip, cons)[i], &debugvarval) );
4509             debugval += SCIPgetCoefsLinearVarsQuadratic(scip, cons)[i] * debugvarval;
4510          }
4511 
4512          SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
4513       }
4514 #endif
4515 
4516       SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4517    }
4518    else
4519    {
4520       assert(SCIPgetNLinearVarsQuadratic(scip, cons) == 1);
4521       z = SCIPgetLinearVarsQuadratic(scip, cons)[0];
4522       zcoef = SCIPgetCoefsLinearVarsQuadratic(scip, cons)[0];
4523    }
4524 
4525    /* we now have lhs <= sqrcoef * (x + offset)^2 - sqrcoef * offset^2 + zcoef * z <= rhs */
4526 
4527    /* move sqrcoef * offset^2 into lhs and rhs */
4528    if( !SCIPisInfinity(scip, -lhs) )
4529       lhs += quadvarterm.sqrcoef * xoffset * xoffset;
4530    if( !SCIPisInfinity(scip,  rhs) )
4531       rhs += quadvarterm.sqrcoef * xoffset * xoffset;
4532 
4533    /* divide by sqrcoef if x+offset > 0 and by -sqrcoef if < 0 */
4534    signpowcoef = quadvarterm.sqrcoef;
4535    if( SCIPisNegative(scip, SCIPvarGetLbGlobal(x) + xoffset) )
4536       signpowcoef = -signpowcoef;
4537    if( signpowcoef > 0.0 )
4538    {
4539       if( !SCIPisInfinity(scip, -lhs) )
4540          lhs /= signpowcoef;
4541       if( !SCIPisInfinity(scip,  rhs) )
4542          rhs /= signpowcoef;
4543    }
4544    else
4545    {
4546       SCIP_Real newrhs;
4547 
4548       if( !SCIPisInfinity(scip, -lhs) )
4549          newrhs = lhs / signpowcoef;
4550       else
4551          newrhs = SCIPinfinity(scip);
4552       if( !SCIPisInfinity(scip,  rhs) )
4553          lhs = rhs / signpowcoef;
4554       else
4555          lhs = -SCIPinfinity(scip);
4556       rhs = newrhs;
4557    }
4558    zcoef /= signpowcoef;
4559 
4560    /* create the absolute power constraint */
4561    SCIP_CALL( SCIPcreateConsAbspower(scip, &upgdconss[*nupgdconss], SCIPconsGetName(cons), x, z, 2.0,
4562          xoffset, zcoef, lhs, rhs,
4563          SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
4564          SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
4565          SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
4566          SCIPconsIsStickingAtNode(cons)) );
4567    SCIPdebugPrintCons(scip, upgdconss[*nupgdconss], NULL);
4568    ++*nupgdconss;
4569 
4570    return SCIP_OKAY;
4571 }
4572 
4573 /** tries to upgrade a nonlinear constraint into a absolute power constraint */
4574 static
SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdAbspower)4575 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdAbspower)
4576 {
4577    SCIP_EXPRGRAPH* exprgraph;
4578    SCIP_EXPRGRAPHNODE* node;
4579    SCIP_EXPRGRAPHNODE* child;
4580    SCIP_Real exponent;
4581    SCIP_VAR* x;
4582    SCIP_VAR* z;
4583    SCIP_Real signpowcoef;
4584    SCIP_Real zcoef;
4585    SCIP_Real xoffset;
4586    SCIP_Real constant;
4587    SCIP_Real lhs;
4588    SCIP_Real rhs;
4589 
4590    assert(nupgdconss != NULL);
4591    assert(upgdconss != NULL);
4592 
4593    *nupgdconss = 0;
4594 
4595    /* absolute power needs at least one linear variable (constraint is trivial, otherwise) */
4596    if( SCIPgetNLinearVarsNonlinear(scip, cons) == 0 )
4597       return SCIP_OKAY;
4598 
4599    node = SCIPgetExprgraphNodeNonlinear(scip, cons);
4600 
4601    /* no interest in linear constraints */
4602    if( node == NULL )
4603       return SCIP_OKAY;
4604 
4605    /* need exactly one argument */
4606    if( SCIPexprgraphGetNodeNChildren(node) != 1 )
4607       return SCIP_OKAY;
4608 
4609    constant = 0.0;
4610    signpowcoef = 1.0; /* coefficient of sign(x)abs(x)^n term, to be reformulated away... */
4611 
4612    child = SCIPexprgraphGetNodeChildren(node)[0];
4613 
4614    /* check if node expression fits to absolute power constraint */
4615    switch( SCIPexprgraphGetNodeOperator(node) )
4616    {
4617    case SCIP_EXPR_REALPOWER:
4618       /* realpower with exponent > 1.0 can always be signpower, since it assumes that argument is >= 0.0 */
4619       exponent = SCIPexprgraphGetNodeRealPowerExponent(node);
4620       if( exponent <= 1.0 )
4621          return SCIP_OKAY;
4622 
4623       assert(SCIPexprgraphGetNodeBounds(child).inf >= 0.0);
4624       break;
4625 
4626    case SCIP_EXPR_INTPOWER:
4627    {
4628       /* check if exponent > 1.0 and either odd or even with child having fixed sign */
4629       SCIP_INTERVAL childbounds;
4630 
4631       exponent = (SCIP_Real)SCIPexprgraphGetNodeIntPowerExponent(node);
4632       if( exponent <= 1.0 )
4633          return SCIP_OKAY;
4634 
4635       childbounds = SCIPexprgraphGetNodeBounds(child);
4636       if( (int)exponent % 2 == 0 && childbounds.inf < 0.0 && childbounds.sup > 0.0 )
4637          return SCIP_OKAY;
4638 
4639       /* use x^exponent = -sign(x) |x|^exponent if exponent is even and x always negative */
4640       if( (int)exponent % 2 == 0 && childbounds.inf < 0.0 )
4641          signpowcoef = -1.0;
4642 
4643       break;
4644    }
4645 
4646    case SCIP_EXPR_SQUARE:
4647    {
4648       /* check if child has fixed sign */
4649       SCIP_INTERVAL childbounds;
4650 
4651       childbounds = SCIPexprgraphGetNodeBounds(child);
4652       if( childbounds.inf < 0.0 && childbounds.sup > 0.0 )
4653          return SCIP_OKAY;
4654 
4655       /* use x^2 = -sign(x) |x|^2 if x is always negative */
4656       if( childbounds.inf < 0.0 )
4657          signpowcoef = -1.0;
4658 
4659       exponent = 2.0;
4660       break;
4661    }
4662 
4663    case SCIP_EXPR_SIGNPOWER:
4664       /* check if exponent > 1.0 */
4665       exponent = SCIPexprgraphGetNodeSignPowerExponent(node);
4666       if( exponent <= 1.0 )
4667          return SCIP_OKAY;
4668       break;
4669 
4670    case SCIP_EXPR_POLYNOMIAL:
4671    {
4672       SCIP_EXPRDATA_MONOMIAL* monomial;
4673       SCIP_INTERVAL childbounds;
4674 
4675       /* check if only one univariate monomial with exponent > 1.0 */
4676 
4677       /* if sum of univariate monomials, then this should have been taken care of by exprgraphnodeReformSignpower */
4678       if( SCIPexprgraphGetNodePolynomialNMonomials(node) > 1 )
4679          return SCIP_OKAY;
4680       assert(SCIPexprgraphGetNodePolynomialNMonomials(node) == 1); /* assume simplified, i.e., no constant polynomial */
4681 
4682       monomial = SCIPexprgraphGetNodePolynomialMonomials(node)[0];
4683       assert(SCIPexprGetMonomialNFactors(monomial) == 1); /* since we have only one children and assume simplified */
4684 
4685       exponent = SCIPexprGetMonomialExponents(monomial)[0];
4686       if( exponent <= 1.0 )
4687          return SCIP_OKAY;
4688 
4689       /* if exponent is even integer and child has mixed sign, then cannot do
4690        * if exponent is even integer and child is always negative, then can do via multiplication by -1.0 */
4691       childbounds = SCIPexprgraphGetNodeBounds(child);
4692       if( SCIPisIntegral(scip, exponent) && ((int)SCIPround(scip, exponent) % 2 == 0) && childbounds.inf < 0.0 )
4693       {
4694          if( childbounds.sup > 0.0 )
4695             return SCIP_OKAY;
4696          signpowcoef = -1.0;
4697       }
4698 
4699       constant = SCIPexprgraphGetNodePolynomialConstant(node);
4700       signpowcoef *= SCIPexprGetMonomialCoef(monomial);
4701 
4702       break;
4703    }
4704 
4705    default:
4706       return SCIP_OKAY;
4707    }  /*lint !e788*/
4708    assert(SCIPexprgraphGetNodeNChildren(node) == 1);
4709 
4710    /* check magnitue of coefficient of z in signpower constraint */
4711    zcoef = 1.0;
4712    if( SCIPgetNLinearVarsNonlinear(scip, cons) == 1 )
4713       zcoef = SCIPgetLinearCoefsNonlinear(scip, cons)[0];
4714    zcoef /= signpowcoef;
4715    if( SCIPexprgraphGetNodeOperator(child) == SCIP_EXPR_LINEAR && SCIPexprgraphGetNodeNChildren(child) == 1 )
4716    {
4717       zcoef /= pow(REALABS(SCIPexprgraphGetNodeLinearCoefs(child)[0]), exponent);
4718    }
4719    if( SCIPisZero(scip, zcoef) )
4720    {
4721       SCIPdebugMsg(scip, "skip upgrade to signpower since |zcoef| = %g would be zero\n", zcoef);
4722       return SCIP_OKAY;
4723    }
4724 
4725    /* count how many constraints we need to add (use negative numbers, for convenience):
4726     * one constraint for absolute power,
4727     * plus one if we need to replace the linear part by single variable,
4728     * plus one if we need to replace the argument of absolute power by a single variable
4729     */
4730    *nupgdconss = -1;
4731 
4732    if( SCIPexprgraphGetNodeOperator(child) != SCIP_EXPR_VARIDX && (SCIPexprgraphGetNodeOperator(child) != SCIP_EXPR_LINEAR || SCIPexprgraphGetNodeNChildren(child) > 1) )
4733    {
4734       /* if node has known curvature and we would add auxiliary var for child, then don't upgrade
4735        * it's not really necessary, but may introduce more numerical troubles
4736        * @todo maybe still do if child is linear?
4737        */
4738       if( SCIPexprgraphGetNodeCurvature(node) != SCIP_EXPRCURV_UNKNOWN )
4739       {
4740          *nupgdconss = 0;
4741          return SCIP_OKAY;
4742       }
4743 
4744       --*nupgdconss;
4745    }
4746 
4747    if( SCIPgetNLinearVarsNonlinear(scip, cons) > 1 )
4748       --*nupgdconss;
4749 
4750    /* request larger upgdconss array */
4751    if( upgdconsssize < -*nupgdconss )
4752       return SCIP_OKAY;
4753 
4754    SCIPdebugMsg(scip, "upgrading constraint <%s>\n", SCIPconsGetName(cons));
4755 
4756    /* start counting at zero again */
4757    *nupgdconss = 0;
4758 
4759    exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
4760 
4761    lhs = SCIPgetLhsNonlinear(scip, cons);
4762    rhs = SCIPgetRhsNonlinear(scip, cons);
4763 
4764    /* get x and it's offset */
4765    if( SCIPexprgraphGetNodeOperator(child) == SCIP_EXPR_VARIDX )
4766    {
4767       x = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, child);
4768       xoffset = 0.0;
4769    }
4770    else if( SCIPexprgraphGetNodeOperator(child) == SCIP_EXPR_LINEAR && SCIPexprgraphGetNodeNChildren(child) == 1 )
4771    {
4772       SCIP_Real xcoef;
4773 
4774       x = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(child)[0]);
4775       xcoef = SCIPexprgraphGetNodeLinearCoefs(child)[0];
4776       assert(!SCIPisZero(scip, xcoef));
4777 
4778       signpowcoef *= (xcoef < 0.0 ? -1.0 : 1.0) * pow(REALABS(xcoef), exponent);
4779       xoffset = SCIPexprgraphGetNodeLinearConstant(child) / xcoef;
4780    }
4781    else
4782    {
4783       /* reformulate by adding auxiliary variable and constraint for child */
4784       char name[SCIP_MAXSTRLEN];
4785       SCIP_INTERVAL bounds;
4786       SCIP_VAR* auxvar;
4787       SCIP_Real minusone;
4788 
4789       bounds = SCIPexprgraphGetNodeBounds(child);
4790       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_powerarg", SCIPconsGetName(cons));
4791 
4792       SCIPdebugMsg(scip, "add auxiliary variable and constraint %s for node %p(%d,%d)\n", name, (void*)child, SCIPexprgraphGetNodeDepth(child), SCIPexprgraphGetNodePosition(child));
4793 
4794       SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
4795             SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
4796       SCIP_CALL( SCIPaddVar(scip, auxvar) );
4797 
4798       /* create new constraint child == auxvar
4799        * since signpower is monotonic, we need only child <= auxvar or child >= auxvar, if not both sides are finite, and depending on signpowcoef
4800        * i.e., we need child - auxvar <= 0.0 if rhs is finite and signpowcoef > 0.0 or lhs is finite and signpowcoef < 0.0
4801        *   and we need 0.0 <= child - auxvar if lhs is finite and signpowcoef > 0.0 or rhs is finite and signpowcoef < 0.0
4802        */
4803       minusone = -1.0;
4804       assert(upgdconsssize > *nupgdconss);
4805       SCIP_CALL( SCIPcreateConsNonlinear2(scip, &upgdconss[*nupgdconss], name, 1, &auxvar, &minusone, child,
4806             ((signpowcoef > 0.0 && !SCIPisInfinity(scip, -lhs)) || (signpowcoef < 0.0 && !SCIPisInfinity(scip,  rhs))) ? 0.0 : -SCIPinfinity(scip),
4807             ((signpowcoef > 0.0 && !SCIPisInfinity(scip,  rhs)) || (signpowcoef < 0.0 && !SCIPisInfinity(scip, -lhs))) ? 0.0 :  SCIPinfinity(scip),
4808             TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4809       ++*nupgdconss;
4810 
4811       /* use auxvar to setup absolute power constraint */
4812       x = auxvar;
4813       xoffset = 0.0;
4814 
4815       /* compute and set value of auxvar in debug solution, if debugging is enabled */
4816       SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(child)) );  /*lint !e506 !e774*/
4817 
4818       SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4819    }
4820 
4821    /* get z and its coefficient */
4822    if( SCIPgetNLinearVarsNonlinear(scip, cons) > 1 )
4823    {
4824       /* create auxiliary variable and constraint for linear part, since we can handle only at most one variable in cons_signpower */
4825       char name[SCIP_MAXSTRLEN];
4826       SCIP_VAR* auxvar;
4827 
4828       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_linpart", SCIPconsGetName(cons));
4829       SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
4830             SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
4831       SCIP_CALL( SCIPaddVar(scip, auxvar) );
4832 
4833       assert(upgdconsssize > *nupgdconss);
4834       SCIP_CALL( SCIPcreateConsLinear(scip, &upgdconss[*nupgdconss], name, SCIPgetNLinearVarsNonlinear(scip, cons),
4835             SCIPgetLinearVarsNonlinear(scip, cons), SCIPgetLinearCoefsNonlinear(scip, cons),
4836             SCIPisInfinity(scip, -lhs) ? -SCIPinfinity(scip) : 0.0,
4837             SCIPisInfinity(scip,  rhs) ?  SCIPinfinity(scip) : 0.0,
4838             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), TRUE,
4839             TRUE, SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
4840             SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
4841             SCIPconsIsStickingAtNode(cons)) );
4842       SCIP_CALL( SCIPaddCoefLinear(scip, upgdconss[*nupgdconss], auxvar, -1.0) );
4843 
4844       z = auxvar;
4845       zcoef = 1.0;
4846 
4847       ++*nupgdconss;
4848 
4849       /* compute and set value of auxvar in debug solution */
4850 #ifdef WITH_DEBUG_SOLUTION
4851       if( SCIPdebugIsMainscip(scip) )
4852       {
4853          SCIP_Real debugval;
4854          SCIP_Real debugvarval;
4855          int i;
4856 
4857          debugval = 0.0;
4858          for( i = 0; i < SCIPgetNLinearVarsNonlinear(scip, cons); ++i )
4859          {
4860             SCIP_CALL( SCIPdebugGetSolVal(scip, SCIPgetLinearVarsNonlinear(scip, cons)[i], &debugvarval) );
4861             debugval += SCIPgetLinearCoefsNonlinear(scip, cons)[i] * debugvarval;
4862          }
4863 
4864          SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
4865       }
4866 #endif
4867 
4868       SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4869    }
4870    else
4871    {
4872       assert(SCIPgetNLinearVarsNonlinear(scip, cons) == 1);
4873       z = SCIPgetLinearVarsNonlinear(scip, cons)[0];
4874       zcoef = SCIPgetLinearCoefsNonlinear(scip, cons)[0];
4875    }
4876 
4877    if( constant != 0.0 )
4878    {
4879       if( !SCIPisInfinity(scip, -lhs) )
4880          lhs -= constant;
4881       if( !SCIPisInfinity(scip,  rhs) )
4882          rhs -= constant;
4883    }
4884 
4885    /* divide absolute power constraint by signpowcoef */
4886    if( signpowcoef != 1.0 )
4887    {
4888       zcoef /= signpowcoef;
4889       if( signpowcoef < 0.0 )
4890       {
4891          SCIP_Real newrhs;
4892 
4893          newrhs = SCIPisInfinity(scip, -lhs) ? SCIPinfinity(scip) : lhs/signpowcoef;
4894          lhs = SCIPisInfinity(scip, rhs) ? -SCIPinfinity(scip) : rhs/signpowcoef;
4895          rhs = newrhs;
4896       }
4897       else
4898       {
4899          if( !SCIPisInfinity(scip, -lhs) )
4900             lhs /= signpowcoef;
4901          if( !SCIPisInfinity(scip,  rhs) )
4902             rhs /= signpowcoef;
4903       }
4904    }
4905 
4906    /* finally setup a absolute power constraint */
4907 
4908    assert(*nupgdconss < upgdconsssize);
4909    SCIP_CALL( SCIPcreateConsAbspower(scip, &upgdconss[*nupgdconss], SCIPconsGetName(cons),
4910          x, z, exponent, xoffset, zcoef, lhs, rhs,
4911          SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
4912          SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
4913          SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
4914          SCIPconsIsStickingAtNode(cons)) );
4915    ++*nupgdconss;
4916 
4917    return SCIP_OKAY;
4918 }
4919 
4920 /** tries to reformulate a expression graph node via introducing a absolute power constraint
4921  * if node fits to absolute power and has indefinte curvature and has no nonlinear parents and has siblings, then replace by auxvar and absolute power constraint
4922  * if it still has nonlinear parents, then we wait to see if reformulation code move node into auxiliary constraint,
4923  *   so we do not add unnessary auxiliary variables for something like an x^2 in an exp(x^2)
4924  * if it has no siblings, then we let the upgrading for nonlinear constraints take care of it,
4925  *   since it may be able to upgrade the constraint as a whole and can take the constraint sides into account too (may need only <=/>= auxcons)
4926  */
4927 static
SCIP_DECL_EXPRGRAPHNODEREFORM(exprgraphnodeReformAbspower)4928 SCIP_DECL_EXPRGRAPHNODEREFORM(exprgraphnodeReformAbspower)
4929 {
4930    SCIP_EXPRGRAPHNODE* child;
4931    char name[SCIP_MAXSTRLEN];
4932    SCIP_CONS* cons;
4933    SCIP_Real exponent;
4934    SCIP_VAR* x;
4935    SCIP_VAR* z;
4936    SCIP_Real signpowcoef;
4937    SCIP_Real xoffset;
4938    SCIP_Real constant;
4939 
4940    assert(scip != NULL);
4941    assert(exprgraph != NULL);
4942    assert(node != NULL);
4943    assert(naddcons != NULL);
4944    assert(reformnode != NULL);
4945 
4946    *reformnode = NULL;
4947 
4948    if( SCIPexprgraphGetNodeCurvature(node) != SCIP_EXPRCURV_UNKNOWN )
4949       return SCIP_OKAY;
4950 
4951    constant = 0.0;
4952    signpowcoef = 1.0; /* coefficient of sign(x)abs(x)^n term, to be move in from of z... */
4953 
4954    /* check if node expression fits to absolute power constraint */
4955    switch( SCIPexprgraphGetNodeOperator(node) )
4956    {
4957    case SCIP_EXPR_REALPOWER:
4958       /* realpower with exponent > 1.0 can always be absolute power, since it assumes that argument is >= 0.0
4959        * @todo we should also ensure that argument is >= 0.0
4960        */
4961       exponent = SCIPexprgraphGetNodeRealPowerExponent(node);
4962       if( exponent <= 1.0 )
4963          return SCIP_OKAY;
4964 
4965       child = SCIPexprgraphGetNodeChildren(node)[0];
4966       assert(SCIPexprgraphGetNodeBounds(child).inf >= 0.0);
4967       break;
4968 
4969    case SCIP_EXPR_INTPOWER:
4970    {
4971       /* check if exponent > 1.0 and either odd or even with child having fixed sign */
4972       SCIP_INTERVAL childbounds;
4973 
4974       exponent = (SCIP_Real)SCIPexprgraphGetNodeIntPowerExponent(node);
4975       if( exponent <= 1.0 )
4976          return SCIP_OKAY;
4977 
4978       child = SCIPexprgraphGetNodeChildren(node)[0];
4979       childbounds = SCIPexprgraphGetNodeBounds(child);
4980       if( (int)exponent % 2 == 0 && childbounds.inf < 0.0 && childbounds.sup > 0.0 )
4981          return SCIP_OKAY;
4982 
4983       /* use x^exponent = -sign(x) |x|^exponent if exponent is even and x always negative */
4984       if( (int)exponent % 2 == 0 && childbounds.inf < 0.0 )
4985          signpowcoef = -1.0;
4986 
4987       break;
4988    }
4989 
4990    case SCIP_EXPR_SQUARE:
4991    {
4992       /* check if child has fixed sign */
4993       SCIP_INTERVAL childbounds;
4994 
4995       child = SCIPexprgraphGetNodeChildren(node)[0];
4996       childbounds = SCIPexprgraphGetNodeBounds(child);
4997       if( childbounds.inf < 0.0 && childbounds.sup > 0.0 )
4998          return SCIP_OKAY;
4999 
5000       /* use x^2 = -sign(x) |x|^2 if x is always negative */
5001       if( childbounds.inf < 0.0 )
5002          signpowcoef = -1.0;
5003 
5004       exponent = 2.0;
5005       break;
5006    }
5007 
5008    case SCIP_EXPR_SIGNPOWER:
5009       /* check if exponent > 1.0 */
5010       exponent = SCIPexprgraphGetNodeSignPowerExponent(node);
5011       if( exponent <= 1.0 )
5012          return SCIP_OKAY;
5013       child = SCIPexprgraphGetNodeChildren(node)[0];
5014       break;
5015 
5016    case SCIP_EXPR_POLYNOMIAL:
5017    {
5018       SCIP_EXPRDATA_MONOMIAL* monomial;
5019       SCIP_INTERVAL childbounds;
5020 
5021       /* check if only one monomial */
5022       if( SCIPexprgraphGetNodePolynomialNMonomials(node) > 1 )
5023          return SCIP_OKAY;
5024       assert(SCIPexprgraphGetNodePolynomialNMonomials(node) == 1); /* assume simplified, i.e., no constant polynomial */
5025 
5026       monomial = SCIPexprgraphGetNodePolynomialMonomials(node)[0];
5027 
5028       assert(SCIPexprgraphGetNodeNChildren(node) >= 1);
5029       if( SCIPexprgraphGetNodeNChildren(node) == 1 )
5030       {
5031          /* handle univariate case with exponent > 1.0 */
5032          assert(SCIPexprGetMonomialNFactors(monomial) == 1); /* since we have only one child and assume simplified */
5033 
5034          exponent = SCIPexprGetMonomialExponents(monomial)[0];
5035          if( exponent <= 1.0 )
5036             return SCIP_OKAY;
5037 
5038          /* if exponent is even integer and child has mixed sign, then cannot do
5039           * if exponent is even integer and child is always negative, then can do via multiplication by -1.0 */
5040          child = SCIPexprgraphGetNodeChildren(node)[0];
5041          childbounds = SCIPexprgraphGetNodeBounds(child);
5042          if( SCIPisIntegral(scip, exponent) && ((int)SCIPround(scip, exponent) % 2 == 0) && childbounds.inf < 0.0 )
5043          {
5044             if( childbounds.sup > 0.0 )
5045                return SCIP_OKAY;
5046             signpowcoef = -1.0;
5047          }
5048 
5049          constant = SCIPexprgraphGetNodePolynomialConstant(node);
5050          signpowcoef *= SCIPexprGetMonomialCoef(monomial);
5051       }
5052       else if( SCIPexprgraphGetNodeNChildren(node) == 2 )
5053       {
5054          /* look for abs(x)^p * x or x * abs(x)^p */
5055          SCIP_EXPRGRAPHNODE* child1;
5056          SCIP_EXPRGRAPHNODE* child2;
5057 
5058          assert(SCIPexprGetMonomialNFactors(monomial) == 2); /* since we have two children and assume simplified */
5059 
5060          child1 = SCIPexprgraphGetNodeChildren(node)[SCIPexprGetMonomialChildIndices(monomial)[0]];
5061          child2 = SCIPexprgraphGetNodeChildren(node)[SCIPexprGetMonomialChildIndices(monomial)[1]];
5062 
5063          if( SCIPexprgraphGetNodeOperator(child1) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(child1)[0] == child2 )
5064          {
5065             /* have abs(x)^p1 * x^p2; need p1 > 0, p2 = 1 */
5066             if( SCIPexprGetMonomialExponents(monomial)[0] <= 0.0 || SCIPexprGetMonomialExponents(monomial)[1] != 1.0 )
5067                return SCIP_OKAY;
5068             exponent = 1.0 + SCIPexprGetMonomialExponents(monomial)[0];
5069             child = child2;
5070          }
5071          else if( SCIPexprgraphGetNodeOperator(child2) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(child2)[0] == child1 )
5072          {
5073             /* have x^p1 * abs(x)^p2; need p1 = 1, p2 > 0 */
5074             if( SCIPexprGetMonomialExponents(monomial)[0] != 1.0 || SCIPexprGetMonomialExponents(monomial)[1] <= 0.0 )
5075                return SCIP_OKAY;
5076             exponent = 1.0 + SCIPexprGetMonomialExponents(monomial)[1];
5077             child = child1;
5078          }
5079          else
5080             return SCIP_OKAY;
5081 
5082          constant = SCIPexprgraphGetNodePolynomialConstant(node);
5083          signpowcoef = SCIPexprGetMonomialCoef(monomial);
5084       }
5085       else
5086          return SCIP_OKAY;
5087 
5088       break;
5089    }
5090 
5091    case SCIP_EXPR_MUL:
5092    {
5093       /* look for abs(x) * x and x * abs(x) */
5094       SCIP_EXPRGRAPHNODE* child1;
5095       SCIP_EXPRGRAPHNODE* child2;
5096 
5097       child1 = SCIPexprgraphGetNodeChildren(node)[0];
5098       child2 = SCIPexprgraphGetNodeChildren(node)[1];
5099 
5100       if( SCIPexprgraphGetNodeNChildren(child1) == 1 && SCIPexprgraphGetNodeOperator(child1) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(child1)[0] == child2 )
5101       {
5102          /* abs(x) * x */
5103          exponent = 2.0;
5104          child = child2;
5105          break;
5106       }
5107 
5108       if( SCIPexprgraphGetNodeNChildren(child2) == 1 && SCIPexprgraphGetNodeOperator(child2) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(child2)[0] == child1 )
5109       {
5110          /* x * abs(x) */
5111          exponent = 2.0;
5112          child = child1;
5113          break;
5114       }
5115 
5116       /* the cases below should not happening, because node will be of polynomial type after simplifty */
5117 #ifdef SCIP_DISABLED_CODE
5118       if( SCIPexprgraphGetNodeNChildren(child1) == 1 && (SCIPexprgraphGetNodeOperator(child1) == SCIP_EXPR_INTPOWER || SCIPexprgraphGetNodeOperator(child1) == SCIP_EXPR_REALPOWER) &&
5119          SCIPexprgraphGetNodeOperator(SCIPexprgraphGetNodeChildren(child1)[0]) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(SCIPexprgraphGetNodeChildren(child1)[0])[0] == child2 )
5120       {
5121          /* abs(x)^p * x */
5122          exponent = 1.0 + SCIPexprgraphGetNodeOperator(child1) == SCIP_EXPR_INTPOWER ? SCIPexprgraphGetNodeIntPowerExponent(child1) : SCIPexprgraphGetNodeRealPowerExponent(child1);
5123          child = child2;
5124          break;
5125       }
5126 
5127       if( SCIPexprgraphGetNodeNChildren(child2) == 1 && (SCIPexprgraphGetNodeOperator(child2) == SCIP_EXPR_INTPOWER || SCIPexprgraphGetNodeOperator(child2) == SCIP_EXPR_REALPOWER) &&
5128          SCIPexprgraphGetNodeOperator(SCIPexprgraphGetNodeChildren(child2)[0]) == SCIP_EXPR_ABS && SCIPexprgraphGetNodeChildren(SCIPexprgraphGetNodeChildren(child2)[0])[0] == child1 )
5129       {
5130          /* x * abs(x)^p */
5131          exponent = 1.0 + SCIPexprgraphGetNodeOperator(child2) == SCIP_EXPR_INTPOWER ? SCIPexprgraphGetNodeIntPowerExponent(child2) : SCIPexprgraphGetNodeRealPowerExponent(child2);
5132          child = child1;
5133          break;
5134       }
5135 #endif
5136       return SCIP_OKAY;
5137    }
5138 
5139    default:
5140       return SCIP_OKAY;
5141    }  /*lint !e788*/
5142 
5143    if( SCIPexprgraphHasNodeNonlinearAncestor(node) )
5144       return SCIP_OKAY;
5145    if( SCIPexprgraphGetNodeNChildren(node) == 1 && !SCIPexprgraphHasNodeSibling(node) )  /* why did I require siblings??? */
5146       return SCIP_OKAY;
5147 
5148    SCIPdebugMsg(scip, "reformulate node %p via signpower\n", (void*)node);
5149 
5150    /* get x and its offset */
5151    if( SCIPexprgraphGetNodeOperator(child) == SCIP_EXPR_VARIDX )
5152    {
5153       x = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, child);
5154       xoffset = 0.0;
5155    }
5156    else if( SCIPexprgraphGetNodeOperator(child) == SCIP_EXPR_LINEAR && SCIPexprgraphGetNodeNChildren(child) == 1 )
5157    {
5158       SCIP_Real xcoef;
5159 
5160       x = (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(child)[0]);
5161       xcoef = SCIPexprgraphGetNodeLinearCoefs(child)[0];
5162       assert(!SCIPisZero(scip, xcoef));
5163 
5164       signpowcoef *= (xcoef < 0.0 ? -1.0 : 1.0) * pow(REALABS(xcoef), exponent);
5165       xoffset = SCIPexprgraphGetNodeLinearConstant(child) / xcoef;
5166    }
5167    else
5168    {
5169       /* reformulate by adding auxiliary variable and constraint for child */
5170       SCIP_INTERVAL bounds;
5171       SCIP_VAR* auxvar;
5172       SCIP_Real minusone;
5173 
5174       bounds = SCIPexprgraphGetNodeBounds(child);
5175       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%dsp", *naddcons);
5176 
5177       SCIPdebugMsg(scip, "add auxiliary variable and constraint %s for node %p(%d,%d)\n", name, (void*)child, SCIPexprgraphGetNodeDepth(child), SCIPexprgraphGetNodePosition(child));
5178 
5179       SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0, SCIP_VARTYPE_CONTINUOUS,
5180             TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
5181       SCIP_CALL( SCIPaddVar(scip, auxvar) );
5182 
5183       /* create new constraint child == auxvar */
5184       minusone = -1.0;
5185       SCIP_CALL( SCIPcreateConsNonlinear2(scip, &cons, name, 1, &auxvar, &minusone, child, 0.0, 0.0,
5186             TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5187       SCIP_CALL( SCIPaddCons(scip, cons) );
5188       ++*naddcons;
5189 
5190       /* use auxvar to setup signpower constraint */
5191       x = auxvar;
5192       xoffset = 0.0;
5193 
5194       SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(child)) );  /*lint !e506 !e774*/
5195 
5196       SCIP_CALL( SCIPreleaseCons(scip, &cons) );
5197       SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
5198    }
5199 
5200    /* create auxiliary variable z and add to expression graph */
5201    (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%dsp", *naddcons);
5202    SCIP_CALL( SCIPcreateVar(scip, &z, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS,
5203          TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
5204    SCIP_CALL( SCIPaddVar(scip, z) );
5205    SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&z, reformnode) );
5206 
5207    /* setup a absolute power constraint */
5208    if( REALABS(signpowcoef) * SCIPfeastol(scip) < 1.0 )
5209    {
5210       /* if signpowcoef is not huge (<10^6), then put it into absolute power constraint */
5211       SCIP_CALL( SCIPcreateConsAbspower(scip, &cons, name,
5212             x, z, exponent, xoffset, -1.0/signpowcoef, -constant/signpowcoef, -constant/signpowcoef,
5213             TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5214       SCIP_CALL( SCIPaddCons(scip, cons) );
5215       SCIPdebugPrintCons(scip, cons, NULL);
5216       ++*naddcons;
5217 
5218       /* compute value of z and reformnode and set in debug solution and expression graph, resp. */
5219 #ifdef WITH_DEBUG_SOLUTION
5220       if( SCIPdebugIsMainscip(scip) )
5221       {
5222          SCIP_Real xval;
5223          SCIP_Real zval;
5224 
5225          SCIP_CALL( SCIPdebugGetSolVal(scip, x, &xval) );
5226          zval = signpowcoef * SIGN(xval + xoffset) * pow(REALABS(xval + xoffset), exponent) + constant;
5227 
5228          SCIP_CALL( SCIPdebugAddSolVal(scip, z, zval) );
5229          SCIPexprgraphSetVarNodeValue(*reformnode, zval);
5230       }
5231 #endif
5232    }
5233    else
5234    {
5235       /* if signpowcoef is huge, then avoid very small coefficient of z
5236        * instead create additional node on top of current reformnode */
5237       SCIP_EXPRGRAPHNODE* linnode;
5238 
5239       SCIP_CALL( SCIPcreateConsAbspower(scip, &cons, name,
5240             x, z, exponent, xoffset, -1.0, 0.0, 0.0,
5241             TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5242       SCIP_CALL( SCIPaddCons(scip, cons) );
5243       SCIPdebugPrintCons(scip, cons, NULL);
5244       ++*naddcons;
5245 
5246       /* compute value of z and reformnode and set in debug solution and expression graph, resp. */
5247 #ifdef WITH_DEBUG_SOLUTION
5248       if( SCIPdebugIsMainscip(scip) )
5249       {
5250          SCIP_Real xval;
5251          SCIP_Real zval;
5252 
5253          SCIP_CALL( SCIPdebugGetSolVal(scip, x, &xval) );
5254          zval = SIGN(xval + xoffset) * pow(REALABS(xval + xoffset), exponent);
5255 
5256          SCIP_CALL( SCIPdebugAddSolVal(scip, z, zval) );
5257          SCIPexprgraphSetVarNodeValue(*reformnode, zval);
5258       }
5259 #endif
5260 
5261       SCIP_CALL( SCIPexprgraphCreateNodeLinear(SCIPblkmem(scip), &linnode, 1, &signpowcoef, constant) );
5262       SCIP_CALL( SCIPexprgraphAddNode(exprgraph, linnode, -1, 1, reformnode) );
5263 
5264       *reformnode = linnode;
5265    }
5266 
5267    SCIP_CALL( SCIPreleaseCons(scip, &cons) );
5268    SCIP_CALL( SCIPreleaseVar(scip, &z) );
5269 
5270    return SCIP_OKAY;
5271 }
5272 
5273 /** helper function to enforce constraints */
5274 static
enforceConstraint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_Bool solinfeasible,SCIP_RESULT * result)5275 SCIP_RETCODE enforceConstraint(
5276    SCIP*                 scip,               /**< SCIP data structure */
5277    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5278    SCIP_CONS**           conss,              /**< constraints to process */
5279    int                   nconss,             /**< number of constraints */
5280    int                   nusefulconss,       /**< number of useful (non-obsolete) constraints to process */
5281    SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
5282    SCIP_Bool             solinfeasible,      /**< was the solution already declared infeasible by a constraint handler? */
5283    SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
5284    )
5285 {
5286    SCIP_CONSHDLRDATA* conshdlrdata;
5287    SCIP_CONS*         maxviolcons;
5288    SCIP_CONSDATA*     consdata;
5289    SCIP_Bool          success;
5290    SCIP_Bool          cutoff;
5291    SCIP_Bool          solviolbounds;
5292    SCIP_Real          sepaefficacy;
5293    SCIP_Real          maxviol;
5294    int                nnotify;
5295    int                c;
5296 
5297    assert(scip     != NULL);
5298    assert(conshdlr != NULL);
5299    assert(conss    != NULL || nconss == 0);
5300    assert(result   != NULL);
5301 
5302    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5303    assert(conshdlrdata != NULL);
5304 
5305    SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcons) );
5306 
5307    if( maxviolcons == NULL )
5308    {
5309       *result = SCIP_FEASIBLE;
5310       return SCIP_OKAY;
5311    }
5312 
5313    *result = SCIP_INFEASIBLE;
5314 
5315    if( solviolbounds )
5316    {
5317       /* if LP solution violates variable bounds, then this should be because a row was added that
5318        * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
5319        * have been added to resolve an infeasibility, so solinfeasible should be TRUE
5320        * see also issue #627
5321        */
5322       assert(solinfeasible);
5323       /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
5324        * stops because infeasible cannot be resolved */
5325        /*lint --e{774} */
5326       if( !solinfeasible )
5327          *result = SCIP_CUTOFF;
5328       return SCIP_OKAY;
5329    }
5330 
5331    /* if we are above the 100'th enforcement round for this node, something is strange
5332     * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
5333     * in this case, check if some limit is hit or SCIP should stop for some other reason and terminate enforcement by creating a dummy node
5334     * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
5335     * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
5336     * we only increment nenforounds until 101 to avoid an overflow
5337     */
5338    if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
5339    {
5340       if( conshdlrdata->nenforounds > 100 )
5341       {
5342          if( SCIPisStopped(scip) )
5343          {
5344             SCIP_NODE* child;
5345 
5346             SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
5347             *result = SCIP_BRANCHED;
5348 
5349             return SCIP_OKAY;
5350          }
5351       }
5352       else
5353          ++conshdlrdata->nenforounds;
5354    }
5355    else
5356    {
5357       conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
5358       conshdlrdata->nenforounds = 0;
5359    }
5360 
5361    /* run domain propagation for violated constraints */
5362    for( c = 0; c < nconss; ++c )
5363    {
5364       int       nchgbds;
5365       int       naddconss;
5366 
5367       assert(conss[c] != NULL);  /*lint !e613*/
5368 
5369       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
5370       assert(consdata != NULL);
5371 
5372       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5373          continue;
5374 
5375       nchgbds = 0;
5376       naddconss = 0;
5377       SCIP_CALL( propagateCons(scip, conshdlr, conss[c], TRUE, &cutoff, &nchgbds, &naddconss) );  /*lint !e613*/
5378       if( cutoff )
5379       {
5380          *result = SCIP_CUTOFF;
5381          return SCIP_OKAY;
5382       }
5383       if( nchgbds )
5384          *result = SCIP_REDUCEDDOM;
5385       if( naddconss )
5386          *result = SCIP_CONSADDED;
5387    }
5388    if( *result == SCIP_REDUCEDDOM || *result == SCIP_CONSADDED )
5389       return SCIP_OKAY;
5390 
5391    consdata = SCIPconsGetData(maxviolcons);
5392    assert(consdata != NULL);
5393    maxviol = consdata->lhsviol + consdata->rhsviol;
5394    assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
5395 
5396    /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
5397     * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
5398     */
5399    SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPfeastol(scip), TRUE, FALSE, &success,
5400          &cutoff, &sepaefficacy) );
5401    if( cutoff )
5402    {
5403       SCIPdebugMsg(scip, "separation detected cutoff.\n");
5404       *result = SCIP_CUTOFF;
5405       return SCIP_OKAY;
5406    }
5407    if( success )
5408    {
5409       SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
5410       *result = SCIP_SEPARATED;
5411       return SCIP_OKAY;
5412    }
5413    SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip),
5414       maxviol);
5415 
5416    /* we are not feasible, the whole node is not infeasible, and we cannot find a reasonable cut
5417     * -> collect variables for branching
5418     */
5419    SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
5420 
5421    if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPgetLPFeastol(scip) )
5422    {
5423       /* fallback 1: we also have no branching candidates, so try to find a weak cut */
5424       SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetLPFeastol(scip), TRUE, FALSE,
5425             &success, &cutoff, &sepaefficacy) );
5426       if( cutoff )
5427       {
5428          SCIPdebugMsg(scip, "separation detected cutoff.\n");
5429          *result = SCIP_CUTOFF;
5430          return SCIP_OKAY;
5431       }
5432       if( success )
5433       {
5434          *result = SCIP_SEPARATED;
5435          return SCIP_OKAY;
5436       }
5437    }
5438 
5439    if( nnotify == 0 && !solinfeasible )
5440    {
5441       SCIP_Bool reduceddom;
5442       SCIP_VAR* brvar = NULL;
5443 
5444       /* fallback 2: fix almost-fixed nonlinear variables */
5445       SCIP_CALL( fixAlmostFixedX(scip, conss, nconss, &cutoff, &reduceddom) );
5446       if( cutoff )
5447       {
5448          SCIPdebugMsg(scip, "fixing almost fixed var lead to infeasibility.\n");
5449          *result = SCIP_CUTOFF;
5450          return SCIP_OKAY;
5451       }
5452       if( reduceddom )
5453       {
5454          *result = SCIP_REDUCEDDOM;
5455          return SCIP_OKAY;
5456       }
5457 
5458       /* fallback 3: separation probably failed because of numerical difficulties;
5459          if no-one declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching */
5460       SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
5461       if( brvar == NULL )
5462       {
5463          SCIPwarningMessage(scip, "Could not find any branching variable candidate. Cutting off node. Max viol = %g.\n",
5464             SCIPconsGetData(maxviolcons)->lhsviol+SCIPconsGetData(maxviolcons)->rhsviol);
5465          *result = SCIP_CUTOFF;
5466          return SCIP_OKAY;
5467       }
5468       else
5469       {
5470          SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable %s with LP value %g for branching. Max. viol. cons. <%s>: %g+%g\n",
5471             SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar), SCIPconsGetName(maxviolcons),
5472             SCIPconsGetData(maxviolcons)->lhsviol, SCIPconsGetData(maxviolcons)->rhsviol);
5473          nnotify = 1;
5474       }
5475    }
5476 
5477    assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
5478    return SCIP_OKAY;
5479 }
5480 
5481 /*
5482  * Callback methods of constraint handler
5483  */
5484 
5485 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
5486 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopyAbspower)5487 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyAbspower)
5488 {  /*lint --e{715}*/
5489    assert(scip != NULL);
5490    assert(conshdlr != NULL);
5491    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
5492 
5493    /* call inclusion method of constraint handler */
5494    SCIP_CALL( SCIPincludeConshdlrAbspower(scip) );
5495 
5496    *valid = TRUE;
5497 
5498    return SCIP_OKAY;
5499 }
5500 
5501 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
5502 static
SCIP_DECL_CONSFREE(consFreeAbspower)5503 SCIP_DECL_CONSFREE(consFreeAbspower)
5504 {  /*lint --e{715}*/
5505    SCIP_CONSHDLRDATA* conshdlrdata;
5506 
5507    assert(scip     != NULL);
5508    assert(conshdlr != NULL);
5509 
5510    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5511    assert(conshdlrdata != NULL);
5512 
5513    SCIPfreeBlockMemory(scip, &conshdlrdata);
5514 
5515    return SCIP_OKAY;
5516 }
5517 
5518 /** initialization method of constraint handler (called after problem was transformed) */
5519 static
SCIP_DECL_CONSINIT(consInitAbspower)5520 SCIP_DECL_CONSINIT(consInitAbspower)
5521 {  /*lint --e{715}*/
5522    SCIP_CONSHDLRDATA* conshdlrdata;
5523 
5524    assert(scip != NULL);
5525    assert(conshdlr != NULL);
5526 
5527    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5528    assert(conshdlrdata != NULL);
5529 
5530    conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
5531    conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
5532    conshdlrdata->conshdlrindicator = SCIPfindConshdlr(scip, "indicator");
5533    conshdlrdata->nsecantcuts = 0;
5534    conshdlrdata->ncuts = 0;
5535 
5536    return SCIP_OKAY;
5537 }
5538 
5539 /** deinitialization method of constraint handler (called before transformed problem is freed) */
5540 static
SCIP_DECL_CONSEXIT(consExitAbspower)5541 SCIP_DECL_CONSEXIT(consExitAbspower)
5542 {  /*lint --e{715}*/
5543    SCIP_CONSHDLRDATA* conshdlrdata;
5544 
5545    assert(scip != NULL);
5546    assert(conshdlr != NULL);
5547 
5548    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5549    assert(conshdlrdata != NULL);
5550 
5551    conshdlrdata->subnlpheur = NULL;
5552    conshdlrdata->trysolheur = NULL;
5553    conshdlrdata->conshdlrindicator = NULL;
5554 
5555    return SCIP_OKAY;
5556 }
5557 
5558 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
5559 static
SCIP_DECL_CONSINITPRE(consInitpreAbspower)5560 SCIP_DECL_CONSINITPRE(consInitpreAbspower)
5561 {  /*lint --e{715}*/
5562    SCIP_CONSHDLRDATA* conshdlrdata;
5563 
5564    assert(conshdlr != NULL);
5565 
5566    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5567    assert(conshdlrdata != NULL);
5568 
5569    /* initialize comparedpairwise flag to TRUE, if at most one constraint, otherwise 0 */
5570    conshdlrdata->comparedpairwise = (nconss <= 1);
5571 
5572    return SCIP_OKAY;
5573 }
5574 
5575 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
5576 static
SCIP_DECL_CONSEXITPRE(consExitpreAbspower)5577 SCIP_DECL_CONSEXITPRE(consExitpreAbspower)
5578 {  /*lint --e{715}*/
5579    int c;
5580 
5581    assert(scip  != NULL);
5582    assert(conss != NULL || nconss == 0);
5583 
5584    /* tell SCIP that we have something nonlinear, and whether we are nonlinear in a continuous variable */
5585    for( c = 0; c < nconss; ++c )
5586    {
5587       assert(conss[c] != NULL);  /*lint !e613*/
5588 
5589       if( SCIPconsIsAdded(conss[c]) )  /*lint !e613*/
5590       {
5591          SCIPenableNLP(scip);
5592          break;
5593       }
5594    }
5595 
5596    return SCIP_OKAY;
5597 }
5598 
5599 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
5600 static
SCIP_DECL_CONSINITSOL(consInitsolAbspower)5601 SCIP_DECL_CONSINITSOL(consInitsolAbspower)
5602 {  /*lint --e{715}*/
5603    SCIP_CONSHDLRDATA* conshdlrdata;
5604    SCIP_CONSDATA* consdata;
5605    int            c;
5606 
5607    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5608    assert(conshdlrdata != NULL);
5609 
5610    assert(scip  != NULL);
5611    assert(conss != NULL || nconss == 0);
5612 
5613    for( c = 0; c < nconss; ++c )
5614    {
5615       assert(conss[c] != NULL);  /*lint !e613*/
5616 
5617       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
5618       assert(consdata != NULL);
5619 
5620       assert(consdata->exponent > 1.0);
5621 
5622       /* setup root that corresponds to exponent */
5623       if( SCIPisIntegral(scip, consdata->exponent) && consdata->exponent-0.5 < ROOTS_KNOWN )
5624       {
5625          consdata->root = roots[(int)SCIPfloor(scip, consdata->exponent+0.5)];
5626       }
5627       else if( SCIPisEQ(scip, consdata->exponent, 1.852) )
5628       {
5629          consdata->root = 0.39821689389382575186;
5630       }
5631       else
5632       {
5633          SCIP_Real root;
5634          SCIP_Real polyval;
5635          SCIP_Real gradval;
5636          int iter;
5637 
5638          /* search for a positive root of (n-1) y^n + n y^(n-1) - 1
5639           * use the closest precomputed root as starting value */
5640          if( consdata->exponent >= ROOTS_KNOWN )
5641             root = roots[ROOTS_KNOWN];
5642          else if( consdata->exponent <= 2.0 )
5643             root = roots[2];
5644          else
5645             root = roots[(int)SCIPfloor(scip, consdata->exponent)];
5646          iter = 0;
5647          do
5648          {
5649             polyval = (consdata->exponent - 1.0) * consdata->power(root, consdata->exponent) + consdata->exponent * pow(root, consdata->exponent-1.0) - 1.0;
5650             if( SCIPisZero(scip, polyval) )
5651                break;
5652 
5653             /* gradient of (n-1) y^n + n y^(n-1) - 1 is n(n-1)y^(n-1) + n(n-1)y^(n-2) */
5654             gradval = (consdata->exponent - 1.0) * consdata->exponent * (pow(root, consdata->exponent - 1.0) + pow(root, consdata->exponent - 2.0));
5655             if( SCIPisZero(scip, gradval) )
5656                break;
5657 
5658             /* update root by adding -polyval/gradval (Newton's method) */
5659             root -= polyval / gradval;
5660             if( root < 0.0 )
5661                root = 0.0;
5662          }
5663          while( ++iter < 1000 );
5664 
5665          if( !SCIPisZero(scip, polyval) )
5666          {
5667             SCIPerrorMessage("failed to compute root for exponent %g\n", consdata->exponent);
5668             return SCIP_ERROR;
5669          }
5670          SCIPdebugMsg(scip, "root for %g is %.15g, certainty = %g\n", consdata->exponent, root, polyval);
5671          /* @todo cache root value?? (they are actually really fast to compute...) */
5672 
5673          consdata->root = root;
5674       }
5675 
5676       /* add nlrow respresentation to NLP, if NLP had been constructed */
5677       if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )  /*lint !e613*/
5678       {
5679          if( consdata->nlrow == NULL )
5680          {
5681             SCIP_CALL( createNlRow(scip, conss[c]) );  /*lint !e613*/
5682             assert(consdata->nlrow != NULL);
5683          }
5684          SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
5685       }
5686    }
5687 
5688    conshdlrdata->newsoleventfilterpos = -1;
5689    if( nconss != 0 )
5690    {
5691       SCIP_EVENTHDLR* eventhdlr;
5692 
5693       eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
5694       assert(eventhdlr != NULL);
5695 
5696       SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
5697    }
5698 
5699    /* reset flags and counters */
5700    conshdlrdata->sepanlp = FALSE;
5701    conshdlrdata->lastenfonode = NULL;
5702    conshdlrdata->nenforounds = 0;
5703 
5704    return SCIP_OKAY;
5705 }
5706 
5707 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
5708 static
SCIP_DECL_CONSEXITSOL(consExitsolAbspower)5709 SCIP_DECL_CONSEXITSOL(consExitsolAbspower)
5710 {  /*lint --e{715}*/
5711    SCIP_CONSHDLRDATA* conshdlrdata;
5712    SCIP_CONSDATA* consdata;
5713    int c;
5714 
5715    assert(scip  != NULL);
5716    assert(conss != NULL || nconss == 0);
5717 
5718    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5719    assert(conshdlrdata != NULL);
5720 
5721    if( conshdlrdata->newsoleventfilterpos >= 0 )
5722    {
5723       SCIP_EVENTHDLR* eventhdlr;
5724 
5725       eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
5726       assert(eventhdlr != NULL);
5727 
5728       SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
5729       conshdlrdata->newsoleventfilterpos = -1;
5730    }
5731 
5732    for( c = 0; c < nconss; ++c )
5733    {
5734       assert(conss[c] != NULL);  /*lint !e613*/
5735 
5736       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
5737       assert(consdata != NULL);
5738 
5739       /* free nonlinear row representation */
5740       if( consdata->nlrow != NULL )
5741       {
5742          SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
5743       }
5744    }
5745 
5746    return SCIP_OKAY;
5747 }
5748 
5749 /** frees specific constraint data */
5750 static
SCIP_DECL_CONSDELETE(consDeleteAbspower)5751 SCIP_DECL_CONSDELETE(consDeleteAbspower)
5752 {  /*lint --e{715}*/
5753    assert(scip != NULL);
5754    assert(conshdlr != NULL);
5755    assert(cons != NULL);
5756    assert(consdata != NULL);
5757    assert((*consdata)->x != NULL);
5758    assert((*consdata)->z != NULL);
5759    assert((*consdata)->xeventfilterpos == -1);
5760    assert((*consdata)->zeventfilterpos == -1);
5761 
5762    if( (*consdata)->nlrow != NULL )
5763    {
5764       SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
5765    }
5766 
5767    SCIPfreeBlockMemory(scip, consdata);
5768 
5769    return SCIP_OKAY;
5770 }
5771 
5772 /** transforms constraint data into data belonging to the transformed problem */
5773 static
SCIP_DECL_CONSTRANS(consTransAbspower)5774 SCIP_DECL_CONSTRANS(consTransAbspower)
5775 {  /*lint --e{715}*/
5776    SCIP_CONSDATA* sourcedata;
5777    SCIP_CONSDATA* targetdata;
5778 
5779    sourcedata = SCIPconsGetData(sourcecons);
5780    assert(sourcedata != NULL);
5781 
5782    SCIP_CALL( SCIPduplicateBlockMemory(scip, &targetdata, sourcedata) );
5783    assert(targetdata->xeventfilterpos == -1);
5784    assert(targetdata->zeventfilterpos == -1);
5785 
5786    SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->x, &targetdata->x) );
5787    SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->z, &targetdata->z) );
5788 
5789    /* branching on multiaggregated variables does not seem to work well, so avoid multiagg. x */
5790    assert( SCIPvarIsActive(targetdata->x) );
5791    SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, targetdata->x) );
5792 
5793    /* cannot propagate on multiaggregated vars, so avoid multiagg. z */
5794    assert( SCIPvarIsActive(targetdata->z) );
5795    SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, targetdata->z) );
5796 
5797    /* create target constraint */
5798    SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
5799          SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
5800          SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),  SCIPconsIsLocal(sourcecons),
5801          SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
5802          SCIPconsIsStickingAtNode(sourcecons)) );
5803 
5804    return SCIP_OKAY;
5805 }
5806 
5807 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved)
5808  *
5809  * we add secant underestimators
5810  */
5811 static
SCIP_DECL_CONSINITLP(consInitlpAbspower)5812 SCIP_DECL_CONSINITLP(consInitlpAbspower)
5813 {  /*lint --e{715}*/
5814    SCIP_CONSDATA*     consdata;
5815    SCIP_CONSHDLRDATA* conshdlrdata;
5816    SCIP_ROWPREP*      rowprep = NULL;
5817    SCIP_ROW*          row = NULL;
5818    int                c;
5819    SCIP_Real          xlb;
5820    SCIP_Real          xub;
5821    SCIP_Real          coefrange;
5822 
5823    assert(scip  != NULL);
5824    assert(conshdlr != NULL);
5825    assert(conss != NULL || nconss == 0);
5826 
5827    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5828    assert(conshdlrdata != NULL);
5829 
5830    *infeasible = FALSE;
5831 
5832    for( c = 0; c < nconss && !(*infeasible); ++c )
5833    {
5834       assert(conss[c] != NULL);  /*lint !e613*/
5835 
5836       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
5837       assert(consdata != NULL);
5838 
5839       xlb = SCIPvarGetLbGlobal(consdata->x);
5840       xub = SCIPvarGetUbGlobal(consdata->x);
5841 
5842       if( SCIPisRelEQ(scip, xlb, xub) )
5843          continue;
5844 
5845       if( !SCIPisInfinity(scip,  consdata->rhs) )
5846       {
5847          if( !SCIPisInfinity(scip, -xlb) )
5848          {
5849             if( SCIPisNegative(scip, xlb + consdata->xoffset) )
5850             {
5851                /* generate secant between xlb and right changepoint */
5852                SCIP_CALL( generateSecantCutNoCheck(scip, &rowprep, xlb, MIN(-consdata->root * (xlb+consdata->xoffset) - consdata->xoffset, xub),
5853                      consdata->exponent, consdata->xoffset, consdata->power, 1.0, consdata->zcoef, consdata->rhs, consdata->x, consdata->z) );
5854                if( rowprep != NULL )
5855                {
5856                   SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5857                   if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5858                   {
5859                      SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5860 
5861                      assert(!(*infeasible));
5862                      SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5863 
5864                      if( conshdlrdata->conshdlrindicator != NULL && !SCIProwIsLocal(row) )
5865                      {
5866                         SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5867                      }
5868                      SCIP_CALL( SCIPreleaseRow(scip, &row) );
5869                   }
5870                   SCIPfreeRowprep(scip, &rowprep);
5871                }
5872             }
5873             else if( xlb < INITLPMAXVARVAL )
5874             {
5875                /* generate tangent in lower bound */
5876                SCIP_CALL( generateLinearizationCut(scip, &rowprep, conshdlr, xlb, consdata->exponent, consdata->xoffset, 1.0, consdata->zcoef, consdata->rhs,
5877                      consdata->x, consdata->z, FALSE) );
5878                assert(rowprep != NULL);
5879 
5880                SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5881                if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5882                {
5883                   SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5884 
5885                   assert(!(*infeasible));
5886                   SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5887 
5888                   if( conshdlrdata->conshdlrindicator != NULL )
5889                   {
5890                      SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5891                   }
5892                   SCIP_CALL( SCIPreleaseRow(scip, &row) );
5893                }
5894                SCIPfreeRowprep(scip, &rowprep);
5895             }
5896          }
5897 
5898          if( !(*infeasible) && !SCIPisInfinity(scip, xub) )
5899          {
5900             /* generate tangent in upper bound */
5901             if( -consdata->root * (xlb+consdata->xoffset) - consdata->xoffset < xub && xub <= INITLPMAXVARVAL )
5902             {
5903                SCIP_CALL( generateLinearizationCut(scip, &rowprep, conshdlr, xub, consdata->exponent, consdata->xoffset, 1.0, consdata->zcoef, consdata->rhs,
5904                      consdata->x, consdata->z, FALSE) );
5905                assert(rowprep != NULL);
5906 
5907                SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5908                if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5909                {
5910                   SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5911 
5912                   assert(!(*infeasible));
5913                   SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5914 
5915                   if( conshdlrdata->conshdlrindicator != NULL )
5916                   {
5917                      SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5918                   }
5919                   SCIP_CALL( SCIPreleaseRow(scip, &row) );
5920                }
5921                SCIPfreeRowprep(scip, &rowprep);
5922             }
5923          }
5924       }
5925 
5926       if( !(*infeasible) && !SCIPisInfinity(scip, -consdata->lhs) )
5927       {
5928          if( !SCIPisInfinity(scip, xub) )
5929          {
5930             if( SCIPisPositive(scip, xub + consdata->xoffset) )
5931             {
5932                /* generate secant between left change point and upper bound */
5933                SCIP_CALL( generateSecantCutNoCheck(scip, &rowprep, -xub, MIN(consdata->root * (xub+consdata->xoffset) + consdata->xoffset, -xlb),
5934                      consdata->exponent, -consdata->xoffset, consdata->power, -1.0, -consdata->zcoef, -consdata->lhs, consdata->x, consdata->z) );
5935                if( rowprep != NULL )
5936                {
5937                   SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5938                   if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5939                   {
5940                      SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5941 
5942                      assert(!(*infeasible));
5943                      SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5944 
5945                      if( conshdlrdata->conshdlrindicator != NULL && !SCIProwIsLocal(row) )
5946                      {
5947                         SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5948                      }
5949                      SCIP_CALL( SCIPreleaseRow(scip, &row) );
5950                   }
5951                   SCIPfreeRowprep(scip, &rowprep);
5952                }
5953             }
5954             else if( xub >= -INITLPMAXVARVAL )
5955             {
5956                /* generate tangent in upper bound */
5957                SCIP_CALL( generateLinearizationCut(scip, &rowprep, conshdlr, -xub, consdata->exponent, -consdata->xoffset, -1.0, -consdata->zcoef, -consdata->lhs,
5958                      consdata->x, consdata->z, FALSE) );
5959                assert(rowprep != NULL);
5960 
5961                SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5962                if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5963                {
5964                   SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5965 
5966                   assert(!(*infeasible));
5967                   SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5968 
5969                   if( conshdlrdata->conshdlrindicator != NULL )
5970                   {
5971                      SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5972                   }
5973                   SCIP_CALL( SCIPreleaseRow(scip, &row) );
5974                }
5975                SCIPfreeRowprep(scip, &rowprep);
5976             }
5977          }
5978 
5979          if( !(*infeasible) && !SCIPisInfinity(scip, -xlb) )
5980          {
5981             /* generate tangent in lower bound */
5982             if( -consdata->root * (xub+consdata->xoffset) - consdata->xoffset > xlb && xlb >= -INITLPMAXVARVAL )
5983             {
5984                SCIP_CALL( generateLinearizationCut(scip, &rowprep, conshdlr, -xlb, consdata->exponent, -consdata->xoffset, -1.0, -consdata->zcoef, -consdata->lhs,
5985                      consdata->x, consdata->z, FALSE) );
5986                assert(rowprep != NULL);
5987 
5988                SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, NULL, conshdlrdata->cutmaxrange, -SCIPinfinity(scip), &coefrange, NULL) );
5989                if( coefrange < conshdlrdata->cutmaxrange && !SCIPisInfinity(scip, REALABS(rowprep->side)) )
5990                {
5991                   SCIP_CALL( SCIPgetRowprepRowConshdlr(scip, &row, rowprep, conshdlr) );
5992 
5993                   assert(!(*infeasible));
5994                   SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
5995 
5996                   if( conshdlrdata->conshdlrindicator != NULL )
5997                   {
5998                      SCIP_CALL( SCIPaddRowIndicator(scip, conshdlrdata->conshdlrindicator, row) );
5999                   }
6000                   SCIP_CALL( SCIPreleaseRow(scip, &row) );
6001                }
6002                SCIPfreeRowprep(scip, &rowprep);
6003             }
6004          }
6005       }
6006    }
6007 
6008    return SCIP_OKAY;
6009 }
6010 
6011 /** separation method of constraint handler for LP solutions */
6012 static
SCIP_DECL_CONSSEPALP(consSepalpAbspower)6013 SCIP_DECL_CONSSEPALP(consSepalpAbspower)
6014 {  /*lint --e{715}*/
6015    SCIP_CONSHDLRDATA* conshdlrdata;
6016    SCIP_CONS*         maxviolcon;
6017    SCIP_Bool          success;
6018    SCIP_Bool          cutoff;
6019    SCIP_Bool          solviolbounds;
6020 
6021    assert(scip     != NULL);
6022    assert(conshdlr != NULL);
6023    assert(conss    != NULL || nconss == 0);
6024    assert(result   != NULL);
6025 
6026    *result = SCIP_DIDNOTFIND;
6027 
6028    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6029    assert(conshdlrdata != NULL);
6030 
6031    SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
6032 
6033    /* if LP solution is (temporarily) outside bounds, then don't try to separate it */
6034    if( solviolbounds )
6035       return SCIP_OKAY;
6036 
6037    /* if no violation, then nothing to separate */
6038    if( maxviolcon == NULL )
6039       return SCIP_OKAY;
6040 
6041    /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
6042     * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
6043     */
6044    if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
6045       (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
6046       SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
6047    {
6048       SCIP_CONSDATA*  consdata;
6049       SCIP_NLPSOLSTAT solstat;
6050       SCIP_Bool       solvednlp;
6051       int c;
6052 
6053       solstat = SCIPgetNLPSolstat(scip);
6054       solvednlp = FALSE;
6055       if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
6056       {
6057          /* NLP is not solved yet, so we might want to do this
6058           * but first check whether there is a violated constraint side which corresponds to a convex function
6059           * @todo put this check into initsol and update via consenable/consdisable
6060           */
6061          for( c = 0; c < nconss; ++c )
6062          {
6063             assert(conss[c] != NULL);  /*lint !e613*/
6064 
6065             consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
6066             assert(consdata != NULL);
6067 
6068             /* skip feasible constraints */
6069             if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6070                continue;
6071 
6072             if( (!SCIPisGT(scip, SCIPvarGetUbGlobal(consdata->x), -consdata->xoffset) && !SCIPisInfinity(scip, -consdata->lhs)) ||
6073                ( !SCIPisLT(scip, SCIPvarGetLbGlobal(consdata->x), -consdata->xoffset) && !SCIPisInfinity(scip, -consdata->rhs)) )
6074                break;
6075          }
6076 
6077          if( c < nconss )
6078          {
6079             /* try to solve NLP and update solstat */
6080 
6081             /* ensure linear conss are in NLP */
6082             if( conshdlrdata->subnlpheur != NULL )
6083             {
6084                SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
6085             }
6086 
6087             /* set LP solution as starting values, if available */
6088             if( SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6089             {
6090                SCIP_CALL( SCIPsetNLPInitialGuessSol(scip, NULL) );
6091             }
6092 
6093             /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
6094             SCIP_CALL( SCIPsolveNLP(scip) );
6095 
6096             solstat = SCIPgetNLPSolstat(scip);
6097             SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
6098 
6099             solvednlp = TRUE;
6100          }
6101       }
6102 
6103       conshdlrdata->sepanlp = TRUE;
6104 
6105       if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
6106       {
6107          SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
6108          *result = SCIP_CUTOFF;
6109          return SCIP_OKAY;
6110       }
6111 
6112       if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
6113       {
6114          /* if we have feasible NLP solution, generate linearization cuts there */
6115          SCIP_Bool lpsolseparated;
6116          SCIP_SOL* nlpsol;
6117 
6118          SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
6119          assert(nlpsol != NULL);
6120 
6121          /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
6122          if( solvednlp && conshdlrdata->trysolheur != NULL )
6123          {
6124             int nfracvars;
6125 
6126             nfracvars = 0;
6127             if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
6128             {
6129                SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
6130             }
6131 
6132             if( nfracvars == 0 )
6133             {
6134                SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
6135             }
6136          }
6137 
6138          SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
6139 
6140          SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
6141 
6142          /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
6143          if( lpsolseparated )
6144          {
6145             SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
6146 
6147             *result = SCIP_SEPARATED;
6148 
6149             return SCIP_OKAY;
6150          }
6151       }
6152    }
6153    /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
6154     * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
6155     */
6156 
6157    SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, conshdlrdata->sepainboundsonly, &success, &cutoff, NULL) );
6158    if( cutoff )
6159       *result = SCIP_CUTOFF;
6160    else if( success )
6161       *result = SCIP_SEPARATED;
6162 
6163    return SCIP_OKAY;
6164 }
6165 
6166 /** separation method of constraint handler for arbitrary primal solutions */
6167 static
SCIP_DECL_CONSSEPASOL(consSepasolAbspower)6168 SCIP_DECL_CONSSEPASOL(consSepasolAbspower)
6169 {  /*lint --e{715}*/
6170    SCIP_CONS*         maxviolcon;
6171    SCIP_Bool          success;
6172    SCIP_Bool          cutoff;
6173    SCIP_Bool          solviolbounds;
6174 
6175    assert(scip     != NULL);
6176    assert(conshdlr != NULL);
6177    assert(conss    != NULL || nconss == 0);
6178    assert(sol      != NULL);
6179    assert(result   != NULL);
6180 
6181    *result = SCIP_DIDNOTFIND;
6182 
6183    SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
6184 
6185    /* if solution is not even within bounds, then don't bother trying to separate it */
6186    if( solviolbounds )
6187       return SCIP_OKAY;
6188 
6189    /* if nothing violated, then nothing to separate */
6190    if( maxviolcon == NULL )
6191       return SCIP_OKAY;
6192 
6193    SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, FALSE, &success, &cutoff, NULL) );
6194    if( cutoff )
6195       *result = SCIP_CUTOFF;
6196    else if( success )
6197       *result = SCIP_SEPARATED;
6198 
6199    return SCIP_OKAY;
6200 }
6201 
6202 /** constraint enforcing method of constraint handler for LP solutions */
6203 static
SCIP_DECL_CONSENFOLP(consEnfolpAbspower)6204 SCIP_DECL_CONSENFOLP(consEnfolpAbspower)
6205 {  /*lint --e{715}*/
6206    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
6207 
6208    return SCIP_OKAY;
6209 }
6210 
6211 /** constraint enforcing method of constraint handler for relaxation solutions */
6212 static
SCIP_DECL_CONSENFORELAX(consEnforelaxAbspower)6213 SCIP_DECL_CONSENFORELAX(consEnforelaxAbspower)
6214 {  /*lint --e{715}*/
6215    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
6216 
6217    return SCIP_OKAY;
6218 }
6219 
6220 /** constraint enforcing method of constraint handler for pseudo solutions */
6221 static
SCIP_DECL_CONSENFOPS(consEnfopsAbspower)6222 SCIP_DECL_CONSENFOPS(consEnfopsAbspower)
6223 {  /*lint --e{715}*/
6224    SCIP_CONSHDLRDATA* conshdlrdata;
6225    SCIP_CONS*         maxviolcon;
6226    SCIP_CONSDATA*     consdata;
6227    int                c;
6228    int                nnotify;
6229    SCIP_Bool          solviolbounds;
6230 
6231    assert(scip != NULL);
6232    assert(conshdlr != NULL);
6233    assert(conss != NULL || nconss == 0);
6234 
6235    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6236    assert(conshdlrdata != NULL);
6237 
6238    SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
6239 
6240    assert(!solviolbounds); /* the pseudo-solution should be within bounds by definition */
6241 
6242    if( maxviolcon == NULL )
6243    {
6244       *result = SCIP_FEASIBLE;
6245       return SCIP_OKAY;
6246    }
6247 
6248    *result = SCIP_INFEASIBLE;
6249 
6250    /* run domain propagation for violated constraints */
6251    for( c = 0; c < nconss; ++c )
6252    {
6253       SCIP_Bool cutoff;
6254       int       nchgbds;
6255       int       naddconss;
6256 
6257       assert(conss[c] != NULL);  /*lint !e613*/
6258 
6259       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
6260       assert(consdata != NULL);
6261 
6262       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6263          continue;
6264 
6265       nchgbds = 0;
6266       naddconss = 0;
6267       SCIP_CALL( propagateCons(scip, conshdlr, conss[c], TRUE, &cutoff, &nchgbds, &naddconss) );  /*lint !e613*/
6268       if( cutoff )
6269       {
6270          *result = SCIP_CUTOFF;
6271          return SCIP_OKAY;
6272       }
6273       if( nchgbds )
6274          *result = SCIP_REDUCEDDOM;
6275       if( naddconss )
6276          *result = SCIP_CONSADDED;
6277    }
6278    if( *result == SCIP_REDUCEDDOM || *result == SCIP_CONSADDED )
6279       return SCIP_OKAY;
6280 
6281    /* we are not feasible and we cannot proof that the whole node is infeasible
6282     * -> branch on all unfixed variables in violated constraints
6283     */
6284    nnotify = 0;
6285    for( c = 0; c < nconss; ++c )
6286    {
6287       assert(conss != NULL);
6288       consdata = SCIPconsGetData(conss[c]);
6289       assert(consdata != NULL);
6290       SCIPdebugMsg(scip, "cons <%s> violation: %g %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
6291 
6292       if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6293          continue;
6294 
6295       SCIPdebugMsg(scip, "cons <%s> violation: %g %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
6296 
6297       /* domain propagation should have removed cons when x is fixed */
6298       assert(!SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->x), SCIPvarGetUbLocal(consdata->x)));
6299 
6300       SCIP_CALL( SCIPaddExternBranchCand(scip, consdata->x, consdata->lhsviol + consdata->rhsviol, proposeBranchingPoint(scip, conss[c], NULL, conshdlrdata->preferzerobranch, conshdlrdata->branchminconverror)) );
6301       ++nnotify;
6302    }
6303 
6304    if( nnotify == 0 )
6305    {
6306       SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
6307       *result = SCIP_SOLVELP;
6308    }
6309 
6310    assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
6311    return SCIP_OKAY;
6312 }
6313 
6314 
6315 /** domain propagation method of constraint handler */
6316 static
SCIP_DECL_CONSPROP(consPropAbspower)6317 SCIP_DECL_CONSPROP(consPropAbspower)
6318 {  /*lint --e{715}*/
6319    int         c;
6320    int         nchgbds;
6321    int         naddconss;
6322    SCIP_Bool   cutoff = FALSE;
6323 
6324    assert(scip     != NULL);
6325    assert(conshdlr != NULL);
6326    assert(conss    != NULL || nconss == 0);
6327    assert(result   != NULL);
6328 
6329    *result = SCIP_DIDNOTFIND;
6330 
6331    for( c = 0; c < nmarkedconss; ++c )
6332    {
6333       assert(conss != NULL);
6334 
6335       /* propagate constraint, but do not allow to add a constraint for tightening a multiaggregated variable (not allowed in CONSPROP) */
6336       nchgbds = 0;
6337       naddconss = 0;
6338       SCIP_CALL( propagateCons(scip, conshdlr, conss[c], FALSE, &cutoff, &nchgbds, &naddconss) );
6339       assert(naddconss == 0);
6340 
6341       if( cutoff )
6342       {
6343          *result = SCIP_CUTOFF;
6344          break;
6345       }
6346 
6347       if( nchgbds )
6348          *result = SCIP_REDUCEDDOM;
6349 
6350       if( c >= nusefulconss && *result != SCIP_DIDNOTFIND )
6351          break;
6352    }
6353 
6354    return SCIP_OKAY;
6355 }
6356 
6357 /** presolving method of constraint handler */
6358 static
SCIP_DECL_CONSPRESOL(consPresolAbspower)6359 SCIP_DECL_CONSPRESOL(consPresolAbspower)
6360 {  /*lint --e{715}*/
6361    SCIP_CONSHDLRDATA* conshdlrdata;
6362    SCIP_CONSDATA* consdata;
6363    SCIP_RESULT    replaceresult;
6364    SCIP_Bool      success;
6365    SCIP_Bool      infeas;
6366    int            localnchgbds;
6367    int            localnaddconss;
6368    int            c;
6369 
6370    assert(scip   != NULL);
6371    assert(conss  != NULL || nconss == 0);
6372    assert(result != NULL);
6373 
6374    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6375    assert(conshdlrdata != NULL);
6376 
6377    *result = SCIP_DIDNOTFIND;
6378 
6379    /* check for duplicates, if not done yet or if absolute power constraints were modified (variable fixings) or new absolute power constraints had been added */
6380    if( !conshdlrdata->comparedpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
6381    {
6382       SCIP_CALL( presolveFindDuplicates(scip, conshdlr, conss, nconss, nupgdconss, ndelconss, naddconss, nfixedvars, naggrvars, &success, &infeas) );
6383       if( infeas )
6384       {
6385          *result = SCIP_CUTOFF;
6386          return SCIP_OKAY;
6387       }
6388       if( success )
6389          *result = SCIP_SUCCESS;
6390 
6391       conshdlrdata->comparedpairwise = TRUE;
6392 
6393       return SCIP_OKAY;
6394    }
6395 
6396    for( c = 0; c < nconss; ++c )
6397    {
6398       assert(conss[c] != NULL);  /*lint !e613*/
6399 
6400       if( SCIPconsIsDeleted(conss[c]) )  /*lint !e613*/
6401          continue;
6402 
6403       consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
6404       assert(consdata != NULL);
6405 
6406       SCIPdebugMsg(scip, "presolving constraint <%s>\n", SCIPconsGetName(conss[c]));  /*lint !e613*/
6407       SCIPdebugPrintCons(scip, conss[c], NULL);  /*lint !e613*/
6408 
6409       /* check if we can upgrade to a linear constraint */
6410       if( consdata->exponent == 1.0 )
6411       {
6412          SCIP_VAR*  vars[2];
6413          SCIP_Real  coefs[2];
6414          SCIP_CONS* lincons;
6415          SCIP_Real  lhs;
6416          SCIP_Real  rhs;
6417 
6418          vars[0] = consdata->x;
6419          vars[1] = consdata->z;
6420          coefs[0] = 1.0;
6421          coefs[1] = consdata->zcoef;
6422          lhs = consdata->lhs;
6423          rhs = consdata->rhs;
6424          if( !SCIPisInfinity(scip, -lhs) )
6425             lhs -= consdata->xoffset;
6426          if( !SCIPisInfinity(scip,  rhs) )
6427             rhs -= consdata->xoffset;
6428 
6429          SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(conss[c]), 2, vars, coefs, lhs, rhs,
6430                SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
6431                SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]),  SCIPconsIsLocal(conss[c]),
6432                SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
6433                SCIPconsIsStickingAtNode(conss[c])) );  /*lint !e613*/
6434          SCIP_CALL( SCIPaddCons(scip, lincons) );
6435          SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
6436 
6437          SCIP_CALL( SCIPdelCons(scip, conss[c]) );  /*lint !e613*/
6438          ++*nupgdconss;
6439          continue;
6440       }
6441 
6442       /* check for fixed variables */
6443       replaceresult = SCIP_DIDNOTFIND;
6444       SCIP_CALL( checkFixedVariables(scip, conshdlr, conss[c], ndelconss, nupgdconss, nchgbds, nfixedvars, &replaceresult) );  /*lint !e613*/
6445       switch( replaceresult )
6446       {
6447       case SCIP_DIDNOTFIND:
6448          break;
6449 
6450       case SCIP_CUTOFF:
6451          *result = SCIP_CUTOFF;
6452          return SCIP_OKAY;
6453 
6454       case SCIP_REDUCEDDOM:
6455       case SCIP_CONSADDED:
6456          *result = SCIP_SUCCESS;
6457          break;
6458 
6459       default:
6460          SCIPerrorMessage("invalid result from checkFixedVariables\n");
6461          SCIPABORT();
6462          return SCIP_INVALIDDATA;  /*lint !e527*/
6463       }  /*lint !e788*/
6464 
6465       if( SCIPconsIsDeleted(conss[c]) )  /*lint !e613*/
6466       {
6467          *result = SCIP_SUCCESS;
6468          continue;
6469       }
6470 
6471       /* another check for upgrading to a varbound constraint */
6472       if( SCIPvarIsBinary(consdata->x) )
6473       {
6474          SCIP_CONS* lincons;
6475          SCIP_Real lhs;
6476          SCIP_Real rhs;
6477          SCIP_Real zcoef;
6478 
6479          /* for binary variable x,
6480           * sign(x+offset)|x+offset|^n = sign(offset)|offset|^n * (1-x) + sign(offset+1) |offset+1|^n x
6481           *                            = sign(offset)|offset|^n + (sign(offset+1) |offset+1|^n - sign(offset)|offset|^n) * x
6482           * => constraint is lhs <= sign(offset)|offset|^n + (sign(offset+1) |offset+1|^n - sign(offset)|offset|^n) * x + c*z <= rhs
6483           * upgrade to varbound constraint if z is not continuous, otherwise linear
6484           */
6485          if( consdata->xoffset != 0.0 )
6486          {
6487             SCIP_Real xcoef;
6488 
6489             xcoef = SIGN(consdata->xoffset + 1.0) * consdata->power(ABS(consdata->xoffset + 1.0), consdata->exponent)
6490                    -SIGN(consdata->xoffset)       * consdata->power(ABS(consdata->xoffset),       consdata->exponent);
6491 
6492             if( xcoef < 0.0 )
6493             {
6494                if( SCIPisInfinity(scip, consdata->rhs) )
6495                   lhs = -SCIPinfinity(scip);
6496                else
6497                   lhs = (consdata->rhs - SIGN(consdata->xoffset) * consdata->power(ABS(consdata->xoffset), consdata->exponent)) / xcoef;
6498                if( SCIPisInfinity(scip, -consdata->lhs) )
6499                   rhs =  SCIPinfinity(scip);
6500                else
6501                   rhs = (consdata->lhs - SIGN(consdata->xoffset) * consdata->power(ABS(consdata->xoffset), consdata->exponent)) / xcoef;
6502             }
6503             else
6504             {
6505                if( SCIPisInfinity(scip, -consdata->lhs) )
6506                   lhs = -SCIPinfinity(scip);
6507                else
6508                   lhs = (consdata->lhs - SIGN(consdata->xoffset) * consdata->power(ABS(consdata->xoffset), consdata->exponent)) / xcoef;
6509                if( SCIPisInfinity(scip,  consdata->rhs) )
6510                   rhs =  SCIPinfinity(scip);
6511                else
6512                   rhs = (consdata->rhs - SIGN(consdata->xoffset) * consdata->power(ABS(consdata->xoffset), consdata->exponent)) / xcoef;
6513             }
6514             zcoef = consdata->zcoef / xcoef;
6515 
6516             /* avoid numerical troubles if xcoef is too large */
6517             if( SCIPisZero(scip, zcoef) )
6518                zcoef = 0.0;
6519          }
6520          else
6521          {
6522             lhs = consdata->lhs;
6523             rhs = consdata->rhs;
6524             zcoef = consdata->zcoef;
6525          }
6526 
6527          /* the upgraded constraint reduces to lhs <= x <= rhs, try to fix x instead of creating a constraint */
6528          if( SCIPisZero(scip, zcoef) && SCIPisEQ(scip, lhs, rhs) )
6529          {
6530             /* both sides are integral */
6531             if( SCIPisIntegral(scip, lhs) )
6532             {
6533                SCIP_Bool fixed;
6534 
6535                assert(SCIPisIntegral(scip, rhs));
6536 
6537                SCIP_CALL( SCIPfixVar(scip, consdata->x, lhs, &infeas, &fixed) );
6538 
6539                /* fixing x to lhs is infeasible */
6540                if( infeas || !fixed )
6541                {
6542                   SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
6543                         SCIPconsGetName(conss[c]));  /*lint !e613*/
6544                   *result = SCIP_CUTOFF;
6545                   return SCIP_OKAY;
6546                }
6547 
6548                ++(*nfixedvars);
6549                break;
6550             }
6551             else
6552             {
6553                /* an integer variables cannot be fixed to a fractional value */
6554                SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
6555                      SCIPconsGetName(conss[c]));  /*lint !e613*/
6556                *result = SCIP_CUTOFF;
6557                return SCIP_OKAY;
6558             }
6559          }
6560 
6561          if( SCIPvarGetType(consdata->z) < SCIP_VARTYPE_CONTINUOUS && !SCIPisZero(scip, zcoef)
6562             && SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR )
6563          {
6564             SCIP_CALL( SCIPcreateConsVarbound(scip, &lincons, SCIPconsGetName(conss[c]),
6565                   consdata->x, consdata->z, zcoef, lhs, rhs,
6566                   SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
6567                   SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]),  SCIPconsIsLocal(conss[c]),
6568                   SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
6569                   SCIPconsIsStickingAtNode(conss[c])) );  /*lint !e613*/
6570          }
6571          else
6572          {
6573             SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(conss[c]),
6574                   1, &consdata->z, &zcoef, lhs, rhs,
6575                   SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
6576                   SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]),  SCIPconsIsLocal(conss[c]),
6577                   SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
6578                   SCIPconsIsStickingAtNode(conss[c])) );  /*lint !e613*/
6579             SCIP_CALL( SCIPaddCoefLinear(scip, lincons, consdata->x, 1.0) );
6580          }
6581          SCIP_CALL( SCIPaddCons(scip, lincons) );
6582 
6583          SCIPdebugMsg(scip, "upgraded constraint <%s> to linear constraint due to binary x-variable\n", SCIPconsGetName(conss[c]));  /*lint !e613*/
6584          SCIPdebugPrintCons(scip, conss[c], NULL);  /*lint !e613*/
6585          SCIPdebugPrintCons(scip, lincons, NULL);
6586 
6587          SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
6588 
6589          SCIP_CALL( SCIPdelCons(scip, conss[c]) );  /*lint !e613*/
6590          ++*nupgdconss;
6591          continue;
6592       }
6593 
6594       /* run domain propagation, also checks for redundancy */
6595       localnchgbds = 0;
6596       localnaddconss = 0;
6597       SCIP_CALL( propagateCons(scip, conshdlr, conss[c], TRUE, &infeas, &localnchgbds, &localnaddconss) );  /*lint !e613*/
6598       if( infeas )
6599       {
6600          SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));  /*lint !e613*/
6601          *result = SCIP_CUTOFF;
6602          return SCIP_OKAY;
6603       }
6604       if( localnchgbds > 0 || localnaddconss > 0 )
6605       {
6606          *nchgbds   += localnchgbds;
6607          *naddconss += localnaddconss;
6608          *result = SCIP_SUCCESS;
6609       }
6610       if( SCIPconsIsDeleted(conss[c]) )  /*lint !e613*/
6611       {
6612          ++*ndelconss;
6613          *result = SCIP_SUCCESS;
6614          continue;
6615       }
6616 
6617       if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
6618       {
6619          /* check if a variable can be fixed because it appears in no other constraint */
6620          SCIP_CALL( presolveDual(scip, conss[c], &infeas, ndelconss, nfixedvars) );  /*lint !e613*/
6621          if( infeas )
6622          {
6623             SCIPdebugMsg(scip, "dual presolve on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));  /*lint !e613*/
6624             *result = SCIP_CUTOFF;
6625             return SCIP_OKAY;
6626          }
6627          if( SCIPconsIsDeleted(conss[c]) )  /*lint !e613*/
6628          {
6629             *result = SCIP_SUCCESS;
6630             continue;
6631          }
6632       }
6633 
6634       /* propagate variable bound constraints */
6635       if( !consdata->propvarbounds && SCIPallowWeakDualReds(scip) )
6636       {
6637          SCIP_CALL( propagateVarbounds(scip, conshdlr, conss[c], &infeas, nchgbds, naddconss) );  /*lint !e613*/
6638 
6639          if( infeas )
6640          {
6641             *result = SCIP_CUTOFF;
6642             return SCIP_OKAY;
6643          }
6644 
6645          consdata->propvarbounds = TRUE;
6646       }
6647 
6648       /* check if we can make z implicit integer
6649        * if constraint is signpow(x,n) + c*z = rhs with x integer, |c| = 1, rhs and n integral, then z is implicit integral
6650        */
6651       if( SCIPvarGetType(consdata->z) == SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->x) != SCIP_VARTYPE_CONTINUOUS &&
6652          SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->rhs) && SCIPisEQ(scip, REALABS(consdata->zcoef), 1.0) && SCIPisIntegral(scip, consdata->exponent)
6653          )
6654       {
6655          SCIPdebugMsg(scip, "make z = <%s> implicit integer in cons <%s>\n", SCIPvarGetName(consdata->z), SCIPconsGetName(conss[c]));  /*lint !e613*/
6656          SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
6657          SCIP_CALL( SCIPchgVarType(scip, consdata->z, SCIP_VARTYPE_IMPLINT, &infeas) );
6658          if( infeas )
6659          {
6660             SCIPdebugMsg(scip, "problem found infeasible in presolve when making <%s> implicit integer\n", SCIPvarGetName(consdata->z));
6661             *result = SCIP_CUTOFF;
6662             return SCIP_OKAY;
6663          }
6664          else
6665          {
6666             ++*nchgvartypes;
6667          }
6668       }
6669    }
6670 
6671    return SCIP_OKAY;
6672 }
6673 
6674 /** resolves a propagation on the given variable by supplying the variables needed for applying the corresponding
6675  *  propagation rule (see propagateCons()):
6676  *   (1) left hand side and bounds on z -> lower bound on x
6677  *   (2) left hand side and upper bound on x -> bound on z
6678  *   (3) right hand side and bounds on z -> upper bound on x
6679  *   (4) right hand side and lower bound on x -> bound on z
6680  */
6681 static
SCIP_DECL_CONSRESPROP(consRespropAbspower)6682 SCIP_DECL_CONSRESPROP(consRespropAbspower)
6683 {
6684    assert(result != NULL);
6685 
6686    SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, boundtype, bdchgidx) );
6687 
6688    *result = SCIP_SUCCESS;
6689 
6690    return SCIP_OKAY;
6691 }  /*lint !e715*/
6692 
6693 /** variable rounding lock method of constraint handler */
6694 static
SCIP_DECL_CONSLOCK(consLockAbspower)6695 SCIP_DECL_CONSLOCK(consLockAbspower)
6696 {  /*lint --e{715}*/
6697    SCIP_CONSDATA* consdata;
6698    SCIP_Bool      haslb;
6699    SCIP_Bool      hasub;
6700 
6701    assert(scip != NULL);
6702    assert(cons != NULL);
6703    assert(locktype == SCIP_LOCKTYPE_MODEL);
6704 
6705    consdata = SCIPconsGetData(cons);
6706    assert(consdata != NULL);
6707 
6708    haslb = !SCIPisInfinity(scip, -consdata->lhs);
6709    hasub = !SCIPisInfinity(scip,  consdata->rhs);
6710 
6711    if( consdata->x != NULL )
6712    {
6713       if( haslb )
6714       {
6715          SCIP_CALL( SCIPaddVarLocksType(scip, consdata->x, locktype, nlockspos, nlocksneg) );
6716       }
6717       if( hasub )
6718       {
6719          SCIP_CALL( SCIPaddVarLocksType(scip, consdata->x, locktype, nlocksneg, nlockspos) );
6720       }
6721    }
6722 
6723    if( consdata->z != NULL )
6724    {
6725       if( consdata->zcoef > 0 )
6726       {
6727          if( haslb )
6728          {
6729             SCIP_CALL( SCIPaddVarLocksType(scip, consdata->z, locktype, nlockspos, nlocksneg) );
6730          }
6731          if( hasub )
6732          {
6733             SCIP_CALL( SCIPaddVarLocksType(scip, consdata->z, locktype, nlocksneg, nlockspos) );
6734          }
6735       }
6736       else
6737       {
6738          if( haslb )
6739          {
6740             SCIP_CALL( SCIPaddVarLocksType(scip, consdata->z, locktype, nlocksneg, nlockspos) );
6741          }
6742          if( hasub )
6743          {
6744             SCIP_CALL( SCIPaddVarLocksType(scip, consdata->z, locktype, nlockspos, nlocksneg) );
6745          }
6746       }
6747    }
6748 
6749    return SCIP_OKAY;
6750 }
6751 
6752 /** constraint activation notification method of constraint handler */
6753 static
SCIP_DECL_CONSACTIVE(consActiveAbspower)6754 SCIP_DECL_CONSACTIVE(consActiveAbspower)
6755 {  /*lint --e{715}*/
6756    SCIP_CONSHDLRDATA* conshdlrdata;
6757 
6758    assert(conshdlr != NULL);
6759 
6760    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6761    assert(conshdlrdata != NULL);
6762 
6763    /* (re)run constraint comparison, since new constraint is added */
6764    conshdlrdata->comparedpairwise = FALSE;
6765 
6766    return SCIP_OKAY;
6767 }
6768 
6769 /** constraint enabling notification method of constraint handler */
6770 static
SCIP_DECL_CONSENABLE(consEnableAbspower)6771 SCIP_DECL_CONSENABLE(consEnableAbspower)
6772 {  /*lint --e{715}*/
6773    SCIP_CONSHDLRDATA* conshdlrdata;
6774 
6775    assert(scip != NULL);
6776    assert(cons != NULL);
6777    assert(conshdlr != NULL);
6778 
6779    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6780    assert(conshdlrdata != NULL);
6781    assert(conshdlrdata->eventhdlr != NULL);
6782 
6783    SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
6784 
6785    return SCIP_OKAY;
6786 }
6787 
6788 /** constraint disabling notification method of constraint handler */
6789 static
SCIP_DECL_CONSDISABLE(consDisableAbspower)6790 SCIP_DECL_CONSDISABLE(consDisableAbspower)
6791 {  /*lint --e{715}*/
6792    SCIP_CONSHDLRDATA* conshdlrdata;
6793 
6794    assert(scip != NULL);
6795    assert(cons != NULL);
6796    assert(conshdlr != NULL);
6797 
6798    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6799    assert(conshdlrdata != NULL);
6800    assert(conshdlrdata->eventhdlr != NULL);
6801 
6802    SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
6803 
6804    return SCIP_OKAY;
6805 }
6806 
6807 /** constraint display method of constraint handler */
6808 static
SCIP_DECL_CONSPRINT(consPrintAbspower)6809 SCIP_DECL_CONSPRINT(consPrintAbspower)
6810 {  /*lint --e{715}*/
6811    SCIP_CONSDATA* consdata;
6812 
6813    assert(scip != NULL);
6814    assert(cons != NULL);
6815 
6816    consdata = SCIPconsGetData(cons);
6817    assert(consdata != NULL);
6818 
6819    /* print left hand side for ranged rows */
6820    if( !SCIPisInfinity(scip, -consdata->lhs)
6821       && !SCIPisInfinity(scip, consdata->rhs)
6822       && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
6823       SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
6824 
6825    /* print coefficients and variables */
6826    SCIPinfoMessage(scip, file, "signpower(");
6827    SCIP_CALL( SCIPwriteVarName(scip, file, consdata->x, TRUE) );
6828    SCIPinfoMessage(scip, file, " %+.15g, %.15g) ", consdata->xoffset, consdata->exponent);
6829 
6830    SCIPinfoMessage(scip, file, "%+.15g", consdata->zcoef);
6831    SCIP_CALL( SCIPwriteVarName(scip, file, consdata->z, TRUE) );
6832 
6833    /* print right hand side */
6834    if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
6835    {
6836       SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
6837    }
6838    else if( !SCIPisInfinity(scip, consdata->rhs) )
6839    {
6840       SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
6841    }
6842    else if( !SCIPisInfinity(scip, -consdata->lhs) )
6843    {
6844       SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
6845    }
6846    else
6847    {
6848       SCIPinfoMessage(scip, file, " [free]");
6849    }
6850 
6851    return SCIP_OKAY;
6852 }
6853 
6854 /** feasibility check method of constraint handler for integral solutions */
6855 static
SCIP_DECL_CONSCHECK(consCheckAbspower)6856 SCIP_DECL_CONSCHECK(consCheckAbspower)
6857 {  /*lint --e{715}*/
6858    SCIP_CONSHDLRDATA* conshdlrdata;
6859    SCIP_CONSDATA*     consdata;
6860    SCIP_Bool          dolinfeasshift;
6861    SCIP_Bool          solviolbounds;
6862    SCIP_Real          maxviol;
6863    SCIP_Real          viol;
6864    int                c;
6865 
6866    assert(scip   != NULL);
6867    assert(conss  != NULL || nconss == 0);
6868    assert(result != NULL);
6869 
6870    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6871    assert(conshdlrdata != NULL);
6872 
6873    *result = SCIP_FEASIBLE;
6874 
6875    maxviol = 0.0;
6876    viol = SCIP_INVALID;
6877 
6878    dolinfeasshift = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) && SCIPgetStage(scip) > SCIP_STAGE_PROBLEM && SCIPgetStage(scip) < SCIP_STAGE_SOLVED;
6879    for( c = 0; c < nconss; ++c )
6880    {
6881       assert(conss != NULL);
6882       SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &viol, &solviolbounds) );
6883 
6884       assert(!solviolbounds); /* see also issue #627 */
6885 
6886       consdata = SCIPconsGetData(conss[c]);
6887       assert(consdata != NULL);
6888 
6889       if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6890       {
6891          *result = SCIP_INFEASIBLE;
6892 
6893          if( printreason )
6894          {
6895             SCIPinfoMessage(scip, NULL, "absolute power constraint <%s> violated by %g\n\t",
6896                SCIPconsGetName(conss[c]), viol);
6897             SCIP_CALL( consPrintAbspower(scip, conshdlr, conss[c], NULL) );
6898             SCIPinfoMessage(scip, NULL, ";\n");
6899          }
6900 
6901          if( conshdlrdata->subnlpheur == NULL && !dolinfeasshift && !completely )
6902             return SCIP_OKAY;
6903          if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
6904             maxviol = MAX(consdata->lhsviol, consdata->rhsviol);
6905       }
6906    }
6907 
6908    if( *result == SCIP_INFEASIBLE && dolinfeasshift )
6909    {
6910       SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol) );
6911    }
6912 
6913    if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
6914    {
6915       SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
6916    }
6917 
6918    return SCIP_OKAY;
6919 }
6920 
6921 /** constraint copying method of constraint handler */
6922 static
SCIP_DECL_CONSCOPY(consCopyAbspower)6923 SCIP_DECL_CONSCOPY(consCopyAbspower)
6924 {  /*lint --e{715}*/
6925    SCIP_CONSDATA* consdata;
6926    SCIP_VAR*      x;
6927    SCIP_VAR*      z;
6928 
6929    assert(scip != NULL);
6930    assert(cons != NULL);
6931    assert(sourcescip != NULL);
6932    assert(sourcecons != NULL);
6933    assert(varmap != NULL);
6934    assert(valid != NULL);
6935 
6936    consdata = SCIPconsGetData(sourcecons);
6937    assert(consdata != NULL);
6938 
6939    *valid = TRUE;
6940    *cons  = NULL;
6941 
6942    SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->x, &x, varmap, consmap, global, valid) );
6943 
6944    if( *valid )
6945    {
6946       SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->z, &z, varmap, consmap, global, valid) );
6947 
6948       if( *valid )
6949       {
6950          assert(z != NULL); /* for lint */
6951          SCIP_CALL( SCIPcreateConsAbspower(scip, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
6952                x, z, consdata->exponent, consdata->xoffset, consdata->zcoef, consdata->lhs, consdata->rhs,
6953                initial, separate, enforce, check, propagate, local, FALSE, dynamic, removable, stickingatnode) );  /*lint !e644*/
6954       }
6955    }
6956 
6957    return SCIP_OKAY;
6958 }
6959 
6960 /** constraint parsing method of constraint handler */
6961 static
SCIP_DECL_CONSPARSE(consParseAbspower)6962 SCIP_DECL_CONSPARSE(consParseAbspower)
6963 {
6964    SCIP_Real lhs;
6965    SCIP_Real rhs;
6966    SCIP_Real xoffset;
6967    SCIP_Real exponent;
6968    SCIP_Real zcoef;
6969    SCIP_Real value;
6970    char*     endptr;
6971    char      sense;
6972    SCIP_VAR* x;
6973    SCIP_VAR* z;
6974 
6975    *success = TRUE;
6976 
6977    /* set right hand and left side to their default values */
6978    lhs = -SCIPinfinity(scip);
6979    rhs =  SCIPinfinity(scip);
6980 
6981    SCIPdebugMsg(scip, "start parsing absolute power constraint expression %s\n", str);
6982 
6983    if( strncmp(str, "signpower(", 10) != 0 )
6984    {
6985       /* str does not start with signpower string, so may be left-hand-side of ranged constraint */
6986       if( !SCIPstrToRealValue(str, &lhs, &endptr) )
6987       {
6988          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: left-hand-side or 'signpower(' expected at begin on '%s'\n", str);
6989          *success = FALSE;
6990          return SCIP_OKAY;
6991       }
6992       str = endptr;
6993    }
6994    else
6995    {
6996       str += 10;
6997    }
6998 
6999    /* parse (x +offset, exponent) +coef z */
7000 
7001    /* parse variable name */
7002    SCIP_CALL( SCIPparseVarName(scip, str, &x, &endptr) );
7003    if( x == NULL )
7004    {
7005       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
7006       *success = FALSE;
7007       return SCIP_OKAY;
7008    }
7009    str = endptr;
7010 
7011    /* skip whitespace */
7012    while( isspace((int)*str) )
7013       ++str;
7014 
7015    /* parse offset */
7016    if( !SCIPstrToRealValue(str, &xoffset, &endptr) )
7017    {
7018       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected coefficient at begin of '%s'\n", str);
7019       *success = FALSE;
7020       return SCIP_OKAY;
7021    }
7022    str = endptr;
7023 
7024    if( *str != ',' )
7025    {
7026       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected ',' at begin of '%s'\n", str);
7027       *success = FALSE;
7028       return SCIP_OKAY;
7029    }
7030    ++str;
7031 
7032    /* skip whitespace */
7033    while( isspace((int)*str) )
7034       ++str;
7035 
7036    /* parse exponent */
7037    if( !SCIPstrToRealValue(str, &exponent, &endptr) )
7038    {
7039       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected coefficient at begin of '%s'\n", str);
7040       *success = FALSE;
7041       return SCIP_OKAY;
7042    }
7043    str = endptr;
7044 
7045    if( *str != ')' )
7046    {
7047       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected ')' at begin of '%s'\n", str);
7048       *success = FALSE;
7049       return SCIP_OKAY;
7050    }
7051    ++str;
7052 
7053    /* skip whitespace */
7054    while( isspace((int)*str) )
7055       ++str;
7056 
7057    /* parse coefficient */
7058    if( !SCIPstrToRealValue(str, &zcoef, &endptr) )
7059    {
7060       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected coefficient at begin of '%s'\n", str);
7061       *success = FALSE;
7062       return SCIP_OKAY;
7063    }
7064    str = endptr;
7065 
7066    /* parse variable name */
7067    SCIP_CALL( SCIPparseVarName(scip, str, &z, &endptr) );
7068    if( z == NULL )
7069    {
7070       SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
7071       *success = FALSE;
7072       return SCIP_OKAY;
7073    }
7074    str = endptr;
7075 
7076    /* skip whitespace */
7077    while( isspace((int)*str) )
7078       ++str;
7079 
7080    if( strncmp(str, "[free]", 6) != 0 )
7081    {
7082       /* parse sense */
7083       if( (*str != '<' && *str != '>' && *str != '=') || str[1] != '=' )
7084       {
7085          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected sense at begin of '%s'\n", str);
7086          *success = FALSE;
7087          return SCIP_OKAY;
7088       }
7089       sense = *str;
7090       str += 2;
7091 
7092       /* parse value at rhs */
7093       if( !SCIPstrToRealValue(str, &value, &endptr) )
7094       {
7095          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected rhs value at begin of '%s'\n", str);
7096          *success = FALSE;
7097          return SCIP_OKAY;
7098       }
7099 
7100       switch( sense )
7101       {
7102       case '<' :
7103          rhs = value;
7104          break;
7105       case '>' :
7106          lhs = value;
7107          break;
7108       case '=' :
7109          lhs = rhs = value;
7110          break;
7111       default:
7112          SCIPABORT(); /* checked above that this cannot happen */
7113          return SCIP_INVALIDDATA;  /*lint !e527*/
7114       }
7115    }
7116 
7117    SCIP_CALL( SCIPcreateConsAbspower(scip, cons, name, x, z, exponent, xoffset, zcoef, lhs, rhs,
7118          initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
7119 
7120    return SCIP_OKAY;
7121 }  /*lint !e715*/
7122 
7123 /** constraint method of constraint handler which returns the variables (if possible) */
7124 static
SCIP_DECL_CONSGETVARS(consGetVarsAbspower)7125 SCIP_DECL_CONSGETVARS(consGetVarsAbspower)
7126 {  /*lint --e{715}*/
7127    if( varssize < 2 )
7128       (*success) = FALSE;
7129    else
7130    {
7131       SCIP_CONSDATA* consdata;
7132       assert(cons != NULL);
7133       assert(vars != NULL);
7134 
7135       consdata = SCIPconsGetData(cons);
7136       assert(consdata != NULL);
7137 
7138       vars[0] = consdata->x;
7139       vars[1] = consdata->z;
7140       (*success) = TRUE;
7141    }
7142 
7143    return SCIP_OKAY;
7144 }
7145 
7146 /** constraint method of constraint handler which returns the number of variables (if possible) */
7147 static
SCIP_DECL_CONSGETNVARS(consGetNVarsAbspower)7148 SCIP_DECL_CONSGETNVARS(consGetNVarsAbspower)
7149 {  /*lint --e{715}*/
7150    (*nvars) = 2;
7151    (*success) = TRUE;
7152 
7153    return SCIP_OKAY;
7154 }
7155 
7156 /*
7157  * constraint specific interface methods
7158  */
7159 
7160 /** creates the handler for absolute power constraints and includes it in SCIP */
SCIPincludeConshdlrAbspower(SCIP * scip)7161 SCIP_RETCODE SCIPincludeConshdlrAbspower(
7162    SCIP*                 scip                /**< SCIP data structure */
7163    )
7164 {
7165    SCIP_CONSHDLRDATA* conshdlrdata;
7166    SCIP_CONSHDLR* conshdlr;
7167    SCIP_EVENTHDLR* eventhdlr;
7168 
7169    /* create absolute power constraint handler data */
7170    SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
7171    BMSclearMemory(conshdlrdata);
7172 
7173    /* include constraint handler */
7174    SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
7175          CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
7176          consEnfolpAbspower, consEnfopsAbspower, consCheckAbspower, consLockAbspower,
7177          conshdlrdata) );
7178 
7179    assert(conshdlr != NULL);
7180 
7181    /* set non-fundamental callbacks via specific setter functions */
7182    SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveAbspower) );
7183    SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyAbspower, consCopyAbspower) );
7184    SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteAbspower) );
7185    SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableAbspower) );
7186    SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableAbspower) );
7187    SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitAbspower) );
7188    SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreAbspower) );
7189    SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolAbspower) );
7190    SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeAbspower) );
7191    SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsAbspower) );
7192    SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsAbspower) );
7193    SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitAbspower) );
7194    SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreAbspower) );
7195    SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolAbspower) );
7196    SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpAbspower) );
7197    SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseAbspower) );
7198    SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolAbspower, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7199    SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintAbspower) );
7200    SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropAbspower, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
7201          CONSHDLR_PROP_TIMING) );
7202    SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropAbspower) );
7203    SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpAbspower, consSepasolAbspower, CONSHDLR_SEPAFREQ,
7204          CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
7205    SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransAbspower) );
7206    SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxAbspower) );
7207 
7208    /* include the quadratic constraint upgrade in the quadratic constraint handler */
7209    SCIP_CALL( SCIPincludeQuadconsUpgrade(scip, quadconsUpgdAbspower, QUADCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
7210 
7211    /* include the absolute power constraint upgrade and node reform in the nonlinear constraint handler
7212     * we give it higher priority as quadratic, so it also takes care of x^2 constraints, if possible
7213     */
7214    SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, nonlinconsUpgdAbspower, exprgraphnodeReformAbspower, NONLINCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
7215 
7216    /* add absolute power constraint handler parameters */
7217    SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
7218          "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
7219          &conshdlrdata->cutmaxrange, FALSE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
7220 
7221    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectrefpoint",
7222          "whether to project the reference point when linearizing an absolute power constraint in a convex region",
7223          &conshdlrdata->projectrefpoint, FALSE, TRUE, NULL, NULL) );
7224 
7225    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/preferzerobranch",
7226          "how much to prefer branching on 0.0 when sign of variable is not fixed yet: 0 no preference, 1 prefer if LP solution will be cutoff in both child nodes, 2 prefer always, 3 ensure always",
7227          &conshdlrdata->preferzerobranch, FALSE, 1, 0, 3, NULL, NULL) );
7228 
7229    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchminconverror",
7230          "whether to compute branching point such that the convexification error is minimized (after branching on 0.0)",
7231          &conshdlrdata->branchminconverror, FALSE, FALSE, NULL, NULL) );
7232 
7233    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addvarboundcons",
7234          "should variable bound constraints be added for derived variable bounds?",
7235          &conshdlrdata->addvarboundcons, TRUE, TRUE, NULL, NULL) );
7236 
7237    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
7238          "whether to try to make solutions in check function feasible by shifting the linear variable z",
7239          &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
7240 
7241    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/dualpresolve",
7242          "should dual presolve be applied?",
7243          &conshdlrdata->dualpresolve, FALSE, TRUE, NULL, NULL) );
7244 
7245    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sepainboundsonly",
7246          "whether to separate linearization cuts only in the variable bounds (does not affect enforcement)",
7247          &conshdlrdata->sepainboundsonly, FALSE, FALSE, NULL, NULL) );
7248 
7249    SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
7250          "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
7251          &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
7252 
7253    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
7254          "are cuts added during enforcement removable from the LP in the same node?",
7255          &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
7256 
7257    SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, CONSHDLR_NAME, "signals a bound change on a variable to an absolute power constraint",
7258          processVarEvent, NULL) );
7259    conshdlrdata->eventhdlr = eventhdlr;
7260 
7261    SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
7262          processNewSolutionEvent, NULL) );
7263 
7264    return SCIP_OKAY;
7265 }
7266 
7267 /** creates and captures a absolute power constraint
7268  *
7269  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7270  */
SCIPcreateConsAbspower(SCIP * scip,SCIP_CONS ** cons,const char * name,SCIP_VAR * x,SCIP_VAR * z,SCIP_Real exponent,SCIP_Real xoffset,SCIP_Real zcoef,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)7271 SCIP_RETCODE SCIPcreateConsAbspower(
7272    SCIP*                 scip,               /**< SCIP data structure */
7273    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
7274    const char*           name,               /**< name of constraint */
7275    SCIP_VAR*             x,                  /**< nonlinear variable x in constraint */
7276    SCIP_VAR*             z,                  /**< linear variable z in constraint */
7277    SCIP_Real             exponent,           /**< exponent n of |x+offset|^n term in constraint */
7278    SCIP_Real             xoffset,            /**< offset in |x+offset|^n term in constraint */
7279    SCIP_Real             zcoef,              /**< coefficient of z in constraint */
7280    SCIP_Real             lhs,                /**< left hand side of constraint */
7281    SCIP_Real             rhs,                /**< right hand side of constraint */
7282    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
7283                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
7284    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
7285                                               *   Usually set to TRUE. */
7286    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
7287                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
7288    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
7289                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
7290    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
7291                                               *   Usually set to TRUE. */
7292    SCIP_Bool             local,              /**< is constraint only valid locally?
7293                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7294    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
7295                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
7296                                               *   adds coefficients to this constraint. */
7297    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
7298                                               *   Usually set to FALSE. Set to TRUE for own cuts which
7299                                               *   are seperated as constraints. */
7300    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
7301                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7302    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
7303                                               *   if it may be moved to a more global node?
7304                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7305    )
7306 {
7307    SCIP_CONSHDLR* conshdlr;
7308    SCIP_CONSDATA* consdata;
7309 
7310    assert(x != NULL);
7311    assert(z != NULL);
7312    assert(exponent > 1.0);
7313    assert(!SCIPisZero(scip, zcoef));
7314    assert(!SCIPisInfinity(scip, REALABS(zcoef)));
7315    assert(!modifiable); /* we do not support column generation */
7316 
7317    /* find the absolute power constraint handler */
7318    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7319    if( conshdlr == NULL )
7320    {
7321       SCIPerrorMessage("absolute power constraint handler not found\n");
7322       return SCIP_PLUGINNOTFOUND;
7323    }
7324 
7325    /* create constraint data */
7326    SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
7327    BMSclearMemory(consdata);
7328    consdata->xeventfilterpos = -1;
7329    consdata->zeventfilterpos = -1;
7330 
7331    consdata->x        = x;
7332    consdata->z        = z;
7333    consdata->xoffset  = xoffset;
7334    consdata->zcoef    = zcoef;
7335    consdata->lhs      = lhs;
7336    consdata->rhs      = rhs;
7337 
7338    if( SCIPisEQ(scip, exponent, 2.0) )
7339    {
7340       consdata->exponent = 2.0;
7341       consdata->power    = square;
7342    }
7343    else
7344    {
7345       consdata->exponent = exponent;
7346       consdata->power    = pow;
7347    }
7348 
7349    /* branching on multiaggregated variables does not seem to work well, so try to avoid multiagg. x */
7350    if( SCIPvarIsActive(x) )
7351       SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, x) );
7352 
7353    /* cannot propagate on multiaggregated vars, so avoid multiagg. z */
7354    if( SCIPvarIsActive(z) )
7355       SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, z) );
7356 
7357    /* create constraint */
7358    SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
7359          local, modifiable, dynamic, removable, stickingatnode) );
7360 
7361    return SCIP_OKAY;
7362 }
7363 
7364 /** creates and captures an absolute power constraint
7365  *  in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
7366  *  method SCIPcreateConsAbspower(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
7367  *
7368  *  @see SCIPcreateConsAbspower() for information about the basic constraint flag configuration
7369  *
7370  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7371  */
SCIPcreateConsBasicAbspower(SCIP * scip,SCIP_CONS ** cons,const char * name,SCIP_VAR * x,SCIP_VAR * z,SCIP_Real exponent,SCIP_Real xoffset,SCIP_Real zcoef,SCIP_Real lhs,SCIP_Real rhs)7372 SCIP_RETCODE SCIPcreateConsBasicAbspower(
7373    SCIP*                 scip,               /**< SCIP data structure */
7374    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
7375    const char*           name,               /**< name of constraint */
7376    SCIP_VAR*             x,                  /**< nonlinear variable x in constraint */
7377    SCIP_VAR*             z,                  /**< linear variable z in constraint */
7378    SCIP_Real             exponent,           /**< exponent n of |x+offset|^n term in constraint */
7379    SCIP_Real             xoffset,            /**< offset in |x+offset|^n term in constraint */
7380    SCIP_Real             zcoef,              /**< coefficient of z in constraint */
7381    SCIP_Real             lhs,                /**< left hand side of constraint */
7382    SCIP_Real             rhs                 /**< right hand side of constraint */
7383    )
7384 {
7385    assert(scip != NULL);
7386 
7387    SCIP_CALL( SCIPcreateConsAbspower(scip, cons, name, x, z, exponent, xoffset, zcoef, lhs, rhs,
7388          TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
7389 
7390    return SCIP_OKAY;
7391 }
7392 
7393 /** gets the absolute power constraint as a nonlinear row representation */
SCIPgetNlRowAbspower(SCIP * scip,SCIP_CONS * cons,SCIP_NLROW ** nlrow)7394 SCIP_RETCODE SCIPgetNlRowAbspower(
7395    SCIP*                 scip,               /**< SCIP data structure */
7396    SCIP_CONS*            cons,               /**< constraint */
7397    SCIP_NLROW**          nlrow               /**< a buffer where to store pointer to nonlinear row */
7398    )
7399 {
7400    SCIP_CONSDATA* consdata;
7401 
7402    assert(cons  != NULL);
7403    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7404    assert(nlrow != NULL);
7405 
7406    consdata = SCIPconsGetData(cons);
7407    assert(consdata != NULL);
7408 
7409    if( consdata->nlrow == NULL )
7410    {
7411       SCIP_CALL( createNlRow(scip, cons) );
7412    }
7413    assert(consdata->nlrow != NULL);
7414    *nlrow = consdata->nlrow;
7415 
7416    return SCIP_OKAY;
7417 }
7418 
7419 /** gets nonlinear variable x in absolute power constraint */  /*lint -e715*/
SCIPgetNonlinearVarAbspower(SCIP * scip,SCIP_CONS * cons)7420 SCIP_VAR* SCIPgetNonlinearVarAbspower(
7421    SCIP*                 scip,               /**< SCIP data structure */
7422    SCIP_CONS*            cons                /**< absolute power constraint */
7423    )
7424 {
7425    SCIP_CONSDATA* consdata;
7426 
7427    assert(cons != NULL);
7428    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7429 
7430    consdata = SCIPconsGetData(cons);
7431    assert(consdata != NULL);
7432 
7433    return consdata->x;
7434 }
7435 
7436 /** gets linear variable z in absolute power constraint */  /*lint -e715*/
SCIPgetLinearVarAbspower(SCIP * scip,SCIP_CONS * cons)7437 SCIP_VAR* SCIPgetLinearVarAbspower(
7438    SCIP*                 scip,               /**< SCIP data structure */
7439    SCIP_CONS*            cons                /**< absolute power constraint */
7440    )
7441 {
7442    SCIP_CONSDATA* consdata;
7443 
7444    assert(cons != NULL);
7445    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7446 
7447    consdata = SCIPconsGetData(cons);
7448    assert(consdata != NULL);
7449 
7450    return consdata->z;
7451 }
7452 
7453 /** gets exponent in power term in absolute power constraint */
SCIPgetExponentAbspower(SCIP * scip,SCIP_CONS * cons)7454 SCIP_Real SCIPgetExponentAbspower(
7455    SCIP*                 scip,               /**< SCIP data structure */
7456    SCIP_CONS*            cons                /**< absolute power constraint */
7457    )
7458 {  /*lint --e{715}*/
7459    SCIP_CONSDATA* consdata;
7460 
7461    assert(cons != NULL);
7462    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7463 
7464    consdata = SCIPconsGetData(cons);
7465    assert(consdata != NULL);
7466 
7467    return consdata->exponent;
7468 }
7469 
7470 /** gets offset in power term in absolute power constraint */
SCIPgetOffsetAbspower(SCIP * scip,SCIP_CONS * cons)7471 SCIP_Real SCIPgetOffsetAbspower(
7472    SCIP*                 scip,               /**< SCIP data structure */
7473    SCIP_CONS*            cons                /**< absolute power constraint */
7474    )
7475 {  /*lint --e{715}*/
7476    SCIP_CONSDATA* consdata;
7477 
7478    assert(cons != NULL);
7479    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7480 
7481    consdata = SCIPconsGetData(cons);
7482    assert(consdata != NULL);
7483 
7484    return consdata->xoffset;
7485 }
7486 
7487 /** gets coefficient of linear variable in absolute power constraint */
SCIPgetCoefLinearAbspower(SCIP * scip,SCIP_CONS * cons)7488 SCIP_Real SCIPgetCoefLinearAbspower(
7489    SCIP*                 scip,               /**< SCIP data structure */
7490    SCIP_CONS*            cons                /**< absolute power constraint */
7491    )
7492 {  /*lint --e{715}*/
7493    SCIP_CONSDATA* consdata;
7494 
7495    assert(cons != NULL);
7496    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7497 
7498    consdata = SCIPconsGetData(cons);
7499    assert(consdata != NULL);
7500 
7501    return consdata->zcoef;
7502 }
7503 
7504 /** gets left hand side in absolute power constraint */
SCIPgetLhsAbspower(SCIP * scip,SCIP_CONS * cons)7505 SCIP_Real SCIPgetLhsAbspower(
7506    SCIP*                 scip,               /**< SCIP data structure */
7507    SCIP_CONS*            cons                /**< absolute power constraint */
7508    )
7509 {  /*lint --e{715}*/
7510    SCIP_CONSDATA* consdata;
7511 
7512    assert(cons != NULL);
7513    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7514 
7515    consdata = SCIPconsGetData(cons);
7516    assert(consdata != NULL);
7517 
7518    return consdata->lhs;
7519 }
7520 
7521 /** gets right hand side in absolute power constraint */
SCIPgetRhsAbspower(SCIP * scip,SCIP_CONS * cons)7522 SCIP_Real SCIPgetRhsAbspower(
7523    SCIP*                 scip,               /**< SCIP data structure */
7524    SCIP_CONS*            cons                /**< absolute power constraint */
7525    )
7526 {  /*lint --e{715}*/
7527    SCIP_CONSDATA* consdata;
7528 
7529    assert(cons != NULL);
7530    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7531 
7532    consdata = SCIPconsGetData(cons);
7533    assert(consdata != NULL);
7534 
7535    return consdata->rhs;
7536 }
7537 
7538 /** gets the absolute violation of a absolute power constraint by a solution */
SCIPgetViolationAbspower(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol)7539 SCIP_Real SCIPgetViolationAbspower(
7540    SCIP*                 scip,               /**< SCIP data structure */
7541    SCIP_CONS*            cons,               /**< absolute power constraint */
7542    SCIP_SOL*             sol                 /**< LP solution */
7543    )
7544 {
7545    SCIP_CONSDATA* consdata;
7546    SCIP_Real z_val;
7547    SCIP_Real x_val;
7548    SCIP_Real rhs;
7549    SCIP_Real proj_val;
7550 
7551    assert(cons != NULL);
7552    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7553 
7554    consdata = SCIPconsGetData(cons);
7555    assert(consdata != NULL);
7556    assert(consdata->lhs == 0.0);
7557    assert(consdata->rhs == 0.0);
7558 
7559    z_val = SCIPgetSolVal(scip, sol, consdata->z);
7560    x_val = SCIPgetSolVal(scip, sol, consdata->x);
7561 
7562    rhs = -1.0 * consdata->zcoef * z_val;
7563    proj_val = SIGN(rhs) * pow(REALABS(rhs), 1.0 / consdata->exponent) - consdata->xoffset;
7564 
7565    SCIPdebugMsg(scip, "computing slack: linear: %f, power: %f, projected: %f\n", z_val, x_val, proj_val);
7566 
7567    return x_val - proj_val;
7568 }
7569 
7570 /** returns whether constraint is convex w.r.t. global bounds
7571  *
7572  * @note in difference to SCIPisConvexQuadratic, we put convexity/concavity of the constraint function in relation to the constraint sides here
7573  */
SCIPisConvexAbspower(SCIP * scip,SCIP_CONS * cons)7574 SCIP_Bool SCIPisConvexAbspower(
7575    SCIP*                 scip,               /**< SCIP data structure */
7576    SCIP_CONS*            cons                /**< absolute power constraint */
7577    )
7578 {
7579    SCIP_CONSDATA* consdata;
7580    SCIP_Real xlb;
7581    SCIP_Real xub;
7582 
7583    assert(scip != NULL);
7584    assert(cons != NULL);
7585    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
7586 
7587    consdata = SCIPconsGetData(cons);
7588    assert(consdata != NULL);
7589 
7590    xlb = SCIPvarGetLbGlobal(consdata->x);
7591    xub = SCIPvarGetLbGlobal(consdata->x);
7592 
7593    /* if mixed sign, then cannot be convex */
7594    if( SCIPisNegative(scip, xlb + consdata->xoffset) && SCIPisPositive(scip, xub + consdata->xoffset) )
7595       return FALSE;
7596 
7597    /* if not negative, then constraint function is like x^n, n > 1, x >= 0, i.e., convex, thus need no lhs to be convex */
7598    if( !SCIPisNegative(scip, xlb + consdata->xoffset) )
7599       return SCIPisInfinity(scip, -consdata->lhs);
7600 
7601    /* if not positive, then constraint function is like -|x|^n, n > 0, x <= 0, i.e., concave, thus need no rhs to be convex */
7602    return SCIPisInfinity(scip, consdata->rhs);
7603 }
7604