Scippy

SCIP

Solving Constraint Integer Programs

cons_soc.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_soc.c
17  * @brief constraint handler for second order cone constraints \f$\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1})\f$
18  * @author Stefan Vigerske
19  * @author Marc Pfetsch
20  *
21  * @todo rhsvar == NULL is supported in some routines, but not everywhere
22  * @todo merge square terms with same variables in presol/exitpre
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include <assert.h>
28 #include <string.h>
29 #include <math.h>
30 #include <ctype.h>
31 
32 #include "scip/cons_soc.h"
33 #include "scip/cons_quadratic.h"
34 #include "scip/cons_linear.h"
35 #include "scip/heur_subnlp.h"
36 #include "scip/heur_trysol.h"
37 #include "scip/intervalarith.h"
38 #include "nlpi/nlpi.h"
39 #include "nlpi/exprinterpret.h"
40 
41 
42 /* constraint handler properties */
43 #define CONSHDLR_NAME "soc"
44 #define CONSHDLR_DESC "constraint handler for second order cone constraints"
45 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
46 #define CONSHDLR_ENFOPRIORITY -40 /**< priority of the constraint handler for constraint enforcing */
47 #define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */
48 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
49 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
50 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
51  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
52 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
53 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
54 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
55 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
56 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
57 
58 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
59 
60 #define QUADCONSUPGD_PRIORITY 10000 /**< priority of the constraint handler for upgrading of quadratic constraints */
61 
62 #ifndef M_PI
63 #define M_PI 3.141592653589793238462643
64 #endif
65 
66 /*
67  * Data structures
68  */
69 
70 /** Eventdata for variable bound change events. */
72 {
73  SCIP_CONSDATA* consdata; /**< the constraint data */
74  int varidx; /**< the index of a variable on the left hand side which bound change is caught, or -1 for variable on right hand side */
75  int filterpos; /**< position of corresponding event in event filter */
76 };
77 typedef struct VarEventData VAREVENTDATA;
78 
79 /** constraint data for soc constraints */
80 struct SCIP_ConsData
81 {
82  int nvars; /**< number of variables on left hand side (n) */
83  SCIP_VAR** vars; /**< variables on left hand side (x_i) */
84  SCIP_Real* coefs; /**< coefficients for variables on left hand side (alpha_i) */
85  SCIP_Real* offsets; /**< offsets for variables on left hand side (beta_i) */
86  SCIP_Real constant; /**< constant on left hand side (gamma) */
87 
88  SCIP_VAR* rhsvar; /**< variable on right hand side (x_{n+1}) */
89  SCIP_Real rhscoeff; /**< coefficient of square term on right hand side (alpha_{n+1}) */
90  SCIP_Real rhsoffset; /**< offset for variable on right hand side (beta_{n+1}) */
91 
92  SCIP_NLROW* nlrow; /**< nonlinear row representation of constraint */
93 
94  SCIP_Real lhsval; /**< value of left hand side in current point */
95  SCIP_Real violation; /**< violation of constraint in current point */
96 
97  VAREVENTDATA* lhsbndchgeventdatas;/**< eventdata for bound change events on left hand side variables */
98  VAREVENTDATA rhsbndchgeventdata; /**< eventdata for bound change event on right hand side variable */
99  SCIP_Bool ispropagated; /**< does the domains need to be propagated? */
100  SCIP_Bool isapproxadded; /**< has a linear outer approximation be added? */
101 };
102 
103 /** constraint handler data */
104 struct SCIP_ConshdlrData
105 {
106  SCIP_HEUR* subnlpheur; /**< a pointer to the subNLP heuristic, if available */
107  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
108  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
109  int newsoleventfilterpos;/**< filter position of new solution event handler, if caught */
110  SCIP_Bool haveexprint; /**< indicates whether an expression interpreter is available */
111  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
112 
113  SCIP_Bool glineur; /**< is the Glineur outer approx preferred to Ben-Tal Nemirovski? */
114  char scaling; /**< scaling method of constraints in feasibility check */
115  SCIP_Bool projectpoint; /**< is the point in which a cut is generated projected onto the feasible set? */
116  int nauxvars; /**< number of auxiliary variables to use when creating a linear outer approx. of a SOC3 constraint */
117  SCIP_Real minefficacy; /**< minimal efficacy of a cut to be added to LP in separation loop */
118  SCIP_Bool sparsify; /**< whether to sparsify cuts */
119  SCIP_Real sparsifymaxloss; /**< maximal loss in cut efficacy by sparsification */
120  SCIP_Real sparsifynzgrowth; /**< growth rate of maximal allowed nonzeros in cuts in sparsification */
121  SCIP_Bool linfeasshift; /**< whether to try to make solutions feasible in check by shifting the variable on the right hand side */
122  char nlpform; /**< formulation of SOC constraint in NLP */
123  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
124  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
125 
126  SCIP_NODE* lastenfolpnode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
127  int nenfolprounds; /**< counter on number of enforcement rounds for the current node */
128 };
129 
130 
131 /*
132  * Local methods
133  */
134 
135 /** catch left hand side variable events */
136 static
138  SCIP* scip, /**< SCIP data structure */
139  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
140  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
141  int varidx /**< index of the variable which events to catch */
142  )
143 {
144  SCIP_CONSDATA* consdata;
145 
146  assert(scip != NULL);
147  assert(cons != NULL);
148  assert(eventhdlr != NULL);
149 
150  consdata = SCIPconsGetData(cons);
151  assert(consdata != NULL);
152  assert(varidx >= 0);
153  assert(varidx < consdata->nvars);
154  assert(consdata->lhsbndchgeventdatas != NULL);
155 
156  consdata->lhsbndchgeventdatas[varidx].consdata = consdata;
157  consdata->lhsbndchgeventdatas[varidx].varidx = varidx;
158  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[varidx], SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)&consdata->lhsbndchgeventdatas[varidx], &consdata->lhsbndchgeventdatas[varidx].filterpos) );
159 
160  consdata->ispropagated = FALSE;
161 
162  return SCIP_OKAY;
163 }
164 
165 /** catch right hand side variable events */
166 static
168  SCIP* scip, /**< SCIP data structure */
169  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
170  SCIP_CONS* cons /**< constraint for which to catch bound change events */
171  )
172 {
173  SCIP_CONSDATA* consdata;
174 
175  assert(scip != NULL);
176  assert(cons != NULL);
177  assert(eventhdlr != NULL);
178 
179  consdata = SCIPconsGetData(cons);
180  assert(consdata != NULL);
181 
182  consdata->rhsbndchgeventdata.consdata = consdata;
183  consdata->rhsbndchgeventdata.varidx = -1;
184  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->rhsvar, SCIP_EVENTTYPE_UBTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)&consdata->rhsbndchgeventdata, &consdata->rhsbndchgeventdata.filterpos) );
185 
186  consdata->ispropagated = FALSE;
187 
188  return SCIP_OKAY;
189 }
190 
191 /** catch variables events */
192 static
194  SCIP* scip, /**< SCIP data structure */
195  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
196  SCIP_CONS* cons /**< constraint for which to catch bound change events */
197  )
198 {
199  SCIP_CONSDATA* consdata;
200  int i;
201 
202  assert(scip != NULL);
203  assert(cons != NULL);
204  assert(eventhdlr != NULL);
205 
206  consdata = SCIPconsGetData(cons);
207  assert(consdata != NULL);
208  assert(consdata->lhsbndchgeventdatas == NULL);
209 
210  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lhsbndchgeventdatas, consdata->nvars) );
211 
212  for( i = 0; i < consdata->nvars; ++i )
213  {
214  if( consdata->vars[i] != NULL )
215  {
216  SCIP_CALL( catchLhsVarEvents(scip, eventhdlr, cons, i) );
217  }
218  }
219 
220  if( consdata->rhsvar != NULL )
221  {
222  SCIP_CALL( catchRhsVarEvents(scip, eventhdlr, cons) );
223  }
224 
225  return SCIP_OKAY;
226 }
227 
228 /** drop left hand side variable events */
229 static
231  SCIP* scip, /**< SCIP data structure */
232  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
233  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
234  int varidx /**< index of the variable which events to catch */
235  )
236 {
237  SCIP_CONSDATA* consdata;
238 
239  assert(scip != NULL);
240  assert(cons != NULL);
241  assert(eventhdlr != NULL);
242 
243  consdata = SCIPconsGetData(cons);
244  assert(consdata != NULL);
245  assert(varidx >= 0);
246  assert(varidx < consdata->nvars);
247  assert(consdata->lhsbndchgeventdatas != NULL);
248  assert(consdata->lhsbndchgeventdatas[varidx].varidx == varidx);
249 
250  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[varidx], SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)&consdata->lhsbndchgeventdatas[varidx], consdata->lhsbndchgeventdatas[varidx].filterpos) );
251 
252  return SCIP_OKAY;
253 }
254 
255 /** drop right hand side variable events */
256 static
258  SCIP* scip, /**< SCIP data structure */
259  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
260  SCIP_CONS* cons /**< constraint for which to catch bound change events */
261  )
262 {
263  SCIP_CONSDATA* consdata;
264 
265  assert(scip != NULL);
266  assert(cons != NULL);
267  assert(eventhdlr != NULL);
268 
269  consdata = SCIPconsGetData(cons);
270  assert(consdata != NULL);
271  assert(consdata->rhsbndchgeventdata.varidx == -1);
272 
273  SCIP_CALL( SCIPdropVarEvent(scip, consdata->rhsvar, SCIP_EVENTTYPE_UBTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)&consdata->rhsbndchgeventdata, consdata->rhsbndchgeventdata.filterpos) );
274 
275  return SCIP_OKAY;
276 }
277 
278 /** drop variable events */
279 static
281  SCIP* scip, /**< SCIP data structure */
282  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
283  SCIP_CONS* cons /**< constraint for which to catch bound change events */
284  )
285 {
286  SCIP_CONSDATA* consdata;
287  int i;
288 
289  assert(scip != NULL);
290  assert(eventhdlr != NULL);
291  assert(cons != NULL);
292 
293  consdata = SCIPconsGetData(cons);
294  assert(consdata != NULL);
295 
296  for( i = 0; i < consdata->nvars; ++i )
297  {
298  if( consdata->vars[i] != NULL )
299  {
300  SCIP_CALL( dropLhsVarEvents(scip, eventhdlr, cons, i) );
301  }
302  }
303 
304  SCIPfreeBlockMemoryArray(scip, &consdata->lhsbndchgeventdatas, consdata->nvars);
305 
306  if( consdata->rhsvar != NULL )
307  {
308  SCIP_CALL( dropRhsVarEvents(scip, eventhdlr, cons) );
309  }
310 
311  return SCIP_OKAY;
312 }
313 
314 /** process variable bound tightening event */
315 static
316 SCIP_DECL_EVENTEXEC(processVarEvent)
317 {
318  SCIP_CONSDATA* consdata;
319 
320  assert(scip != NULL);
321  assert(event != NULL);
322  assert(eventdata != NULL);
323  assert(eventhdlr != NULL);
324 
325  consdata = ((VAREVENTDATA*)eventdata)->consdata;
326  assert(consdata != NULL);
327 
328  consdata->ispropagated = FALSE;
329  /* @todo look at bounds on x_i to decide whether propagation makes sense */
330 
331  return SCIP_OKAY;
332 }
333 
334 /** create a nonlinear row representation of the constraint and stores them in consdata */
335 static
337  SCIP* scip, /**< SCIP data structure */
338  SCIP_CONSHDLR* conshdlr, /**< SOC constraint handler */
339  SCIP_CONS* cons /**< SOC constraint */
340  )
341 {
342  SCIP_CONSHDLRDATA* conshdlrdata;
343  SCIP_CONSDATA* consdata;
344  char nlpform;
345  int i;
346 
347  assert(scip != NULL);
348  assert(cons != NULL);
349 
350  conshdlrdata = SCIPconshdlrGetData(conshdlr);
351  assert(conshdlrdata != NULL);
352 
353  consdata = SCIPconsGetData(cons);
354  assert(consdata != NULL);
355 
356  if( consdata->nlrow != NULL )
357  {
358  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
359  }
360 
361  nlpform = conshdlrdata->nlpform;
362  if( nlpform == 'a' )
363  {
364  /* if the user let us choose, then we take 's' for "small" SOC constraints, but 'q' for large ones,
365  * since the 's' form leads to nvars^2 elements in Hessian, while the 'q' form yields only n elements
366  * however, if there is no expression interpreter, then the NLPI may have trouble, so we always use 'q' in this case
367  */
368  if( consdata->nvars < 100 && conshdlrdata->haveexprint )
369  nlpform = 's';
370  else
371  nlpform = 'q';
372  }
373 
374  switch( nlpform )
375  {
376  case 'e':
377  {
378  /* construct expression exp(\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} - alpha_{n+1}(x_{n+1} + beta_{n+1})) */
379 
380  if( consdata->nvars > 0 )
381  {
382  SCIP_EXPR* expr;
383  SCIP_EXPR* exprterm;
384  SCIP_EXPR* expr2;
385  SCIP_EXPRTREE* exprtree;
386 
387  if( consdata->constant != 0.0 )
388  {
389  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_CONST, consdata->constant) ); /* gamma */
390  }
391  else
392  {
393  exprterm = NULL;
394  }
395 
396  for( i = 0; i < consdata->nvars; ++i )
397  {
398  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, i) ); /* x_i */
399  if( consdata->offsets[i] != 0.0 )
400  {
401  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->offsets[i]) ); /* beta_i */
402  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, expr2) ); /* x_i + beta_i */
403  }
404  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_SQUARE, expr) ); /* (x_i + beta_i)^2 */
405  if( consdata->coefs[i] != 1.0 )
406  {
407  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->coefs[i]) ); /* alpha_i */
408  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MUL, expr, expr2) ); /* alpha_i * (x_i + beta_i)^2 */
409  }
410  if( exprterm != NULL )
411  {
412  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_PLUS, exprterm, expr) );
413  }
414  else
415  {
416  exprterm = expr;
417  }
418  }
419 
420  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_SQRT, exprterm) ); /* sqrt(gamma + sum_i (...)^2) */
421 
422  if( consdata->rhsvar != NULL )
423  {
424  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, consdata->nvars) ); /* x_{n+1} */
425  if( consdata->rhsoffset != 0.0 )
426  {
427  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->rhsoffset) ); /* beta_{n+1} */
428  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, expr2) ); /* x_{n+1} + beta_{n+1} */
429  }
430  if( consdata->rhscoeff != 1.0 )
431  {
432  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->rhscoeff) ); /* alpha_{n+1} */
433  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MUL, expr, expr2) ); /* alpha_{n+1} * (x_{n+1} + beta_{n+1}) */
434  }
435  }
436  else
437  {
438  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_CONST, consdata->rhscoeff * consdata->rhsoffset) );
439  }
440  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_MINUS, exprterm, expr) ); /* sqrt(gamma + sum_i (...)^2) - alpha_{n+1} * (x_{n+1} + beta_{n+1}) */
441 
442  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_EXP, exprterm) ); /* exp(sqrt(gamma + sum_i (...)^2) - alpha_{n+1} * (x_{n+1} + beta_{n+1})) */
443 
444  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, exprterm, consdata->nvars+1, 0, NULL) );
445 
446  SCIP_CALL( SCIPexprtreeSetVars(exprtree, consdata->nvars, consdata->vars) );
447  SCIP_CALL( SCIPexprtreeAddVars(exprtree, 1, &consdata->rhsvar) );
448 
449  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
450  0.0,
451  0, NULL, NULL,
452  0, NULL, 0, NULL,
453  exprtree, -SCIPinfinity(scip), 1.0) );
454 
455  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
456 
457  break;
458  }
459  /* if there are no left-hand-side variables, then we let the 's' case handle it */
460  } /*lint -fallthrough */
461 
462  case 's':
463  {
464  /* construct expression \sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} */
465 
466  SCIP_EXPR* expr;
467  SCIP_EXPR* exprterm;
468  SCIP_EXPR* expr2;
469  SCIP_EXPRTREE* exprtree;
470  SCIP_Real lincoef;
471 
472  if( consdata->constant != 0.0 )
473  {
474  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_CONST, consdata->constant) ); /* gamma */
475  }
476  else
477  {
478  exprterm = NULL;
479  }
480 
481  for( i = 0; i < consdata->nvars; ++i )
482  {
483  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, i) ); /* x_i */
484  if( consdata->offsets[i] != 0.0 )
485  {
486  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->offsets[i]) ); /* beta_i */
487  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, expr2) ); /* x_i + beta_i */
488  }
489  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_SQUARE, expr) ); /* (x_i + beta_i)^2 */
490  if( consdata->coefs[i] != 1.0 )
491  {
492  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_CONST, consdata->coefs[i]) ); /* alpha_i */
493  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MUL, expr, expr2) ); /* alpha_i * (x_i + beta_i)^2 */
494  }
495  if( exprterm != NULL )
496  {
497  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_PLUS, exprterm, expr) );
498  }
499  else
500  {
501  exprterm = expr;
502  }
503  }
504 
505  if( exprterm != NULL )
506  {
507  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprterm, SCIP_EXPR_SQRT, exprterm) ); /* sqrt(gamma + sum_i (...)^2) */
508  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, exprterm, consdata->nvars, 0, NULL) );
509  SCIP_CALL( SCIPexprtreeSetVars(exprtree, consdata->nvars, consdata->vars) );
510  }
511  else
512  {
513  assert(consdata->nvars == 0);
514  assert(consdata->constant == 0.0);
515  exprtree = NULL;
516  }
517 
518  /* linear and constant part is -\alpha_{n+1} (x_{n+1}+\beta_{n+1}) */
519  lincoef = -consdata->rhscoeff;
520  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
521  -consdata->rhscoeff * consdata->rhsoffset,
522  1, &consdata->rhsvar, &lincoef,
523  0, NULL, 0, NULL,
524  exprtree, -SCIPinfinity(scip), 0.0) );
525 
526  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
527 
528  break;
529  }
530 
531  case 'q':
532  {
533  /* construct quadratic form gamma + sum_{i=1}^{n} (alpha_i (x_i + beta_i))^2 <= (alpha_{n+1} (x_{n+1} + beta_{n+1})^2 */
534  SCIP_QUADELEM sqrterm;
535  SCIP_Real rhs;
536  int rhsvarpos;
537 
538  /* create initial empty row with left hand side variables */
539  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
540  0, NULL, NULL,
541  consdata->nvars, consdata->vars, 0, NULL,
542  NULL, -SCIPinfinity(scip), 0.0) );
543 
544  /* add gamma + sum_{i=1}^{n} (alpha_i x_i)^2 + 2 alpha_i beta_i x_i + beta_i^2 */
545  rhs = -consdata->constant;
546  for( i = 0; i < consdata->nvars; ++i )
547  {
548  sqrterm.idx1 = i;
549  sqrterm.idx2 = i;
550  sqrterm.coef = consdata->coefs[i] * consdata->coefs[i];
551  SCIP_CALL( SCIPaddQuadElementToNlRow(scip, consdata->nlrow, sqrterm) );
552 
553  if( consdata->offsets[i] != 0.0 )
554  {
555  rhs -= consdata->offsets[i] * consdata->offsets[i];
556  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, consdata->vars[i], 2.0 * consdata->coefs[i] * consdata->offsets[i]) );
557  }
558  }
559 
560  /* add rhsvar to quadvars of nlrow, if not there yet */
561  rhsvarpos = SCIPnlrowSearchQuadVar(consdata->nlrow, consdata->rhsvar);
562  if( rhsvarpos == -1 )
563  {
564  SCIP_CALL( SCIPaddQuadVarToNlRow(scip, consdata->nlrow, consdata->rhsvar) );
565  rhsvarpos = SCIPnlrowSearchQuadVar(consdata->nlrow, consdata->rhsvar);
566  assert(rhsvarpos >= 0);
567  }
568 
569  /* add -(alpha_{n+1} x_{n+1))^2 - 2 alpha_{n+1} beta_{n+1} x_{n+1} - beta_{n+1}^2 */
570  sqrterm.idx1 = rhsvarpos;
571  sqrterm.idx2 = rhsvarpos;
572  sqrterm.coef = -consdata->rhscoeff * consdata->rhscoeff;
573  SCIP_CALL( SCIPaddQuadElementToNlRow(scip, consdata->nlrow, sqrterm) );
574 
575  if( consdata->rhsoffset != 0.0 )
576  {
577  rhs += consdata->rhsoffset * consdata->rhsoffset;
578  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, consdata->rhsvar, -2.0 * consdata->rhscoeff * consdata->rhsoffset) );
579  }
580 
581  SCIP_CALL( SCIPchgNlRowRhs(scip, consdata->nlrow, rhs) );
582 
583  break;
584  }
585 
586  case 'd':
587  {
588  /* construct division form (gamma + sum_{i=1}^n (alpha_i(x_i+beta_i))^2)/(alpha_{n+1}(x_{n+1}+beta_{n+1})) <= alpha_{n+1}(x_{n+1}+beta_{n+1})
589  */
590  SCIP_EXPRTREE* exprtree;
591  SCIP_EXPR* expr;
592  SCIP_EXPR* nominator;
593  SCIP_EXPR* denominator;
594  SCIP_EXPR** exprs;
595  SCIP_EXPRDATA_MONOMIAL** monomials;
596  SCIP_Real lincoef;
597  SCIP_Real one;
598  SCIP_Real two;
599 
600  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, consdata->nvars) );
601  SCIP_CALL( SCIPallocBufferArray(scip, &monomials, consdata->nvars) );
602  one = 1.0;
603  two = 2.0;
604 
605  for( i = 0; i < consdata->nvars; ++i )
606  {
607  /* put x_i + beta_i into exprs[i] */
608  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &exprs[i], SCIP_EXPR_VARIDX, i) );
609  if( consdata->offsets[i] != 0.0 )
610  {
611  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &exprs[i], 1, &exprs[i], &one, consdata->offsets[i]) );
612  }
613 
614  /* create monomial alpha_i^2 y_i^2, where y_i will be x_i + beta_i */
615  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomials[i], consdata->coefs[i] * consdata->coefs[i], 1, &i, &two) );
616  }
617 
618  /* setup polynomial expression for gamma + sum_{i=1}^n alpha_i^2 (x_i+beta_i)^2 */
619  SCIP_CALL( SCIPexprCreatePolynomial(SCIPblkmem(scip), &nominator, consdata->nvars, exprs, consdata->nvars, monomials, consdata->constant, FALSE) ); /*lint !e850 */
620 
621  SCIPfreeBufferArray(scip, &monomials);
622  SCIPfreeBufferArray(scip, &exprs);
623 
624  /* setup alpha_{n+1}(x_{n+1}+beta_{n+1})
625  * assert that this term is >= 0.0 (otherwise constraint is infeasible anyway) */
626  assert(consdata->rhsvar != NULL);
627  assert((consdata->rhscoeff >= 0.0 && !SCIPisNegative(scip, SCIPvarGetLbGlobal(consdata->rhsvar) + consdata->rhsoffset)) ||
628  (consdata->rhscoeff <= 0.0 && !SCIPisPositive(scip, SCIPvarGetUbGlobal(consdata->rhsvar) + consdata->rhsoffset)));
629  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &denominator, SCIP_EXPR_VARIDX, consdata->nvars) );
630  if( consdata->rhscoeff != 1.0 || consdata->rhsoffset != 0.0 )
631  {
632  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &denominator, 1, &denominator, &consdata->rhscoeff, consdata->rhscoeff * consdata->rhsoffset) );
633  }
634 
635  /* setup nominator/denominator */
636  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, nominator, denominator) );
637 
638  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, 0, 0, NULL) );
639  SCIP_CALL( SCIPexprtreeSetVars(exprtree, consdata->nvars, consdata->vars) );
640  SCIP_CALL( SCIPexprtreeAddVars(exprtree, 1, &consdata->rhsvar) );
641 
642  /* linear and constant part is -\alpha_{n+1} (x_{n+1}+\beta_{n+1}) */
643  lincoef = -consdata->rhscoeff;
644  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
645  -consdata->rhscoeff * consdata->rhsoffset,
646  1, &consdata->rhsvar, &lincoef,
647  0, NULL, 0, NULL,
648  exprtree, -SCIPinfinity(scip), 0.0) );
649 
650  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
651 
652  break;
653  }
654 
655  default:
656  SCIPerrorMessage("unknown value for nlp formulation parameter\n");
657  return SCIP_ERROR;
658  }
659 
660  SCIPdebugMessage("created nonlinear row representation of SOC constraint\n");
661  SCIPdebugPrintCons(scip, cons, NULL);
662  SCIPdebug( SCIP_CALL( SCIPprintNlRow(scip, consdata->nlrow, NULL) ) );
663 
664  return SCIP_OKAY;
665 }
666 
667 /** evaluates the left hand side of a SOC constraint */
668 static
670  SCIP* scip, /**< SCIP data structure */
671  SCIP_CONS* cons, /**< constraint to evaluate */
672  SCIP_SOL* sol /**< solution to evaluate, or NULL if LP solution should be used */
673  )
674 {
675  SCIP_CONSDATA* consdata;
676  SCIP_VAR* var;
677  SCIP_Real val;
678  int i;
679 
680  assert(scip != NULL);
681  assert(cons != NULL);
682 
683  consdata = SCIPconsGetData(cons);
684  assert(consdata != NULL);
685 
686  consdata->lhsval = consdata->constant;
687 
688  for( i = 0; i < consdata->nvars; ++i )
689  {
690  var = consdata->vars[i];
691  val = SCIPgetSolVal(scip, sol, var);
692 
693  if( SCIPisInfinity(scip, val) || SCIPisInfinity(scip, -val) )
694  {
695  consdata->lhsval = SCIPinfinity(scip);
696  return SCIP_OKAY;
697  }
698 
699  if( sol == NULL )
700  {
701  SCIP_Real lb = SCIPvarGetLbLocal(var);
702  SCIP_Real ub = SCIPvarGetUbLocal(var);
703  SCIP_Real minval = MIN(ub, val);
704 
705 #if 0 /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
706  assert(SCIPisFeasGE(scip, val, lb));
707  assert(SCIPisFeasLE(scip, val, ub));
708 #endif
709  val = MAX(lb, minval);
710  }
711 
712  val = consdata->coefs[i] * (val + consdata->offsets[i]);
713  consdata->lhsval += val * val;
714  }
715  consdata->lhsval = sqrt(consdata->lhsval);
716 
717  return SCIP_OKAY;
718 }
719 
720 /* computes the norm of the gradient of the SOC function */
721 static
723  SCIP* scip, /**< SCIP data structure */
724  SCIP_CONS* cons, /**< constraint */
725  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
726  )
727 {
728  SCIP_CONSDATA* consdata;
729  SCIP_Real g, h;
730  int i;
731 
732  assert(scip != NULL);
733  assert(cons != NULL);
734 
735  consdata = SCIPconsGetData(cons);
736  assert(consdata != NULL);
737 
738  g = 0.0;
739  for( i = 0; i < consdata->nvars; ++i )
740  {
741  assert(!SCIPisInfinity(scip, ABS(SCIPgetSolVal(scip, sol, consdata->vars[i])))); /*lint !e666*/
742 
743  h = SCIPgetSolVal(scip, sol, consdata->vars[i]) + consdata->offsets[i];
744  h *= consdata->coefs[i] * consdata->coefs[i];
745  g += h * h;
746  }
747  g /= consdata->lhsval * consdata->lhsval;
748  g += consdata->rhscoeff * consdata->rhscoeff;
749 
750  return sqrt(g);
751 }
752 
753 /** computes violation of a SOC constraint */
754 static
756  SCIP* scip, /**< SCIP data structure */
757  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
758  SCIP_CONS* cons, /**< constraint to evaluate */
759  SCIP_SOL* sol /**< solution to evaluate, or NULL if LP solution should be used */
760  )
761 {
762  SCIP_CONSHDLRDATA* conshdlrdata;
763  SCIP_CONSDATA* consdata;
764  SCIP_Real rhsval;
765 
766  assert(scip != NULL);
767  assert(conshdlr != NULL);
768  assert(cons != NULL);
769 
770  conshdlrdata = SCIPconshdlrGetData(conshdlr);
771  assert(conshdlrdata != NULL);
772 
773  consdata = SCIPconsGetData(cons);
774  assert(consdata != NULL);
775 
776  SCIP_CALL( evalLhs(scip, cons, sol) );
777 
778  if( SCIPisInfinity(scip, consdata->lhsval) )
779  {
780  /* infinity <= infinity is feasible
781  * infinity <= finite value is not feasible and has violation infinity
782  */
783  if( (consdata->rhscoeff > 0.0 && SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, consdata->rhsvar))) ||
784  ( consdata->rhscoeff < 0.0 && SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, consdata->rhsvar))) )
785  consdata->violation = 0.0;
786  else
787  consdata->violation = SCIPinfinity(scip);
788  return SCIP_OKAY;
789  }
790 
791  rhsval = SCIPgetSolVal(scip, sol, consdata->rhsvar);
792  if( SCIPisInfinity(scip, rhsval) )
793  {
794  consdata->violation = consdata->rhscoeff > 0.0 ? 0.0 : SCIPinfinity(scip);
795  return SCIP_OKAY;
796  }
797  if( SCIPisInfinity(scip, -rhsval) )
798  {
799  consdata->violation = consdata->rhscoeff < 0.0 ? 0.0 : SCIPinfinity(scip);
800  return SCIP_OKAY;
801  }
802  if( sol == NULL )
803  {
804  SCIP_Real lb = SCIPvarGetLbLocal(consdata->rhsvar);
805  SCIP_Real ub = SCIPvarGetUbLocal(consdata->rhsvar);
806  SCIP_Real minval = MIN(ub, rhsval);
807 
808 #if 0 /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
809  assert(SCIPisFeasGE(scip, rhsval, lb));
810  assert(SCIPisFeasLE(scip, rhsval, ub));
811 #endif
812  rhsval = MAX(lb, minval);
813  }
814 
815  consdata->violation = consdata->lhsval - consdata->rhscoeff * (rhsval + consdata->rhsoffset);
816  if( consdata->violation <= 0.0 )
817  {
818  /* constraint is not violated for sure */
819  consdata->violation = 0.0;
820  return SCIP_OKAY;
821  }
822 
823  switch( conshdlrdata->scaling )
824  {
825  case 'o' :
826  {
827  /* no scaling */
828  break;
829  }
830 
831  case 'g' :
832  {
833  /* scale by sup-norm of gradient in current point */
834  if( consdata->violation > 0.0 )
835  {
836  SCIP_Real norm;
837 
838  norm = getGradientNorm(scip, cons, sol);
839 
840  if( norm > 1.0 )
841  consdata->violation /= norm;
842  }
843  break;
844  }
845 
846  case 's' :
847  {
848  /* scale by constant term on right hand side */
849  if( consdata->violation > 0.0 )
850  consdata->violation /= MAX(1.0, consdata->rhscoeff * consdata->rhsoffset);
851 
852  break;
853  }
854 
855  default :
856  {
857  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
858  SCIPABORT();
859  return SCIP_INVALIDDATA; /*lint !e527*/
860  }
861  }
862 
863  return SCIP_OKAY;
864 }
865 
866 /** computes violations for a set of constraints */
867 static
869  SCIP* scip, /**< SCIP data structure */
870  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
871  SCIP_CONS** conss, /**< constraints to evaluate */
872  int nconss, /**< number of constraints to evaluate */
873  SCIP_SOL* sol, /**< solution to evaluate, or NULL if LP solution should be used */
874  SCIP_CONS** maxviolcons /**< a buffer to store pointer to maximal violated constraint, or NULL if of no interest */
875  )
876 {
877  SCIP_CONSDATA* consdata;
878  SCIP_Real maxviol = 0.0;
879  int c;
880 
881  assert(scip != NULL);
882  assert(conss != NULL || nconss == 0);
883 
884  if( maxviolcons != NULL )
885  *maxviolcons = NULL;
886 
887  for( c = 0; c < nconss; ++c )
888  {
889  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) ); /*lint !e613*/
890  if( maxviolcons != NULL )
891  {
892  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
893  assert(consdata != NULL);
894  if( consdata->violation > maxviol && SCIPisGT(scip, consdata->violation, SCIPfeastol(scip)) )
895  {
896  maxviol = consdata->violation;
897  *maxviolcons = conss[c]; /*lint !e613*/
898  }
899  }
900  }
901 
902  return SCIP_OKAY;
903 }
904 
905 /** generate supporting hyperplane in a given solution */
906 static
908  SCIP* scip, /**< SCIP pointer */
909  SCIP_CONS* cons, /**< constraint */
910  SCIP_SOL* sol, /**< solution to separate, or NULL for LP solution */
911  SCIP_ROW** row /**< place to store cut */
912  )
913 {
914  SCIP_CONSDATA* consdata;
915  char cutname[SCIP_MAXSTRLEN];
916  SCIP_Real* rowcoeff;
917  SCIP_Real rhs = 0.0;
918  SCIP_Real val;
919  int i;
920 
921  assert(scip != NULL);
922  assert(cons != NULL);
923  assert(row != NULL);
924 
925  consdata = SCIPconsGetData(cons);
926  assert(consdata != NULL);
927 
928  assert(SCIPisPositive(scip, consdata->lhsval)); /* do not like to linearize in 0 */
929  assert(!SCIPisInfinity(scip, consdata->lhsval));
930 
931  SCIP_CALL( SCIPallocBufferArray(scip, &rowcoeff, consdata->nvars) );
932 
933  for( i = 0; i < consdata->nvars; ++i )
934  {
935  val = SCIPgetSolVal(scip, sol, consdata->vars[i]) + consdata->offsets[i];
936  val *= consdata->coefs[i] * consdata->coefs[i];
937 
938  rowcoeff[i] = val / consdata->lhsval;
939 
940  val *= SCIPgetSolVal(scip, sol, consdata->vars[i]);
941  rhs += val;
942  }
943  rhs /= consdata->lhsval;
944  rhs -= consdata->lhsval - consdata->rhscoeff * consdata->rhsoffset;
945 
946  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_linearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
947 
948  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, -SCIPinfinity(scip), rhs, SCIPconsIsLocal(cons), FALSE, TRUE) );
949  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nvars, consdata->vars, rowcoeff) );
950  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->rhsvar, -consdata->rhscoeff) );
951 
952  SCIPfreeBufferArray(scip, &rowcoeff);
953 
954  return SCIP_OKAY;
955 }
956 
957 /** generate supporting hyperplane in a given point */
958 static
960  SCIP* scip, /**< SCIP pointer */
961  SCIP_CONS* cons, /**< constraint */
962  SCIP_Real* x, /**< point (lhs-vars) where to generate cut */
963  SCIP_ROW** row /**< place to store cut */
964  )
965 {
966  SCIP_CONSDATA* consdata;
967  SCIP_Real* rowcoeff;
968  SCIP_Real rhs = 0.0;
969  SCIP_Real lhsval;
970  SCIP_Real val;
971  int i;
972  char cutname[SCIP_MAXSTRLEN];
973 
974  assert(scip != NULL);
975  assert(cons != NULL);
976  assert(row != NULL);
977 
978  consdata = SCIPconsGetData(cons);
979  assert(consdata != NULL);
980 
981  lhsval = consdata->constant;
982  for( i = 0; i < consdata->nvars; ++i )
983  {
984  assert(!SCIPisInfinity(scip, ABS(x[i])));
985 
986  val = consdata->coefs[i] * (x[i] + consdata->offsets[i]);
987  lhsval += val * val;
988  }
989  lhsval = sqrt(lhsval);
990 
991  if( SCIPisZero(scip, lhsval) )
992  { /* do not like to linearize in 0 */
993  return SCIP_OKAY;
994  }
995 
996  SCIP_CALL( SCIPallocBufferArray(scip, &rowcoeff, consdata->nvars) );
997 
998  for( i = 0; i < consdata->nvars; ++i )
999  {
1000  val = x[i] + consdata->offsets[i];
1001  if( SCIPisZero(scip, val) )
1002  {
1003  rowcoeff[i] = 0.0;
1004  continue;
1005  }
1006  val *= consdata->coefs[i] * consdata->coefs[i];
1007 
1008  rowcoeff[i] = val / lhsval;
1009 
1010  val *= x[i];
1011  rhs += val;
1012  }
1013  rhs /= lhsval;
1014  rhs -= lhsval - consdata->rhscoeff * consdata->rhsoffset;
1015 
1016  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_linearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
1017 
1018  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, -SCIPinfinity(scip), rhs, SCIPconsIsLocal(cons), FALSE, TRUE) );
1019  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nvars, consdata->vars, rowcoeff) );
1020  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->rhsvar, -consdata->rhscoeff) );
1021 
1022  SCIPfreeBufferArray(scip, &rowcoeff);
1023 
1024  return SCIP_OKAY;
1025 }
1026 
1027 /** generate supporting hyperplane w.r.t. solution projected on feasible set
1028  *
1029  * Instead of linearizing the SOC constraint in the given solution point, this function projects the point
1030  * first onto the feasible set of the SOC constraint (w.r.t. euclidean norm (scaled by alpha))
1031  * and linearizes the SOC constraint there.
1032  * The hope is that this produces somewhat tighter cuts.
1033  *
1034  * The projection has only be computed for the case gamma = 0.
1035  * If gamma > 0, generateCut is called.
1036  *
1037  * Let \f$\hat x\f$ be sol or the LP solution if sol == NULL.
1038  * Then the projected point \f$\tilde x\f$ is given by
1039  * \f[
1040  * \tilde x_i = \frac{\hat x_i + \lambda \beta_i}{1-\lambda}, \quad i=1,\ldots, n; \quad
1041  * \tilde x_{n+1} = \frac{\hat x_{n+1} - \lambda \beta_{n+1}}{1+\lambda}
1042  * \f]
1043  * where
1044  * \f[
1045  * \lambda = \frac{1-A}{1+A}, \qquad
1046  * A = \frac{\alpha_{n+1}(\hat x_{n+1}+\beta_{n+1})}{\sqrt{\sum_{i=1}^n (\alpha_i(\hat x_i+\beta_i))^2}}
1047  * \f]
1048  *
1049  * If lambda is very close to 1, generateCut is called.
1050  *
1051  * The generated cut is very similar to the unprojected form.
1052  * The only difference is in the right hand side, which is (in the case beta = 0) multiplied by 1/(1-lambda).
1053  * */
1054 static
1056  SCIP* scip, /**< SCIP pointer */
1057  SCIP_CONS* cons, /**< constraint */
1058  SCIP_SOL* sol, /**< solution to separate, or NULL for LP solution */
1059  SCIP_ROW** row /**< place to store cut */
1060  )
1061 {
1062  SCIP_CONSDATA* consdata;
1063  SCIP_Real* rowcoeff;
1064  SCIP_Real rhs = 0.0;
1065  SCIP_Real val;
1066  SCIP_Real A, lambda;
1067  int i;
1068  char cutname[SCIP_MAXSTRLEN];
1069 
1070  assert(scip != NULL);
1071  assert(cons != NULL);
1072  assert(row != NULL);
1073 
1074  consdata = SCIPconsGetData(cons);
1075  assert(consdata != NULL);
1076 
1077  assert(SCIPisPositive(scip, consdata->lhsval)); /* do not like to linearize in 0 */
1078  assert(!SCIPisInfinity(scip, consdata->lhsval));
1079 
1080  if( !SCIPisZero(scip, consdata->constant) )
1081  { /* have not thought about this case yet */
1082  SCIP_CALL( generateCutSol(scip, cons, sol, row) );
1083  return SCIP_OKAY;
1084  }
1085 
1086  A = consdata->rhscoeff * (SCIPgetSolVal(scip, sol, consdata->rhsvar) + consdata->rhsoffset);
1087  A /= consdata->lhsval;
1088 
1089  lambda = (1.0 - A) / (1.0 + A);
1090 
1091  assert(!SCIPisNegative(scip, lambda)); /* otherwise A > 1, so constraint is not violated */
1092 
1093  SCIPdebugMessage("A = %g \t lambda = %g\n", A, lambda);
1094 
1095  if( SCIPisFeasEQ(scip, lambda, 1.0) )
1096  { /* avoid numerical difficulties when dividing by (1-lambda) below */
1097  SCIP_CALL( generateCutSol(scip, cons, sol, row) );
1098  return SCIP_OKAY;
1099  }
1100 
1101  SCIP_CALL( SCIPallocBufferArray(scip, &rowcoeff, consdata->nvars) );
1102 
1103  for( i = 0; i < consdata->nvars; ++i )
1104  {
1105  val = SCIPgetSolVal(scip, sol, consdata->vars[i]) + consdata->offsets[i];
1106  val *= consdata->coefs[i] * consdata->coefs[i];
1107 
1108  rowcoeff[i] = val / consdata->lhsval;
1109 
1110  val *= SCIPgetSolVal(scip, sol, consdata->vars[i]) + lambda * consdata->offsets[i];
1111  rhs += val;
1112  }
1113  rhs /= consdata->lhsval;
1114  rhs -= consdata->lhsval;
1115  rhs /= 1.0 - lambda;
1116  rhs -= consdata->rhscoeff * consdata->rhsoffset;
1117 
1118  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_linearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
1119 
1120  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, -SCIPinfinity(scip), rhs, SCIPconsIsLocal(cons), FALSE, TRUE) );
1121  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nvars, consdata->vars, rowcoeff) );
1122  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->rhsvar, -consdata->rhscoeff) );
1123 
1124  SCIPfreeBufferArray(scip, &rowcoeff);
1125 
1126  return SCIP_OKAY;
1127 }
1128 
1129 /** generates sparsified supporting hyperplane */
1130 static
1132  SCIP* scip, /**< SCIP pointer */
1133  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1134  SCIP_CONS* cons, /**< constraint */
1135  SCIP_SOL* sol, /**< solution to separate, or NULL for LP solution */
1136  SCIP_ROW** row, /**< place to store cut */
1137  SCIP_Real minefficacy /**< minimal efficacy for a cut to be accepted */
1138  )
1139 {
1140  SCIP_CONSHDLRDATA* conshdlrdata;
1141  SCIP_CONSDATA* consdata;
1142  SCIP_Real* x;
1143  SCIP_Real* dist; /* distance to 0 */
1144  int* ind; /* indices */
1145  int i;
1146  int maxnz, nextmaxnz;
1147  SCIP_Real efficacy;
1148  SCIP_Real goodefficacy;
1149 
1150  assert(scip != NULL);
1151  assert(conshdlr != NULL);
1152  assert(cons != NULL);
1153  assert(row != NULL);
1154 
1155  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1156  assert(conshdlrdata != NULL);
1157 
1158  consdata = SCIPconsGetData(cons);
1159  assert(consdata != NULL);
1160 
1161  assert(SCIPisPositive(scip, consdata->lhsval)); /* do not like to linearize in 0 */
1162  assert(!SCIPisInfinity(scip, consdata->lhsval));
1163 
1164  if( consdata->nvars <= 3 )
1165  {
1166  SCIP_CALL( generateCutSol(scip, cons, sol, row) );
1167  return SCIP_OKAY;
1168  }
1169 
1170  goodefficacy = MAX((1.0-conshdlrdata->sparsifymaxloss) * consdata->violation, minefficacy);
1171 
1172  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nvars) );
1173  SCIP_CALL( SCIPallocBufferArray(scip, &dist, consdata->nvars) );
1174  SCIP_CALL( SCIPallocBufferArray(scip, &ind, consdata->nvars) );
1175 
1176  SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, x) );
1177  /* distance to "-offset" * alpha_i^2 should indicate loss when moving refpoint to x[i] = -offset[i] */
1178  for( i = 0; i < consdata->nvars; ++i )
1179  {
1180  ind[i] = i;
1181  dist[i] = ABS(x[i] + consdata->offsets[i]);
1182  dist[i] *= consdata->coefs[i] * consdata->coefs[i];
1183  }
1184 
1185  /* sort variables according to dist */
1186  SCIPsortRealInt(dist, ind, consdata->nvars);
1187 
1188  maxnz = 2;
1189  /* set all except biggest maxnz entries in x to -offset */
1190  for( i = 0; i < consdata->nvars - maxnz; ++i )
1191  x[ind[i]] = -consdata->offsets[i];
1192 
1193  do
1194  {
1195  /* @todo speed up a bit by computing efficacy of new cut from efficacy of old cut
1196  * generate row only if efficient enough
1197  */
1198  SCIP_CALL( generateCutPoint(scip, cons, x, row) );
1199 
1200  if( *row != NULL )
1201  {
1202  efficacy = -SCIPgetRowSolFeasibility(scip, *row, sol) ;
1203  switch( conshdlrdata->scaling )
1204  {
1205  case 'o' :
1206  break;
1207 
1208  case 'g' :
1209  {
1210  SCIP_Real norm;
1211 
1212  norm = SCIPgetRowMaxCoef(scip, *row);
1213  efficacy /= MAX(1.0, norm);
1214  break;
1215  }
1216 
1217  case 's' :
1218  {
1219  SCIP_Real abslhs = REALABS(SCIProwGetLhs(*row));
1220  SCIP_Real absrhs = REALABS(SCIProwGetRhs(*row));
1221  SCIP_Real minval = MIN(abslhs, absrhs);
1222 
1223  efficacy /= MAX(1.0, minval);
1224  break;
1225  }
1226 
1227  default:
1228  SCIPerrorMessage("Wrong type of scaling: %c.\n", conshdlrdata->scaling);
1229  SCIPABORT();
1230  return SCIP_INVALIDDATA; /*lint !e527*/
1231  }
1232 
1233  if( SCIPisGT(scip, efficacy, goodefficacy) ||
1234  (maxnz >= consdata->nvars && SCIPisGT(scip, efficacy, minefficacy)) )
1235  {
1236  /* cut cuts off solution and is efficient enough */
1237  SCIPdebugMessage("accepted cut with %d of %d nonzeros, efficacy = %g\n", maxnz, consdata->nvars, efficacy);
1238  break;
1239  }
1240  SCIP_CALL( SCIPreleaseRow(scip, row) );
1241  }
1242 
1243  /* cut also not efficient enough if generated in original refpoint (that's bad) */
1244  if( maxnz >= consdata->nvars )
1245  break;
1246 
1247  nextmaxnz = (int)(conshdlrdata->sparsifynzgrowth * maxnz);
1248  if( nextmaxnz == consdata->nvars - 1)
1249  nextmaxnz = consdata->nvars;
1250  else if( nextmaxnz == maxnz )
1251  ++nextmaxnz;
1252 
1253  /* restore entries of x that are nonzero in next attempt */
1254  for( i = MAX(0, consdata->nvars - nextmaxnz); i < consdata->nvars - maxnz; ++i )
1255  x[ind[i]] = SCIPgetSolVal(scip, sol, consdata->vars[ind[i]]);
1256 
1257  maxnz = nextmaxnz;
1258  }
1259  while( TRUE ); /*lint !e506*/
1260 
1261  SCIPfreeBufferArray(scip, &x);
1262  SCIPfreeBufferArray(scip, &dist);
1263  SCIPfreeBufferArray(scip, &ind);
1264 
1265  return SCIP_OKAY;
1266 }
1267 
1268 /** separates a point, if possible */
1269 static
1271  SCIP* scip, /**< SCIP data structure */
1272  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1273  SCIP_CONS** conss, /**< constraints */
1274  int nconss, /**< number of constraints */
1275  int nusefulconss, /**< number of constraints that seem to be useful */
1276  SCIP_SOL* sol, /**< solution to separate, or NULL for LP solution */
1277  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
1278  SCIP_Bool* cutoff, /**< pointer to store whether a fixing leads to a cutoff */
1279  SCIP_Bool* success /**< buffer to store whether the point was separated */
1280  )
1281 {
1282  SCIP_CONSHDLRDATA* conshdlrdata;
1283  SCIP_CONSDATA* consdata;
1284  SCIP_Real minefficacy;
1285  int c;
1286  SCIP_ROW* row;
1287 
1288  assert(scip != NULL);
1289  assert(conss != NULL || nconss == 0);
1290  assert(nusefulconss <= nconss);
1291  assert(cutoff != NULL);
1292  assert(success != NULL);
1293 
1294  *cutoff = FALSE;
1295 
1296  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1297  assert(conshdlrdata != NULL);
1298 
1299  *success = FALSE;
1300 
1301  minefficacy = inenforcement ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip)) : conshdlrdata->minefficacy;
1302 
1303  for( c = 0; c < nconss; ++c )
1304  {
1305  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1306  assert(consdata != NULL);
1307 
1308  if( SCIPisGT(scip, consdata->violation, SCIPfeastol(scip)) && !SCIPisInfinity(scip, consdata->violation) )
1309  {
1310  SCIP_Real efficacy;
1311 
1312  row = NULL;
1313 
1314  /* generate cut */
1315  if( conshdlrdata->sparsify )
1316  {
1317  SCIP_CALL( generateSparseCut(scip, conshdlr, conss[c], sol, &row, minefficacy) ); /*lint !e613*/
1318 
1319  if( row == NULL )
1320  continue;
1321  }
1322  else
1323  {
1324  if( conshdlrdata->projectpoint )
1325  {
1326  SCIP_CALL( generateCutProjectedPoint(scip, conss[c], sol, &row) ); /*lint !e613*/
1327  }
1328  else
1329  {
1330  SCIP_CALL( generateCutSol(scip, conss[c], sol, &row) ); /*lint !e613*/
1331  }
1332 
1333  efficacy = -SCIPgetRowSolFeasibility(scip, row, sol);
1334  switch( conshdlrdata->scaling )
1335  {
1336  case 'o' :
1337  break;
1338 
1339  case 'g' :
1340  {
1341  SCIP_Real norm;
1342 
1343  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
1344  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up
1345  * too also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers
1346  * (equilibrium scaling) */
1347  norm = SCIPgetRowMaxCoef(scip, row);
1348  efficacy /= MAX(1.0, norm);
1349  break;
1350  }
1351 
1352  case 's' :
1353  {
1354  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
1355  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
1356  SCIP_Real minval = MIN(abslhs, absrhs);
1357 
1358  efficacy /= MAX(1.0, minval);
1359  break;
1360  }
1361 
1362  default:
1363  SCIPerrorMessage("Wrong type of scaling: %c.\n", conshdlrdata->scaling);
1364  SCIPABORT();
1365  return SCIP_INVALIDDATA; /*lint !e527*/
1366  }
1367 
1368  if( SCIPisLE(scip, efficacy, minefficacy) || !SCIPisCutApplicable(scip, row) )
1369  {
1370  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1371  continue;
1372  }
1373  }
1374  assert(row != NULL);
1375 
1376  /* cut cuts off solution and efficient enough */
1377  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
1378  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) ); /*lint !e613*/
1379 
1380  *success = TRUE;
1381 
1382  SCIPdebugMessage("added cut with efficacy %g\n", SCIPgetCutEfficacy(scip, sol, row));
1383 
1384  /* mark row as not removable from LP for current node, if in enforcement */
1385  if( inenforcement && !conshdlrdata->enfocutsremovable )
1386  SCIPmarkRowNotRemovableLocal(scip, row);
1387 
1388  SCIP_CALL( SCIPreleaseRow (scip, &row) );
1389  }
1390 
1391  if( *cutoff )
1392  break;
1393 
1394  /* enforce only useful constraints
1395  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
1396  */
1397  if( c >= nusefulconss && *success )
1398  break;
1399  }
1400 
1401  return SCIP_OKAY;
1402 }
1403 
1404 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
1405  * 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
1406  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
1407  * if separatedlpsol is NULL, then cut is added to cutpool only
1408  */
1409 static
1411  SCIP* scip, /**< SCIP data structure */
1412  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
1413  SCIP_CONS** conss, /**< constraints */
1414  int nconss, /**< number of constraints */
1415  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
1416  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 */
1417  SCIP_Real minefficacy, /**< minimal efficacy of a cut when checking for separation of LP solution */
1418  SCIP_Bool* cutoff /**< pointer to store whether a cutoff was detected */
1419  )
1420 {
1421  SCIP_CONSDATA* consdata;
1422  SCIP_Bool addedtolp;
1423  SCIP_ROW* row;
1424  int c;
1425 
1426  assert(scip != NULL);
1427  assert(conshdlr != NULL);
1428  assert(conss != NULL || nconss == 0);
1429  assert(cutoff != NULL);
1430  *cutoff = FALSE;
1431 
1432  if( separatedlpsol != NULL )
1433  *separatedlpsol = FALSE;
1434 
1435  for( c = 0; c < nconss && !(*cutoff); ++c )
1436  {
1437  assert(conss[c] != NULL); /*lint !e613 */
1438 
1439  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613 */
1440  continue;
1441 
1442  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
1443  assert(consdata != NULL);
1444 
1445  SCIP_CALL( evalLhs(scip, conss[c], ref) ); /*lint !e613 */
1446  if( !SCIPisPositive(scip, consdata->lhsval) || SCIPisInfinity(scip, consdata->lhsval) )
1447  {
1448  SCIPdebugMessage("skip adding linearization for <%s> since lhs is %g\n", SCIPconsGetName(conss[c]), consdata->lhsval); /*lint !e613 */
1449  continue;
1450  }
1451 
1452  SCIP_CALL( generateCutSol(scip, conss[c], ref, &row) ); /*lint !e613 */
1453 
1454  if( row == NULL )
1455  continue;
1456 
1457  addedtolp = FALSE;
1458 
1459  assert(!SCIProwIsLocal(row));
1460 
1461  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
1462  if( separatedlpsol != NULL )
1463  {
1464  SCIP_CONSHDLRDATA* conshdlrdata;
1465  SCIP_Real efficacy;
1466  SCIP_Real norm;
1467 
1468  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1469  assert(conshdlrdata != NULL);
1470 
1471  efficacy = -SCIPgetRowLPFeasibility(scip, row);
1472  switch( conshdlrdata->scaling )
1473  {
1474  case 'o' :
1475  break;
1476 
1477  case 'g' :
1478  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
1479  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
1480  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
1481  * scaling) */
1482  norm = SCIPgetRowMaxCoef(scip, row);
1483  efficacy /= MAX(1.0, norm);
1484  break;
1485 
1486  case 's' :
1487  {
1488  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
1489  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
1490  SCIP_Real minval = MIN(abslhs, absrhs);
1491 
1492  efficacy /= MAX(1.0, minval);
1493  break;
1494  }
1495 
1496  default:
1497  SCIPerrorMessage("Wrong type of scaling: %c.\n", conshdlrdata->scaling);
1498  SCIPABORT();
1499  return SCIP_INVALIDDATA; /*lint !e527*/
1500  }
1501 
1502  if( efficacy >= minefficacy )
1503  {
1504  *separatedlpsol = TRUE;
1505  addedtolp = TRUE;
1506  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, cutoff) );
1507  }
1508  }
1509 
1510  if( !addedtolp )
1511  {
1512  SCIP_CALL( SCIPaddPoolCut(scip, row) );
1513  }
1514 
1515  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1516  }
1517 
1518  return SCIP_OKAY;
1519 }
1520 
1521 /** processes the event that a new primal solution has been found */
1522 static
1523 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
1524 {
1525  SCIP_CONSHDLRDATA* conshdlrdata;
1526  SCIP_CONSHDLR* conshdlr;
1527  SCIP_CONS** conss;
1528  int nconss;
1529  SCIP_SOL* sol;
1530  SCIP_Bool cutoff;
1531 
1532  assert(scip != NULL);
1533  assert(event != NULL);
1534  assert(eventdata != NULL);
1535  assert(eventhdlr != NULL);
1536 
1537  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
1538 
1539  conshdlr = (SCIP_CONSHDLR*)eventdata;
1540 
1541  nconss = SCIPconshdlrGetNConss(conshdlr);
1542 
1543  if( nconss == 0 )
1544  return SCIP_OKAY;
1545 
1546  sol = SCIPeventGetSol(event);
1547  assert(sol != NULL);
1548 
1549  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1550  assert(conshdlrdata != NULL);
1551 
1552  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
1553  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
1554  * or are from the tree, but postprocessed via proposeFeasibleSolution
1555  */
1556  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
1557  return SCIP_OKAY;
1558 
1559  conss = SCIPconshdlrGetConss(conshdlr);
1560  assert(conss != NULL);
1561 
1562  SCIPdebugMessage("caught new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
1563 
1564  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0, &cutoff) );
1565  /* ignore cutoff, cannot return status */
1566 
1567  return SCIP_OKAY;
1568 }
1569 
1570 /** removes fixed variables, replace aggregated and negated variables
1571  *
1572  * repeats replacements until no further change is found;
1573  * takes care of capture/release and locks, but not of variable events (assumes that var events are not caught yet)
1574  */
1575 static
1577  SCIP* scip, /**< SCIP data structure */
1578  SCIP_CONSHDLR* conshdlr, /**< constraint handler for signpower constraints */
1579  SCIP_CONS* cons, /**< constraint */
1580  int* ndelconss, /**< counter for number of deleted constraints */
1581  int* nupgdconss, /**< counter for number of upgraded constraints */
1582  int* nchgbds, /**< counter for number of bound changes */
1583  int* nfixedvars, /**< counter for number of fixed variables */
1584  SCIP_Bool* iscutoff, /**< to store whether constraint cannot be satisfied */
1585  SCIP_Bool* isdeleted /**< to store whether constraint is redundant and can be deleted */
1586  )
1587 {
1588  SCIP_CONSDATA* consdata;
1589  SCIP_CONSHDLRDATA* conshdlrdata;
1590  SCIP_Bool havechange;
1591  SCIP_Bool haveremovedvar;
1592  int i;
1593  SCIP_VAR* x;
1594  SCIP_Real coef;
1595  SCIP_Real offset;
1596 
1597  assert(scip != NULL);
1598  assert(conshdlr != NULL);
1599  assert(cons != NULL);
1600  assert(iscutoff != NULL);
1601  assert(isdeleted != NULL);
1602 
1603  *iscutoff = FALSE;
1604  *isdeleted = FALSE;
1605 
1606  consdata = SCIPconsGetData(cons);
1607  assert(consdata != NULL);
1608 
1609  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1610  assert(conshdlrdata != NULL);
1611 
1612  SCIPdebugMessage("remove fixed variables from constraint <%s>\n", SCIPconsGetName(cons));
1613  SCIPdebugPrintCons(scip, cons, NULL);
1614 
1615  havechange = FALSE;
1616  haveremovedvar = FALSE;
1617 
1618  /* process variables on left hand side */
1619  for( i = 0; i < consdata->nvars; ++i )
1620  {
1621  x = consdata->vars[i];
1622  assert(x != NULL);
1624 
1626  continue;
1627 
1628  havechange = TRUE;
1629 
1630  /* drop variable event and unlock and release variable */
1631  SCIP_CALL( dropLhsVarEvents(scip, conshdlrdata->eventhdlr, cons, i) );
1632  SCIP_CALL( SCIPunlockVarCons(scip, x, cons, TRUE, TRUE) );
1633  SCIP_CALL( SCIPreleaseVar(scip, &consdata->vars[i]) );
1634 
1635  coef = 1.0;
1636  offset = consdata->offsets[i];
1637  SCIP_CALL( SCIPgetProbvarSum(scip, &x, &coef, &offset) );
1638 
1639  SCIPdebugMessage(" lhs term at position %d is replaced by %g * <%s> + %g\n",
1640  i, coef, SCIPvarGetName(x), offset);
1641 
1642  /* if variable has been fixed, add (alpha*offset)^2 to gamma and continue */
1643  if( coef == 0.0 || x == NULL )
1644  {
1645  consdata->constant += consdata->coefs[i] * consdata->coefs[i] * offset * offset;
1646  consdata->offsets[i] = 0.0;
1647  haveremovedvar = TRUE;
1648  continue;
1649  }
1650 
1652 
1653  /* replace coefs[i] * (vars[i] + offsets[i]) by coefs[i]*coef * (x + offsets[i]/coef) */
1654  consdata->offsets[i] = offset;
1655  if( coef != 1.0 )
1656  {
1657  consdata->coefs[i] = REALABS(coef * consdata->coefs[i]);
1658  consdata->offsets[i] /= coef;
1659  }
1660  consdata->vars[i] = x;
1661 
1662  /* capture and lock new variable, catch variable events */
1663  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
1664  SCIP_CALL( SCIPlockVarCons(scip, consdata->vars[i], cons, TRUE, TRUE) );
1665  SCIP_CALL( catchLhsVarEvents(scip, conshdlrdata->eventhdlr, cons, i) );
1666  }
1667 
1668  /* process variable on right hand side */
1669  x = consdata->rhsvar;
1670  assert(x != NULL);
1672  {
1673  havechange = TRUE;
1674 
1675  /* drop variable event and unlock and release variable */
1676  SCIP_CALL( dropRhsVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1677  SCIP_CALL( SCIPreleaseVar(scip, &consdata->rhsvar) );
1678  SCIP_CALL( SCIPunlockVarCons(scip, x, cons, consdata->rhscoeff > 0.0, consdata->rhscoeff < 0.0) );
1679 
1680  coef = 1.0;
1681  offset = 0.0;
1682  SCIP_CALL( SCIPgetProbvarSum(scip, &x, &coef, &offset) );
1683 
1684  SCIPdebugMessage(" rhs variable is replaced by %g * <%s> + %g\n", coef, SCIPvarGetName(x), offset);
1685 
1686  if( coef == 0.0 || x == NULL )
1687  {
1688  /* if variable has been fixed, add offset to rhsoffset */
1689  consdata->rhsoffset += offset;
1690  }
1691  else
1692  {
1693  /* replace rhscoef * (rhsvar + rhsoffset) by rhscoef*coef * (x + offset/coef + rhsoffset/coef) */
1695 
1696  consdata->rhsoffset = (consdata->rhsoffset + offset) / coef;
1697  consdata->rhscoeff *= coef;
1698  consdata->rhsvar = x;
1699 
1700  /* capture and lock new variable, catch variable events */
1701  SCIP_CALL( SCIPcaptureVar(scip, consdata->rhsvar) );
1702  SCIP_CALL( SCIPlockVarCons(scip, consdata->rhsvar, cons, consdata->rhscoeff > 0.0, consdata->rhscoeff < 0.0) );
1703  SCIP_CALL( catchRhsVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1704  }
1705  }
1706 
1707  if( !havechange )
1708  return SCIP_OKAY;
1709 
1710  /* free nonlinear row representation */
1711  if( consdata->nlrow != NULL )
1712  {
1713  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1714  }
1715 
1716  /* if a variable has been removed, close gaps in vars array */
1717  if( haveremovedvar )
1718  {
1719  int oldnvars;
1720 
1721  /* due to the realloc of the block memory below and the way we store the eventdata in consdata, we best drop all events here and catch them again below */
1722  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1723 
1724  oldnvars = consdata->nvars;
1725  for( i = 0; i < consdata->nvars; ++i )
1726  {
1727  /* forget about empty places at end of vars array */
1728  while( consdata->nvars && consdata->vars[consdata->nvars-1] == NULL )
1729  --consdata->nvars;
1730 
1731  /* all variables at index >= i have been removed */
1732  if( i == consdata->nvars )
1733  break;
1734 
1735  if( consdata->vars[i] != NULL )
1736  continue;
1737 
1738  /* move variable from position nvars-1 to position i */
1739 
1740  assert(consdata->nvars >= 1);
1741  assert(consdata->vars[consdata->nvars-1] != NULL);
1742 
1743  consdata->vars[i] = consdata->vars[consdata->nvars-1];
1744  consdata->offsets[i] = consdata->offsets[consdata->nvars-1];
1745  consdata->coefs[i] = consdata->coefs[consdata->nvars-1];
1746 
1747  --consdata->nvars;
1748  }
1749 
1750  assert(consdata->nvars < oldnvars);
1751 
1752  /* shrink arrays in consdata */
1753  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, oldnvars, consdata->nvars) );
1754  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->offsets, oldnvars, consdata->nvars) );
1755  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->coefs, oldnvars, consdata->nvars) );
1756 
1757  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
1758  }
1759 
1760  SCIPdebugMessage("\t-> ");
1761  SCIPdebugPrintCons(scip, cons, NULL);
1762 
1763  if( consdata->nvars == 0 )
1764  { /* all variables on left hand size have been removed, remaining constraint is sqrt(gamma) <= ... */
1765  assert(!SCIPisNegative(scip, consdata->constant));
1766  if( consdata->rhsvar == NULL )
1767  { /* also rhsvar has been removed, remaining constraint is sqrt(gamma) <= rhscoeff * rhsoffset */
1768  if( SCIPisFeasLE(scip, sqrt(consdata->constant), consdata->rhscoeff*consdata->rhsoffset) )
1769  {
1770  SCIPdebugMessage("remove redundant constraint <%s> after fixing all variables\n", SCIPconsGetName(cons));
1771  }
1772  else
1773  {
1774  SCIPdebugMessage("found problem infeasible after fixing all variables in <%s>\n", SCIPconsGetName(cons));
1775  *iscutoff = TRUE;
1776  }
1777  ++*ndelconss;
1778  }
1779  else if( !SCIPvarIsActive(consdata->rhsvar) )
1780  { /* remaining constraint is sqrt(gamma) - rhscoeff * rhsoffset <= rhscoeff * rhsvar, and rhsvar is probably multi-aggregated */
1781  SCIP_CONS* lincons;
1782 
1783  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons), 1, &consdata->rhsvar, &consdata->rhscoeff,
1784  sqrt(consdata->constant) - consdata->rhscoeff * consdata->rhsoffset, SCIPinfinity(scip),
1788  SCIPconsIsStickingAtNode(cons)) );
1789  SCIP_CALL( SCIPaddCons(scip, lincons) );
1790  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
1791  ++*nupgdconss;
1792  }
1793  else if( consdata->rhscoeff > 0.0 )
1794  { /* remaining constraint is sqrt(gamma) / rhscoeff - rhsoffset <= rhsvar */
1795  SCIP_Bool tightened;
1796  SCIP_CALL( SCIPtightenVarLb(scip, consdata->rhsvar, sqrt(consdata->constant) / consdata->rhscoeff - consdata->rhsoffset, TRUE, iscutoff, &tightened) );
1797  if( *iscutoff )
1798  {
1799  SCIPdebugMessage("found problem infeasible after fixing all lhs variables in <%s> and tightening lower bound of rhs var\n", SCIPconsGetName(cons));
1800  }
1801  else if( tightened )
1802  {
1803  SCIPdebugMessage("remove redundant constraint <%s> after fixing all lhs variables and tightening lower bound of rhs var\n", SCIPconsGetName(cons));
1804  ++*nchgbds;
1805  }
1806  else
1807  {
1808  SCIPdebugMessage("remove redundant constraint <%s> after fixing all lhs variables\n", SCIPconsGetName(cons));
1809  }
1810  ++*ndelconss;
1811  }
1812  else
1813  { /* remaining constraint is sqrt(gamma) / rhscoeff - rhsoffset >= rhsvar */
1814  SCIP_Bool tightened;
1815  SCIP_CALL( SCIPtightenVarUb(scip, consdata->rhsvar, sqrt(consdata->constant) / consdata->rhscoeff - consdata->rhsoffset, TRUE, iscutoff, &tightened) );
1816  if( *iscutoff )
1817  {
1818  SCIPdebugMessage("found problem infeasible after fixing all lhs variables in <%s> and tightening upper bound of rhs var\n", SCIPconsGetName(cons));
1819  }
1820  else if( tightened )
1821  {
1822  SCIPdebugMessage("remove redundant constraint <%s> after fixing all lhs variables and tightening upper bound of rhs var\n", SCIPconsGetName(cons));
1823  ++*nchgbds;
1824  }
1825  else
1826  {
1827  SCIPdebugMessage("remove redundant constraint <%s> after fixing all lhs variables\n", SCIPconsGetName(cons));
1828  }
1829  ++*ndelconss;
1830  }
1831  SCIP_CALL( SCIPdelCons(scip, cons) );
1832  *isdeleted = TRUE;
1833  return SCIP_OKAY;
1834  }
1835 
1836  if( consdata->rhsvar == NULL )
1837  { /* constraint becomes sum_i (alpha_i*(x_i+beta_i))^2 <= (rhscoeff*rhsoffset)^2 - gamma */
1838  if( consdata->nvars > 1 )
1839  { /* upgrade to quadratic constraint */
1840  SCIP_CONS* quadcons;
1841  SCIP_QUADVARTERM* quadvarterms;
1842  SCIP_Real rhs;
1843 
1844  SCIP_CALL( SCIPallocBufferArray(scip, &quadvarterms, consdata->nvars) );
1845  BMSclearMemoryArray(quadvarterms, consdata->nvars);
1846  rhs = consdata->rhscoeff * consdata->rhsoffset;
1847  rhs = rhs * rhs - consdata->constant;
1848 
1849  for( i = 0; i < consdata->nvars; ++i )
1850  {
1851  quadvarterms[i].var = consdata->vars[i];
1852  quadvarterms[i].sqrcoef = consdata->coefs[i] * consdata->coefs[i];
1853  if( consdata->offsets[i] != 0.0 )
1854  {
1855  quadvarterms[i].lincoef = 2 * consdata->offsets[i] * quadvarterms[i].sqrcoef;
1856  rhs -= quadvarterms[i].sqrcoef * consdata->offsets[i]*consdata->offsets[i];
1857  }
1858  }
1859 
1860  assert(!SCIPconsIsStickingAtNode(cons));
1861  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &quadcons, SCIPconsGetName(cons), 0, NULL, NULL,
1862  consdata->nvars, quadvarterms, 0, NULL, -SCIPinfinity(scip), rhs,
1866  SCIP_CALL( SCIPaddCons(scip, quadcons) );
1867  SCIPdebugMessage("upgraded <%s> to quadratic constraint: ", SCIPconsGetName(cons));
1868  SCIPdebugPrintCons(scip, quadcons, NULL);
1869 
1870  SCIP_CALL( SCIPreleaseCons(scip, &quadcons) );
1871 
1872  SCIPfreeBufferArray(scip, &quadvarterms);
1873 
1874  ++*nupgdconss;
1875  }
1876  else if( !SCIPvarIsActive(consdata->vars[0]) )
1877  { /* constraint is |alpha*(x+beta)| <= sqrt((rhscoeff*rhsoffset)^2 - gamma), but x is probably multaggr. -> turn into ranged linear constraint */
1878  SCIP_CONS* lincons;
1879 
1880  /* create constraint alpha*x <= sqrt((rhscoeff*rhsoffset)^2 - gamma) - alpha*beta
1881  * alpha*x >= -sqrt((rhscoeff*rhsoffset)^2 - gamma) - alpha*beta */
1882  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons), 1, &consdata->vars[0], &consdata->coefs[0],
1883  -sqrt(consdata->rhscoeff * consdata->rhscoeff * consdata->rhsoffset * consdata->rhsoffset - consdata->constant) - consdata->coefs[0] * consdata->offsets[0],
1884  +sqrt(consdata->rhscoeff * consdata->rhscoeff * consdata->rhsoffset * consdata->rhsoffset - consdata->constant) - consdata->coefs[0] * consdata->offsets[0],
1888  SCIPconsIsStickingAtNode(cons)) );
1889  SCIP_CALL( SCIPaddCons(scip, lincons) );
1890  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
1891 
1892  ++*nupgdconss;
1893  }
1894  else
1895  { /* constraint is |alpha*(x+beta)| <= sqrt((rhscoeff*rhsoffset)^2 - gamma) -> propagate bounds */
1896  SCIP_Bool tightened;
1897  SCIP_Real rhs;
1898  assert(consdata->nvars == 1); /* case == 0 handled before */
1899  rhs = consdata->rhscoeff * consdata->rhsoffset;
1900  rhs = rhs * rhs;
1901  if( SCIPisNegative(scip, rhs - consdata->constant) )
1902  { /* take this as infeasible */
1903  SCIPdebugMessage("found problem infeasible after fixing rhs and all except one lhs variables in <%s>\n", SCIPconsGetName(cons));
1904  *iscutoff = TRUE;
1905  }
1906  else
1907  {
1908  rhs -= consdata->constant;
1909  rhs = rhs < 0.0 ? 0.0 : sqrt(rhs);
1910 
1911  if( SCIPisZero(scip, rhs) )
1912  { /* constraint is x = -beta */
1913  SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], -consdata->offsets[0], iscutoff, &tightened) );
1914  if( *iscutoff )
1915  {
1916  SCIPdebugMessage("found problem infeasible after fixing rhs and all except one lhs variables and fixing remaining lhs var in <%s>\n", SCIPconsGetName(cons));
1917  }
1918  else if( tightened )
1919  {
1920  SCIPdebugMessage("remove redundant constraint <%s> after fixing rhs and all except one lhs variables and fixing remaining lhs var\n", SCIPconsGetName(cons));
1921  ++*nfixedvars;
1922  }
1923  else
1924  {
1925  SCIPdebugMessage("remove redundant constraint <%s> after fixing rhs and all except one lhs variables and fixing remaining lhs var\n", SCIPconsGetName(cons));
1926  }
1927  }
1928  else
1929  { /* constraint is -rhs/|alpha| - beta <= x <= rhs/|alpha| - beta */
1930  rhs /= ABS(consdata->coefs[0]);
1931  SCIP_CALL( SCIPtightenVarLb(scip, consdata->vars[0], -rhs - consdata->offsets[0], TRUE, iscutoff, &tightened) );
1932  if( *iscutoff )
1933  {
1934  SCIPdebugMessage("found problem infeasible after fixing rhs and all except one lhs variables and tightening lower bound of remaining lhs var in <%s>\n", SCIPconsGetName(cons));
1935  }
1936  else
1937  {
1938  if( tightened )
1939  ++*nchgbds;
1940  SCIP_CALL( SCIPtightenVarUb(scip, consdata->vars[0], rhs - consdata->offsets[0], TRUE, iscutoff, &tightened) );
1941  if( *iscutoff )
1942  {
1943  SCIPdebugMessage("found problem infeasible after fixing rhs and all except one lhs variables and tightening upper bound of remaining lhs var in <%s>\n", SCIPconsGetName(cons));
1944  }
1945  else if( tightened )
1946  ++*nchgbds;
1947  }
1948  if( !*iscutoff )
1949  {
1950  SCIPdebugMessage("remove redundant constraint <%s> after fixing rhs and all except one lhs variables and tightening bounds on remaining lhs var\n", SCIPconsGetName(cons));
1951  }
1952  }
1953  }
1954  ++*ndelconss;
1955  }
1956  *isdeleted = TRUE;
1957  SCIP_CALL( SCIPdelCons(scip, cons) );
1958  return SCIP_OKAY;
1959  }
1960 
1961  if( consdata->nvars == 1 && SCIPisZero(scip, consdata->constant) )
1962  { /* one variable on lhs left and no constant, constraint becomes |alpha*(x+beta)| <= rhscoef*(rhsvar+rhsoffset) -> upgrade to two linear constraints */
1963  SCIP_CONS* lincons;
1964  SCIP_VAR* vars[2];
1965  SCIP_Real coefs[2];
1966  SCIP_Real rhs;
1967  assert(consdata->rhsvar != NULL); /* case == NULL has been handled before */
1968 
1969  vars[0] = consdata->vars[0];
1970  vars[1] = consdata->rhsvar;
1971  coefs[0] = consdata->coefs[0];
1972  coefs[1] = -consdata->rhscoeff;
1973  rhs = consdata->rhscoeff * consdata->rhsoffset - coefs[0] * consdata->offsets[0];
1974 
1975  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons), 2, vars, coefs, -SCIPinfinity(scip), rhs,
1979  SCIPconsIsStickingAtNode(cons)) );
1980  SCIP_CALL( SCIPaddCons(scip, lincons) );
1981  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
1982 
1983  coefs[0] = -coefs[0];
1984  rhs = consdata->rhscoeff * consdata->rhsoffset - coefs[0] * consdata->offsets[0];
1985 
1986  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons), 2, vars, coefs, -SCIPinfinity(scip), rhs,
1990  SCIPconsIsStickingAtNode(cons)) );
1991  SCIP_CALL( SCIPaddCons(scip, lincons) );
1992  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
1993 
1994  SCIPdebugMessage("upgraded <%s> to two linear constraint\n", SCIPconsGetName(cons));
1995 
1996  ++*nupgdconss;
1997  SCIP_CALL( SCIPdelCons(scip, cons) );
1998  *isdeleted = TRUE;
1999  return SCIP_OKAY;
2000  }
2001 
2002  return SCIP_OKAY;
2003 }
2004 
2005 
2006 /** adds the linear outer-approximation of Glineur et.al. for a SOC constraint of dimension 3
2007  *
2008  * Input is the data for a constraint \f$\sqrt{(\alpha_1(x_1+offset1))^2 + (\alpha_2(x_2+offset2))^2) \leq \alpha_3(x_3+offset3)}\f$.
2009  * Here constant >= 0.0, alpha3 > 0.0, and the lower bound of x3 >= -offset3.
2010  * Also x2 = NULL is allowed, in which case the second term is assumed to be constant, and offset2 != 0 is needed.
2011  */
2012 static
2014  SCIP* scip, /**< SCIP data structure */
2015  SCIP_CONS* cons, /**< original constraint */
2016  SCIP_VAR* x1, /**< variable x1 */
2017  SCIP_VAR* x2, /**< variable x2 */
2018  SCIP_VAR* x3, /**< variable x3 */
2019  SCIP_Real alpha1, /**< coefficient of x1 */
2020  SCIP_Real alpha2, /**< coefficient of x2 */
2021  SCIP_Real alpha3, /**< coefficient of x3 */
2022  SCIP_Real offset1, /**< offset of x1 */
2023  SCIP_Real offset2, /**< offset of x2 */
2024  SCIP_Real offset3, /**< offset of x3 */
2025  int N, /**< size of linear approximation, need to be >= 1 */
2026  const char* basename, /**< string to use for building variable and constraint names */
2027  int* naddconss /**< buffer where to add the number of added constraints */
2028  )
2029 {
2030  SCIP_CONS* lincons;
2031  SCIP_VAR* vars[3];
2032  SCIP_Real vals[3];
2033  char varname[255];
2034  char linname[255];
2035  int i;
2036  SCIP_VAR** avars;
2037  SCIP_VAR** bvars;
2038  SCIP_Real val;
2039 
2040  assert(scip != NULL);
2041  assert(cons != NULL);
2042  assert(x1 != NULL);
2043  assert(x2 != NULL || !SCIPisZero(scip, offset2));
2044  assert(x3 != NULL);
2045  assert(SCIPisPositive(scip, alpha3));
2046  assert(SCIPisGE(scip, SCIPconsIsLocal(cons) ? SCIPvarGetLbLocal(x3) : SCIPvarGetLbGlobal(x3), -offset3));
2047  assert(basename != NULL);
2048  assert(N >= 1);
2049  assert(naddconss != NULL);
2050 
2051  SCIPdebugMessage("Creating linear Glineur outer-approximation for <%s>.\n", basename);
2052  SCIPdebugMessage("sqr(%g(%s+%g)) + sqr(%g(%s+%g)) <= sqr(%g(%s+%g)).\n",
2053  alpha1, SCIPvarGetName(x1), offset1, alpha2, x2 ? SCIPvarGetName(x2) : "0", offset2, alpha3, SCIPvarGetName(x3), offset3
2054  );
2055 
2056  SCIP_CALL( SCIPallocBufferArray(scip, &avars, N+1) );
2057  SCIP_CALL( SCIPallocBufferArray(scip, &bvars, N+1) );
2058 
2059  /* create additional variables; we do not use avars[0] and bvars[0] */
2060  for( i = 1; i <= N; ++i )
2061  {
2062  (void) SCIPsnprintf(varname, 255, "soc#%s_a%d", basename, i);
2063  SCIP_CALL( SCIPcreateVar(scip, &avars[i], varname, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2065  SCIP_CALL( SCIPaddVar(scip, avars[i]) );
2066 
2067  (void) SCIPsnprintf(varname, 255, "soc#%s_b%d", basename, i);
2068  SCIP_CALL( SCIPcreateVar(scip, &bvars[i], varname, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2070  SCIP_CALL( SCIPaddVar(scip, bvars[i]) );
2071  }
2072 
2073  /* create linear constraints for the first case
2074  * cos(pi) = -1, sin(pi) = 0
2075  * -> a_1 = - alpha1 (x1 + offset1) -> -alpha1*x1 - a_1 = alpha1*offset1
2076  * -> b_1 >= | alpha2 (x2 + offset2) | -> alpha2*x2 - b_1 <= -alpha2*offset2
2077  * alpha2*x2 + b_1 >= -alpha2*offset2
2078  */
2079 
2080  vars[0] = x1;
2081  vals[0] = -alpha1;
2082  vars[1] = avars[1];
2083  vals[1] = -1.0;
2084 
2085  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, 0);
2086  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, alpha1*offset1, alpha1*offset1,
2092  SCIP_CALL( SCIPaddCons(scip, lincons) );
2093  SCIPdebugPrintCons(scip, lincons, NULL);
2094  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2095  ++*naddconss;
2096 
2097  if( x2 != NULL )
2098  {
2099  vars[0] = x2;
2100  vals[0] = alpha2;
2101  vars[1] = bvars[1];
2102  vals[1] = -1.0;
2103 
2104  (void) SCIPsnprintf(linname, 255, "soc#%s#b%d", basename, 0);
2105  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, -SCIPinfinity(scip), -alpha2*offset2,
2111  SCIP_CALL( SCIPaddCons(scip, lincons) );
2112  SCIPdebugPrintCons(scip, lincons, NULL);
2113  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2114  ++*naddconss;
2115 
2116  vars[0] = x2;
2117  vals[0] = alpha2;
2118  vars[1] = bvars[1];
2119  vals[1] = 1.0;
2120 
2121  (void) SCIPsnprintf(linname, 255, "soc#%s#B%d", basename, 0);
2122  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, -alpha2*offset2, SCIPinfinity(scip),
2128  SCIP_CALL( SCIPaddCons(scip, lincons) );
2129  SCIPdebugPrintCons(scip, lincons, NULL);
2130  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2131  ++*naddconss;
2132  }
2133  else
2134  { /* x2 == NULL -> b_1 >= |alpha2*offset2| */
2135  SCIP_Bool infeas;
2136  SCIP_Bool tightened;
2137  SCIP_CALL( SCIPtightenVarLb(scip, bvars[1], ABS(alpha2 * offset2), TRUE, &infeas, &tightened) );
2138  if( infeas == TRUE )
2139  {
2140  SCIPwarningMessage(scip, "creating glineur outer approximation of SOC3 constraint found problem infeasible.\n");
2141  }
2142  }
2143 
2144  /* create intermediate linear constraints */
2145  val = M_PI;
2146  for( i = 1; i < N; ++i )
2147  {
2148  val /= 2.0;
2149 
2150  vars[0] = avars[i];
2151  vals[0] = cos(val);
2152  vars[1] = bvars[i];
2153  vals[1] = sin(val);
2154  vars[2] = avars[i+1];
2155  vals[2] = -1.0;
2156 
2157  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, i);
2158  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, 0.0, 0.0,
2164  SCIP_CALL( SCIPaddCons(scip, lincons) );
2165  SCIPdebugPrintCons(scip, lincons, NULL);
2166  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2167  ++*naddconss;
2168 
2169  vars[0] = avars[i];
2170  vals[0] = -sin(val);
2171  vars[1] = bvars[i];
2172  vals[1] = cos(val);
2173  vars[2] = bvars[i+1];
2174  vals[2] = -1.0;
2175 
2176  (void) SCIPsnprintf(linname, 255, "soc#%s#b%d", basename, i);
2177  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, -SCIPinfinity(scip), 0.0,
2183  SCIP_CALL( SCIPaddCons(scip, lincons) );
2184  SCIPdebugPrintCons(scip, lincons, NULL);
2185  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2186  ++*naddconss;
2187 
2188  vars[0] = avars[i];
2189  vals[0] = -sin(val);
2190  vars[1] = bvars[i];
2191  vals[1] = cos(val);
2192  vars[2] = bvars[i+1];
2193  vals[2] = 1.0;
2194 
2195  (void) SCIPsnprintf(linname, 255, "soc#%s#B%d", basename, i);
2196  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, 0.0, SCIPinfinity(scip),
2202  SCIP_CALL( SCIPaddCons(scip, lincons) );
2203  SCIPdebugPrintCons(scip, lincons, NULL);
2204  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2205  ++*naddconss;
2206  }
2207 
2208  /* create last linear constraint */
2209  val /= 2.0;
2210  vars[0] = avars[N];
2211  vals[0] = -cos(val);
2212  vars[1] = bvars[N];
2213  vals[1] = -sin(val);
2214  vars[2] = x3;
2215  vals[2] = alpha3;
2216 
2217  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, N);
2218  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, -alpha3*offset3, -alpha3*offset3,
2224  SCIP_CALL( SCIPaddCons(scip, lincons) );
2225  SCIPdebugPrintCons(scip, lincons, NULL);
2226  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2227  ++*naddconss;
2228 
2229  for( i = 1; i <= N; ++i )
2230  {
2231  SCIP_CALL( SCIPreleaseVar(scip, &avars[i]) );
2232  SCIP_CALL( SCIPreleaseVar(scip, &bvars[i]) );
2233  }
2234  SCIPfreeBufferArray(scip, &avars);
2235  SCIPfreeBufferArray(scip, &bvars);
2236 
2237  return SCIP_OKAY;
2238 }
2239 
2240 /** adds the linear outer-approximation of Ben-Tal and Nemirovski for a SOC constraint of dimension 3
2241  *
2242  * Input is the data for a constraint \f$\sqrt{constant + (\alpha_1(x_1+offset1))^2 + (\alpha_2(x_2+offset2))^2) \leq \alpha_3(x_3+offset3)}\f$.
2243  * Here constant >= 0.0, alpha3 > 0.0, and the lower bound of x3 >= -offset3.
2244  * Also x2 = NULL is allowed, in which case the second term is assumed to be constant, and offset2 != 0 is needed.
2245  * */
2246 static
2248  SCIP* scip, /**< SCIP data structure */
2249  SCIP_CONS* cons, /**< original constraint */
2250  SCIP_VAR* x1, /**< variable x1 */
2251  SCIP_VAR* x2, /**< variable x2 */
2252  SCIP_VAR* x3, /**< variable x3 */
2253  SCIP_Real alpha1, /**< coefficient of x1 */
2254  SCIP_Real alpha2, /**< coefficient of x2 */
2255  SCIP_Real alpha3, /**< coefficient of x3 */
2256  SCIP_Real offset1, /**< offset of x1 */
2257  SCIP_Real offset2, /**< offset of x2 */
2258  SCIP_Real offset3, /**< offset of x3 */
2259  int N, /**< size of linear approximation, need to be >= 1 */
2260  const char* basename, /**< string to use for building variable and constraint names */
2261  int* naddconss /**< buffer where to add the number of added constraints */
2262  )
2263 {
2264  SCIP_CONS* lincons;
2265  SCIP_VAR* vars[3];
2266  SCIP_Real vals[3];
2267  char varname[255];
2268  char linname[255];
2269  int i;
2270  SCIP_VAR** avars;
2271  SCIP_VAR** bvars;
2272 
2273  assert(scip != NULL);
2274  assert(cons != NULL);
2275  assert(x1 != NULL);
2276  assert(x2 != NULL || !SCIPisZero(scip, offset2));
2277  assert(x3 != NULL);
2278  assert(SCIPisPositive(scip, alpha3));
2279  assert(SCIPisGE(scip, SCIPconsIsLocal(cons) ? SCIPvarGetLbLocal(x3) : SCIPvarGetLbGlobal(x3), -offset3));
2280  assert(basename != NULL);
2281  assert(N >= 1);
2282  assert(naddconss != NULL);
2283 
2284  SCIPdebugMessage("Creating linear Ben-Tal Nemirovski outer-approximation for <%s>.\n", basename);
2285 
2286  SCIP_CALL( SCIPallocBufferArray(scip, &avars, N+1) );
2287  SCIP_CALL( SCIPallocBufferArray(scip, &bvars, N+1) );
2288 
2289  /* create additional variables */
2290  for( i = 0; i <= N; ++i )
2291  {
2292  (void) SCIPsnprintf(varname, 255, "soc#%s_a%d", basename, i);
2293  SCIP_CALL( SCIPcreateVar(scip, &avars[i], varname, 0.0, SCIPinfinity(scip), 0.0,
2295  SCIP_CALL( SCIPaddVar(scip, avars[i]) );
2296 
2297  (void) SCIPsnprintf(varname, 255, "soc#%s_b%d", basename, i);
2298  SCIP_CALL( SCIPcreateVar(scip, &bvars[i], varname, 0.0, SCIPinfinity(scip), 0.0,
2300  SCIP_CALL( SCIPaddVar(scip, bvars[i]) );
2301  }
2302 
2303  /* create first linear constraints - split into two because of the absolute value */
2304  vars[0] = avars[0];
2305  vals[0] = 1.0;
2306  vars[1] = x1;
2307  vals[1] = -alpha1;
2308 
2309  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, 0);
2310  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, alpha1 * offset1, SCIPinfinity(scip),
2315  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2316  SCIP_CALL( SCIPaddCons(scip, lincons) );
2317  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2318  ++*naddconss;
2319 
2320  vars[0] = avars[0];
2321  vals[0] = 1.0;
2322  vars[1] = x1;
2323  vals[1] = alpha1;
2324 
2325  (void) SCIPsnprintf(linname, 255, "soc#%s#A%d", basename, 0);
2326  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, -alpha1 * offset1, SCIPinfinity(scip),
2331  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2332  SCIP_CALL( SCIPaddCons(scip, lincons) );
2333  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2334  ++*naddconss;
2335 
2336  if( x2 != NULL )
2337  {
2338  vars[0] = bvars[0];
2339  vals[0] = 1.0;
2340  vars[1] = x2;
2341  vals[1] = -alpha2;
2342 
2343  (void) SCIPsnprintf(linname, 255, "soc#%s#b%d", basename, 0);
2344  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, alpha2 * offset2, SCIPinfinity(scip),
2349  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2350  SCIP_CALL( SCIPaddCons(scip, lincons) );
2351  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2352  ++*naddconss;
2353 
2354  vars[0] = bvars[0];
2355  vals[0] = 1.0;
2356  vars[1] = x2;
2357  vals[1] = alpha2;
2358 
2359  (void) SCIPsnprintf(linname, 255, "soc#%s#B%d", basename, 0);
2360  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, -alpha2 * offset2, SCIPinfinity(scip),
2365  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2366  SCIP_CALL( SCIPaddCons(scip, lincons) );
2367  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2368  ++*naddconss;
2369  }
2370  else
2371  { /* second summand is just a constant */
2372  if( SCIPconsIsLocal(cons) )
2373  {
2374  SCIP_CALL( SCIPchgVarLbNode(scip, NULL, bvars[0], ABS(alpha2 * offset2)) );
2375  }
2376  else
2377  {
2378  SCIP_CALL( SCIPchgVarLbGlobal(scip, bvars[0], ABS(alpha2 * offset2)) );
2379  }
2380  }
2381 
2382  /* create intermediate linear constraints */
2383  for( i = 1; i <= N; ++i )
2384  {
2385  SCIP_Real val;
2386 
2387  val = M_PI / pow(2.0, (double) (i+1));
2388 
2389  vars[0] = avars[i-1];
2390  vals[0] = cos(val);
2391  vars[1] = bvars[i-1];
2392  vals[1] = sin(val);
2393  vars[2] = avars[i];
2394  vals[2] = -1.0;
2395 
2396  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, i);
2397  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, 0.0, 0.0,
2402  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2403  SCIP_CALL( SCIPaddCons(scip, lincons) );
2404  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2405  ++*naddconss;
2406 
2407  vars[0] = avars[i-1];
2408  vals[0] = sin(val);
2409  vars[1] = bvars[i-1];
2410  vals[1] = -cos(val);
2411  vars[2] = bvars[i];
2412  vals[2] = 1.0;
2413 
2414  (void) SCIPsnprintf(linname, 255, "soc#%s#b%d", basename, i);
2415  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, 0.0, SCIPinfinity(scip),
2420  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2421  SCIP_CALL( SCIPaddCons(scip, lincons) );
2422  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2423  ++*naddconss;
2424 
2425  vars[0] = avars[i-1];
2426  vals[0] = -sin(val);
2427  vars[1] = bvars[i-1];
2428  vals[1] = cos(val);
2429  vars[2] = bvars[i];
2430  vals[2] = 1.0;
2431 
2432  (void) SCIPsnprintf(linname, 255, "soc#%s#B%d", basename, i);
2433  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 3, vars, vals, 0.0, SCIPinfinity(scip),
2438  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2439  SCIP_CALL( SCIPaddCons(scip, lincons) );
2440  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2441  ++*naddconss;
2442  }
2443 
2444  /* create last linear constraints */
2445  vars[0] = x3;
2446  vals[0] = alpha3;
2447  vars[1] = avars[N];
2448  vals[1] = -1.0;
2449 
2450  (void) SCIPsnprintf(linname, 255, "soc#%s#a%d", basename, N);
2451  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, -alpha3 * offset3, SCIPinfinity(scip),
2457  SCIP_CALL( SCIPaddCons(scip, lincons) );
2458  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2459  ++*naddconss;
2460 
2461  vars[0] = avars[N];
2462  vals[0] = tan( M_PI / pow(2.0, (double) (N+1)) );
2463  vars[1] = bvars[N];
2464  vals[1] = -1.0;
2465 
2466  (void) SCIPsnprintf(linname, 255, "soc#%s#b%d", basename, i);
2467  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, linname, 2, vars, vals, 0.0, SCIPinfinity(scip),
2472  TRUE /* removable */, SCIPconsIsStickingAtNode(cons)) );
2473  SCIP_CALL( SCIPaddCons(scip, lincons) );
2474  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
2475  ++*naddconss;
2476 
2477  for( i = 0; i <= N; ++i )
2478  {
2479  SCIP_CALL( SCIPreleaseVar(scip, &avars[i]) );
2480  SCIP_CALL( SCIPreleaseVar(scip, &bvars[i]) );
2481  }
2482  SCIPfreeBufferArray(scip, &avars);
2483  SCIPfreeBufferArray(scip, &bvars);
2484 
2485  return SCIP_OKAY;
2486 }
2487 
2488 /** adds a linear outer approx for a three dimensional SOC constraint
2489  *
2490  * chooses between Ben-Tan/Nemirovski and Glineur and calls the corresponding function
2491  */
2492 static
2494  SCIP* scip, /**< SCIP data structure */
2495  SCIP_CONS* cons, /**< original constraint */
2496  SCIP_VAR* x1, /**< variable x1 */
2497  SCIP_VAR* x2, /**< variable x2 */
2498  SCIP_VAR* x3, /**< variable x3 */
2499  SCIP_Real alpha1, /**< coefficient of x1 */
2500  SCIP_Real alpha2, /**< coefficient of x2 */
2501  SCIP_Real alpha3, /**< coefficient of x3 */
2502  SCIP_Real offset1, /**< offset of x1 */
2503  SCIP_Real offset2, /**< offset of x2 */
2504  SCIP_Real offset3, /**< offset of x3 */
2505  int N, /**< size of linear approximation, need to be >= 1 */
2506  SCIP_Bool glineur, /**< whether to prefer Glineur to Ben-Tal Nemirovski */
2507  const char* basename, /**< string to use for building variable and constraint names */
2508  int* naddconss /**< buffer where to add the number of added constraints */
2509  )
2510 {
2511  if( glineur )
2512  {
2513  SCIP_CALL( presolveCreateGlineurApproxDim3(scip, cons, x1, x2, x3, alpha1, alpha2, alpha3, offset1, offset2, offset3, N, basename, naddconss) );
2514  }
2515  else
2516  {
2517  SCIP_CALL( presolveCreateBenTalNemirovskiApproxDim3(scip, cons, x1, x2, x3, alpha1, alpha2, alpha3, offset1, offset2, offset3, N, basename, naddconss) );
2518  }
2519 
2520  return SCIP_OKAY;
2521 }
2522 
2523 /** adds linear outer approximation of Ben-Tal and Nemirovski for a constraint \f$\gamma + \sum_{i=1}^n (\alpha_i (x_i + \beta_i))^2 <= (\alpha_{n+1} (x_{n+1} + \beta_{n+1}))^2\f$ to the LP
2524  *
2525  * if n>2, calls same function recursively;
2526  * if n=2, calls presolveCreateBenTalNemirovskiApproxDim3
2527  */
2528 static
2530  SCIP* scip, /**< SCIP data structure */
2531  int nlhsvars, /**< number of variables on left hand side (n) */
2532  SCIP_VAR** lhsvars, /**< variables on left hand side (x_i) */
2533  SCIP_Real* lhscoefs, /**< coefficients of variables on left hand side (alpha_i) */
2534  SCIP_Real* lhsoffsets, /**< offsets of variable on left hand side (beta_i) */
2535  SCIP_VAR* rhsvar, /**< variable on right hand side (y) */
2536  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
2537  SCIP_Real rhsoffset, /**< offset of variable on right hand side (beta_{n+1}) */
2538  SCIP_Real constant, /**< constant term (gamma) */
2539  const char* basename, /**< prefix for variable and constraint name */
2540  SCIP_CONS* origcons, /**< original constraint for which this SOC3 set is added */
2541  int soc3_nr_auxvars, /**< number of auxiliary variables to use for a SOC3 constraint, or 0 if automatic */
2542  SCIP_Bool glineur, /**< whether Glineur should be preferred to Ben-Tal Nemirovski */
2543  int* naddconss /**< buffer where to add the number of added constraints */
2544  )
2545 {
2546  char name[255];
2547  SCIP_VAR* auxvar1;
2548  SCIP_VAR* auxvar2;
2549 
2550  assert(scip != NULL);
2551  assert(lhsvars != NULL);
2552  assert(nlhsvars >= 2);
2553  assert(lhscoefs != NULL);
2554  assert(lhsoffsets != NULL);
2555  assert(rhsvar != NULL);
2556  assert(basename != NULL);
2557  assert(!SCIPisNegative(scip, constant));
2558  assert(naddconss != NULL);
2559 
2560  if( nlhsvars == 1 )
2561  { /* end of recursion */
2562  assert(SCIPisPositive(scip, constant));
2563  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2564  lhsvars[0], NULL, rhsvar,
2565  lhscoefs[0], 1.0, rhscoeff,
2566  lhsoffsets[0], sqrt(constant), rhsoffset,
2567  soc3_nr_auxvars, glineur, basename, naddconss) );
2568 
2569  return SCIP_OKAY;
2570  }
2571 
2572  if( nlhsvars == 2 && SCIPisZero(scip, constant) )
2573  { /* end of recursion */
2574  assert(lhsvars[0] != NULL);
2575  assert(lhsvars[1] != NULL);
2576  assert(rhsvar != NULL);
2577  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2578  lhsvars[0], lhsvars[1], rhsvar,
2579  lhscoefs[0], lhscoefs[1], rhscoeff,
2580  lhsoffsets[0], lhsoffsets[1], rhsoffset,
2581  soc3_nr_auxvars, glineur, basename, naddconss) );
2582 
2583  return SCIP_OKAY;
2584  }
2585 
2586  if( nlhsvars == 3 || (nlhsvars == 2 && !SCIPisZero(scip, constant)) )
2587  {
2588  /* a bit special case too */
2589  /* for first two variables on lhs, create a new aux.var and a new SOC3 */
2590  (void) SCIPsnprintf(name, 255, "%s#z1", basename);
2591  SCIP_CALL( SCIPcreateVar(scip, &auxvar1, name, 0.0, SCIPinfinity(scip), 0.0,
2593  SCIP_CALL( SCIPaddVar(scip, auxvar1) );
2594 
2595  /* constraint alpha_0 (x_0+beta0)^2 + alpha_1 (x_1+beta1)^2 <= auxvar^2 */
2596  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2597  lhsvars[0], lhsvars[1], auxvar1,
2598  lhscoefs[0], lhscoefs[1], 1.0,
2599  lhsoffsets[0], lhsoffsets[1], 0.0,
2600  soc3_nr_auxvars, glineur, name, naddconss) );
2601 
2602  (void) SCIPsnprintf(name, 255, "%s_soc3", basename);
2603  if( nlhsvars == 3 )
2604  { /* create new constraint alpha_2 (x_2+beta2)^2 + auxvar^2 <= (rhscoeff * (rhsvar+rhsoffset))^2 */
2605  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2606  lhsvars[2], auxvar1, rhsvar,
2607  lhscoefs[2], 1.0, rhscoeff,
2608  lhsoffsets[2], 0.0, rhsoffset,
2609  soc3_nr_auxvars, glineur, name, naddconss) );
2610  }
2611  else
2612  { /* create new constraint auxvar^2 + sqrt(constant)^2 <= (rhscoeff * (rhsvar+rhsoffset))^2 */
2613  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2614  auxvar1, NULL, rhsvar,
2615  1.0, 1.0, rhscoeff,
2616  0.0, sqrt(constant), rhsoffset,
2617  soc3_nr_auxvars, glineur, name, naddconss) );
2618  }
2619 
2620  SCIP_CALL( SCIPreleaseVar(scip, &auxvar1) );
2621 
2622  return SCIP_OKAY;
2623  }
2624 
2625  /* nlhsvars >= 4 */
2626 
2627  (void) SCIPsnprintf(name, 255, "%s#z1", basename);
2628  SCIP_CALL( SCIPcreateVar(scip, &auxvar1, name, 0.0, SCIPinfinity(scip), 0.0,
2630  SCIP_CALL( SCIPaddVar(scip, auxvar1) );
2631 
2632  /* approx for left half of lhs */
2634  nlhsvars/2, lhsvars, lhscoefs, lhsoffsets,
2635  auxvar1, 1.0, 0.0,
2636  constant, name, origcons, soc3_nr_auxvars, glineur, naddconss) );
2637 
2638  (void) SCIPsnprintf(name, 255, "%s#z2", basename);
2639  SCIP_CALL( SCIPcreateVar(scip, &auxvar2, name, 0., SCIPinfinity(scip), 0.0,
2641  SCIP_CALL( SCIPaddVar(scip, auxvar2) );
2642 
2643  /* approx for right half of lhs */
2645  nlhsvars-nlhsvars/2, &lhsvars[nlhsvars/2], &lhscoefs[nlhsvars/2], &lhsoffsets[nlhsvars/2],
2646  auxvar2, 1.0, 0.0,
2647  0.0, name, origcons, soc3_nr_auxvars, glineur, naddconss) );
2648 
2649  /* SOC constraint binding both auxvar's */
2650  (void)SCIPsnprintf(name, 255, "%s_soc3", basename);
2651  SCIP_CALL( presolveCreateOuterApproxDim3(scip, origcons,
2652  auxvar1, auxvar2, rhsvar,
2653  1.0, 1.0, rhscoeff,
2654  0.0, 0.0, rhsoffset,
2655  soc3_nr_auxvars, glineur, name, naddconss) );
2656 
2657  SCIP_CALL( SCIPreleaseVar(scip, &auxvar1) );
2658  SCIP_CALL( SCIPreleaseVar(scip, &auxvar2) );
2659 
2660  return SCIP_OKAY;
2661 }
2662 
2663 /** propagates variable bounds */
2664 static
2666  SCIP* scip, /**< SCIP data structure */
2667  SCIP_CONS* cons, /**< constraint */
2668  SCIP_RESULT* result, /**< buffer to store result of propagation */
2669  int* nchgbds /**< buffer where to add number of tightened bounds */
2670  )
2671 {
2672  SCIP_CONSDATA* consdata;
2673  SCIP_INTERVAL lhsrange;
2674  SCIP_INTERVAL* lhsranges;
2675  SCIP_INTERVAL rhsrange;
2676  SCIP_INTERVAL a, b, c;
2677  SCIP_ROUNDMODE roundmode;
2678  SCIP_Bool infeas, tightened;
2679  int i;
2680  SCIP_Real lb, ub;
2681 
2682  assert(scip != NULL);
2683  assert(cons != NULL);
2684  assert(result != NULL);
2685 
2686  consdata = SCIPconsGetData(cons);
2687  assert(consdata != NULL);
2688 
2689  if( consdata->ispropagated )
2690  {
2691  SCIPdebugMessage("skip propagation for constraint %s\n", SCIPconsGetName(cons));
2692  *result = SCIP_DIDNOTRUN;
2693  return SCIP_OKAY;
2694  }
2695  else
2696  {
2697  SCIPdebugMessage("try propagation for constraint %s\n", SCIPconsGetName(cons));
2698  }
2699 
2700  *result = SCIP_DIDNOTFIND;
2701  consdata->ispropagated = TRUE;
2702 
2703  /* @todo do something clever to decide whether propagation should be tried */
2704 
2705  SCIPintervalSetBounds(&lhsrange, consdata->constant - SCIPepsilon(scip), consdata->constant + SCIPepsilon(scip));
2706 
2707  SCIP_CALL( SCIPallocBufferArray(scip, &lhsranges, consdata->nvars) );
2708  for( i = 0; i < consdata->nvars; ++i )
2709  {
2710  lb = SCIPcomputeVarLbLocal(scip, consdata->vars[i]) - SCIPepsilon(scip);
2711  ub = SCIPcomputeVarUbLocal(scip, consdata->vars[i]) + SCIPepsilon(scip);
2712  SCIPintervalSetBounds(&lhsranges[i], MIN(lb, ub), MAX(lb, ub));
2713  if( consdata->offsets[i] != 0.0 )
2714  SCIPintervalAddScalar(SCIPinfinity(scip), &lhsranges[i], lhsranges[i], consdata->offsets[i]);
2715  if( consdata->coefs[i] != 1.0 )
2716  SCIPintervalMulScalar(SCIPinfinity(scip), &lhsranges[i], lhsranges[i], consdata->coefs[i]);
2717  SCIPintervalSquare(SCIPinfinity(scip), &lhsranges[i], lhsranges[i]);
2718 
2719  SCIPintervalAdd(SCIPinfinity(scip), &lhsrange, lhsrange, lhsranges[i]);
2720  }
2721 
2722  if( SCIPvarGetStatus(consdata->rhsvar) != SCIP_VARSTATUS_MULTAGGR )
2723  {
2724  SCIPintervalSquareRoot(SCIPinfinity(scip), &a, lhsrange);
2725  if( consdata->rhscoeff != 1.0 )
2726  SCIPintervalDivScalar(SCIPinfinity(scip), &a, a, consdata->rhscoeff);
2727  if( consdata->rhsoffset != 0.0 )
2728  SCIPintervalSubScalar(SCIPinfinity(scip), &a, a, consdata->rhsoffset);
2729  SCIP_CALL( SCIPtightenVarLb(scip, consdata->rhsvar, SCIPintervalGetInf(a), FALSE, &infeas, &tightened) );
2730  if( infeas )
2731  {
2732  SCIPdebugMessage("propagation found constraint <%s> infeasible\n", SCIPconsGetName(cons));
2733  *result = SCIP_CUTOFF;
2734  }
2735  else if( tightened )
2736  {
2737  SCIPdebugMessage("propagation tightened bounds of rhs variable <%s> in constraint <%s>\n", SCIPvarGetName(consdata->rhsvar), SCIPconsGetName(cons));
2738  *result = SCIP_REDUCEDDOM;
2739  ++*nchgbds;
2740  }
2741  }
2742 
2743  if( *result != SCIP_CUTOFF )
2744  {
2745  lb = SCIPcomputeVarLbLocal(scip, consdata->rhsvar) - SCIPepsilon(scip);
2746  ub = SCIPcomputeVarUbLocal(scip, consdata->rhsvar) + SCIPepsilon(scip);
2747  SCIPintervalSetBounds(&rhsrange, MIN(lb, ub), MAX(lb, ub));
2748  if( consdata->rhsoffset != 0.0 )
2749  SCIPintervalAddScalar(SCIPinfinity(scip), &rhsrange, rhsrange, consdata->rhsoffset);
2750  if( consdata->rhscoeff != 1.0 )
2751  SCIPintervalMulScalar(SCIPinfinity(scip), &rhsrange, rhsrange, consdata->rhscoeff);
2752  SCIPintervalSquare(SCIPinfinity(scip), &rhsrange, rhsrange);
2753  /* rhsrange = sqr(rhscoeff * (rhsvar + rhsoffset) ) */
2754 
2755  if( lhsrange.inf > rhsrange.sup )
2756  {
2757  SCIPdebugMessage("propagation found constraint <%s> infeasible: lhs = [%.15g,%.15g] > rhs = [%.15g,%.15g]\n",
2758  SCIPconsGetName(cons), lhsrange.inf, lhsrange.sup, rhsrange.inf, rhsrange.sup);
2759  *result = SCIP_CUTOFF;
2760  }
2761  }
2762 
2763  if( *result != SCIP_CUTOFF )
2764  {
2765  SCIPintervalSub(SCIPinfinity(scip), &b, rhsrange, lhsrange); /*lint !e644 */
2766  for( i = 0; i < consdata->nvars; ++i )
2767  {
2768  if( SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_MULTAGGR )
2769  continue;
2770 
2771  roundmode = SCIPintervalGetRoundingMode();
2772  if( !SCIPisInfinity(scip, b.sup) )
2773  {
2775  a.sup = b.sup + lhsranges[i].inf;
2776  }
2777  else
2778  {
2779  a.sup = SCIPinfinity(scip);
2780  }
2781  if( !SCIPisInfinity(scip, -b.inf) )
2782  {
2784  a.inf = b.inf + lhsranges[i].sup;
2785  }
2786  else
2787  {
2788  a.inf = -SCIPinfinity(scip);
2789  }
2790  SCIPintervalSetRoundingMode(roundmode);
2791  SCIPintervalSquareRoot(SCIPinfinity(scip), &a, a);
2792 
2793  assert(consdata->coefs[i] >= 0.0); /* should be ensured in create and presolveRemoveFixed */
2794 
2795  c = a;
2796  if( consdata->coefs[i] != 1.0 )
2797  SCIPintervalDivScalar(SCIPinfinity(scip), &c, c, consdata->coefs[i]);
2798  if( consdata->offsets[i] != 0.0 )
2799  SCIPintervalSubScalar(SCIPinfinity(scip), &c, c, consdata->offsets[i]);
2800 
2801  SCIP_CALL( SCIPtightenVarUb(scip, consdata->vars[i], SCIPintervalGetSup(c), FALSE, &infeas, &tightened) );
2802  if( infeas )
2803  {
2804  SCIPdebugMessage("propagation found constraint <%s> infeasible\n", SCIPconsGetName(cons));
2805  *result = SCIP_CUTOFF;
2806  break;
2807  }
2808  else if( tightened )
2809  {
2810  SCIPdebugMessage("propagation tightened bounds of lhs variable <%s> in constraint <%s>\n", SCIPvarGetName(consdata->vars[i]), SCIPconsGetName(cons));
2811  *result = SCIP_REDUCEDDOM;
2812  ++*nchgbds;
2813  }
2814 
2815  c = a;
2816  SCIPintervalDivScalar(SCIPinfinity(scip), &c, c, -consdata->coefs[i]);
2817  if( consdata->offsets[i] != 0.0 )
2818  SCIPintervalSubScalar(SCIPinfinity(scip), &c, c, consdata->offsets[i]);
2819 
2820  SCIP_CALL( SCIPtightenVarLb(scip, consdata->vars[i], SCIPintervalGetInf(c), FALSE, &infeas, &tightened) );
2821  if( infeas )
2822  {
2823  SCIPdebugMessage("propagation found constraint <%s> infeasible\n", SCIPconsGetName(cons));
2824  *result = SCIP_CUTOFF;
2825  break;
2826  }
2827  else if( tightened )
2828  {
2829  SCIPdebugMessage("propagation tightened bounds of lhs variable <%s> in constraint <%s>\n", SCIPvarGetName(consdata->vars[i]), SCIPconsGetName(cons));
2830  *result = SCIP_REDUCEDDOM;
2831  ++*nchgbds;
2832  }
2833  }
2834  }
2835 
2836  SCIPfreeBufferArray(scip, &lhsranges);
2837 
2838  if( *result != SCIP_DIDNOTFIND )
2839  {
2840  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2841  }
2842 
2843  return SCIP_OKAY;
2844 }
2845 
2846 /** tries to adjust a solution such that it satisfies a given constraint by increasing the value for the constraints right hand side variable */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  SCIP_CONS* cons, /**< constraint */
2851  SCIP_SOL* sol, /**< solution to polish */
2852  SCIP_Bool* success /**< buffer to store whether polishing was successful */
2853  )
2854 {
2855  SCIP_CONSDATA* consdata;
2856  SCIP_Real rhsval;
2857 
2858  assert(scip != NULL);
2859  assert(cons != NULL);
2860  assert(sol != NULL);
2861  assert(success != NULL);
2862 
2863  consdata = SCIPconsGetData(cons);
2864  assert(consdata != NULL);
2865  assert(!SCIPisZero(scip, consdata->rhscoeff));
2866 
2867  /* compute minimal rhs variable value so that constraint is satisfied */
2868  if( !SCIPisInfinity(scip, consdata->lhsval) )
2869  rhsval = consdata->lhsval / consdata->rhscoeff - consdata->rhsoffset;
2870  else
2871  rhsval = consdata->rhscoeff > 0.0 ? SCIPinfinity(scip) : -SCIPinfinity(scip);
2872 
2873  if( consdata->rhscoeff > 0.0 )
2874  {
2875  assert(SCIPvarMayRoundUp(consdata->rhsvar));
2876 
2877  /* round rhsval up, if variable is integral */
2878  if( SCIPvarIsIntegral(consdata->rhsvar) && !SCIPisInfinity(scip, rhsval) )
2879  rhsval = SCIPceil(scip, rhsval);
2880 
2881  /* if new value is above upper bound, we are lost */
2882  if( SCIPisGT(scip, rhsval, SCIPvarGetUbGlobal(consdata->rhsvar)) )
2883  {
2884  *success = FALSE;
2885  }
2886  else
2887  {
2888  /* if new value is larger then current one, increase to new value */
2889  if( rhsval > SCIPgetSolVal(scip, sol, consdata->rhsvar) )
2890  {
2891  SCIPdebugMessage("increase <%s> to %g\n", SCIPvarGetName(consdata->rhsvar), rhsval);
2892  SCIP_CALL( SCIPsetSolVal(scip, sol, consdata->rhsvar, rhsval) );
2893  }
2894 
2895  *success = TRUE;
2896  }
2897  }
2898  else
2899  {
2900  assert(SCIPvarMayRoundDown(consdata->rhsvar));
2901 
2902  /* round rhsval down, if variable is integral */
2903  if( SCIPvarIsIntegral(consdata->rhsvar) )
2904  rhsval = SCIPfloor(scip, rhsval);
2905 
2906  /* if new value is below lower bound, we are lost */
2907  if( SCIPisLT(scip, rhsval, SCIPvarGetLbGlobal(consdata->rhsvar)) )
2908  {
2909  *success = FALSE;
2910  }
2911  else
2912  {
2913  /* if new value is below current one, decrease to new value */
2914  if( rhsval < SCIPgetSolVal(scip, sol, consdata->rhsvar) )
2915  {
2916  SCIPdebugMessage("decrease <%s> to %g\n", SCIPvarGetName(consdata->rhsvar), rhsval);
2917  SCIP_CALL( SCIPsetSolVal(scip, sol, consdata->rhsvar, rhsval) );
2918  }
2919 
2920  *success = TRUE;
2921  }
2922  }
2923 
2924  SCIPdebugMessage("polishing solution for constraint <%s> was %ssuccessful\n", SCIPconsGetName(cons), *success ? "" : "not ");
2925 
2926  return SCIP_OKAY;
2927 }
2928 
2929 /*
2930  * Quadratic constraint upgrading
2931  */
2932 
2933 
2934 #ifdef QUADCONSUPGD_PRIORITY
2935 /** tries to upgrade a quadratic constraint to a SOC constraint
2936  * @todo more general quadratic constraints then sums of squares might allow an upgrade to a SOC
2937  */
2938 static
2939 SCIP_DECL_QUADCONSUPGD(upgradeConsQuadratic)
2940 {
2941  int nquadvars;
2942  SCIP_QUADVARTERM* term;
2943  SCIP_VAR** lhsvars;
2944  SCIP_Real* lhscoefs;
2945  SCIP_Real* lhsoffsets;
2946  SCIP_Real lhsconstant;
2947  int lhscount;
2948  SCIP_VAR* rhsvar;
2949  SCIP_Real rhscoef;
2950  SCIP_Real rhsoffset;
2951  int i;
2952 
2953  assert(scip != NULL);
2954  assert(cons != NULL);
2955  assert(nupgdconss != NULL);
2956  assert(upgdconss != NULL);
2957 
2958  *nupgdconss = 0;
2959 
2960  SCIPdebugMessage("upgradeConsQuadratic called for constraint <%s>\n", SCIPconsGetName(cons));
2961  SCIPdebugPrintCons(scip, cons, NULL);
2962 
2963  /* currently do not support linear parts in upgrading of SOC constraints */
2964  if( SCIPgetNLinearVarsQuadratic(scip, cons) )
2965  return SCIP_OKAY;
2966 
2967  /* currently do not support bilinear parts in upgrading of SOC constraints */
2968  if( SCIPgetNBilinTermsQuadratic(scip, cons) )
2969  return SCIP_OKAY;
2970 
2971  nquadvars = SCIPgetNQuadVarTermsQuadratic(scip, cons);
2972 
2973  /* currently, a proper SOC constraint needs at least 3 variables */
2974  if( nquadvars < 3 )
2975  return SCIP_OKAY;
2976 
2977  SCIP_CALL( SCIPallocBufferArray(scip, &lhsvars, nquadvars-1) );
2978  SCIP_CALL( SCIPallocBufferArray(scip, &lhscoefs, nquadvars-1) );
2979  SCIP_CALL( SCIPallocBufferArray(scip, &lhsoffsets, nquadvars-1) );
2980 
2981  lhsconstant = 0.0;
2982  lhscount = 0;
2983  rhsvar = NULL;
2984  rhscoef = 0.0;
2985  rhsoffset = 0.0;
2986 
2987  if( !SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) )
2988  { /* try whether constraint on right hand side is SOC */
2989  lhsconstant = -SCIPgetRhsQuadratic(scip, cons);
2990 
2991  for( i = 0; i < nquadvars; ++i )
2992  {
2993  term = &SCIPgetQuadVarTermsQuadratic(scip, cons)[i];
2994 
2995  /* if there is a linear variable that is still considered as quadratic (constraint probably not presolved yet), then give up */
2996  if( term->sqrcoef == 0.0 )
2997  goto cleanup;
2998 
2999  if( term->sqrcoef > 0.0 )
3000  {
3001  if( lhscount >= nquadvars - 1 )
3002  { /* too many variables on lhs, i.e., all variables seem to have positive coefficient */
3003  rhsvar = NULL;
3004  break;
3005  }
3006 
3007  lhsvars[lhscount] = term->var;
3008  lhscoefs[lhscount] = sqrt(term->sqrcoef);
3009 
3010  if( term->lincoef != 0.0 )
3011  {
3012  lhsoffsets[lhscount] = term->lincoef / (2 * term->sqrcoef);
3013  lhsconstant -= term->lincoef * term->lincoef / (4 * term->sqrcoef);
3014  }
3015  else
3016  {
3017  lhsoffsets[lhscount] = 0.0;
3018  }
3019 
3020  ++lhscount;
3021  }
3022  else if( rhsvar != NULL || SCIPisLT(scip, SCIPcomputeVarLbGlobal(scip, term->var), term->lincoef / (2*term->sqrcoef)) )
3023  { /* second variable with negative coefficient -> cannot be SOC */
3024  /* or lower bound of variable does not ensure positivity of right hand side */
3025  rhsvar = NULL;
3026  break;
3027  }
3028  else
3029  {
3030  rhsvar = term->var;
3031  rhscoef = sqrt(-term->sqrcoef);
3032  rhsoffset = term->lincoef / (2 * term->sqrcoef);
3033  lhsconstant -= term->lincoef * term->lincoef / (4 * term->sqrcoef);
3034  }
3035  }
3036  }
3037 
3038  if( rhsvar != NULL && lhscount >= 2 && !SCIPisNegative(scip, lhsconstant) )
3039  { /* found SOC constraint, so upgrade to SOC constraint(s) (below) and relax right hand side */
3040  SCIPdebugMessage("found right hand side of constraint <%s> to be SOC\n", SCIPconsGetName(cons));
3041 
3042  /* check if upgdconss is long enough to store upgrade constraints:
3043  * we need two if we will have a quadratic constraint for the left hand side left */
3044  *nupgdconss = SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) ? 1 : 2;
3045  if( *nupgdconss > upgdconsssize )
3046  {
3047  /* signal that we need more memory and return */
3048  *nupgdconss = -*nupgdconss;
3049  goto cleanup;
3050  }
3051 
3052  SCIP_CALL( SCIPcreateConsSOC(scip, &upgdconss[0], SCIPconsGetName(cons),
3053  lhscount, lhsvars, lhscoefs, lhsoffsets, MAX(lhsconstant, 0.0),
3054  rhsvar, rhscoef, rhsoffset,
3058  SCIPdebugPrintCons(scip, upgdconss[0], NULL);
3059 
3060  /* create constraint that is equal to cons except that rhs is now infinity */
3061  if( !SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) )
3062  {
3063  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &upgdconss[1], SCIPconsGetName(cons),
3067  SCIPgetLhsQuadratic(scip, cons), SCIPinfinity(scip),
3071  }
3072  }
3073  else if( !SCIPisInfinity(scip, - SCIPgetLhsQuadratic(scip, cons)) )
3074  { /* if the first failed, try if constraint on left hand side is SOC (using negated coefficients) */
3075  lhscount = 0;
3076  rhsvar = NULL;
3077 
3078  lhsconstant = SCIPgetLhsQuadratic(scip, cons);
3079 
3080  for( i = 0; i < nquadvars; ++i )
3081  {
3082  term = &SCIPgetQuadVarTermsQuadratic(scip, cons)[i];
3083 
3084  /* if there is a linear variable that is still considered as quadratic (constraint probably not presolved yet), then give up */
3085  if( term->sqrcoef == 0.0 )
3086  goto cleanup;
3087 
3088  if( term->sqrcoef < 0.0 )
3089  {
3090  if( lhscount >= nquadvars - 1 )
3091  { /* too many variables on lhs, i.e., all variables seem to have negative coefficient */
3092  rhsvar = NULL;
3093  break;
3094  }
3095 
3096  lhsvars[lhscount] = term->var;
3097  lhscoefs[lhscount] = sqrt(-term->sqrcoef);
3098 
3099  if( term->lincoef != 0.0 )
3100  {
3101  lhsoffsets[lhscount] = term->lincoef / (2 * term->sqrcoef);
3102  lhsconstant += term->lincoef * term->lincoef / (4 * term->sqrcoef);
3103  }
3104  else
3105  {
3106  lhsoffsets[lhscount] = 0.0;
3107  }
3108 
3109  ++lhscount;
3110  }
3111  else if( rhsvar || SCIPisLT(scip, SCIPcomputeVarLbGlobal(scip, term->var), -term->lincoef / (2*term->sqrcoef)) )
3112  { /* second variable with positive coefficient -> cannot be SOC */
3113  /* or lower bound of variable does not ensure positivity of right hand side */
3114  rhsvar = NULL;
3115  break;
3116  }
3117  else
3118  {
3119  rhsvar = term->var;
3120  rhscoef = sqrt(term->sqrcoef);
3121  rhsoffset = term->lincoef / (2 * term->sqrcoef);
3122  lhsconstant += term->lincoef * term->lincoef / (4 * term->sqrcoef);
3123  }
3124  }
3125 
3126  if( rhsvar && lhscount >= 2 && !SCIPisNegative(scip, lhsconstant) )
3127  { /* found SOC constraint, so upgrade to SOC constraint(s) (below) and relax left hand side */
3128  SCIPdebugMessage("found left hand side of constraint <%s> to be SOC\n", SCIPconsGetName(cons));
3129 
3130  /* check if upgdconss is long enough to store upgrade constraints:
3131  * we need two if we will have a quadratic constraint for the right hand side left */
3132  *nupgdconss = SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) ? 1 : 2;
3133  if( *nupgdconss > upgdconsssize )
3134  {
3135  /* signal that we need more memory and return */
3136  *nupgdconss = -*nupgdconss;
3137  goto cleanup;
3138  }
3139 
3140  SCIP_CALL( SCIPcreateConsSOC(scip, &upgdconss[0], SCIPconsGetName(cons),
3141  lhscount, lhsvars, lhscoefs, lhsoffsets, MAX(lhsconstant, 0.0),
3142  rhsvar, rhscoef, rhsoffset,
3146  SCIPdebugPrintCons(scip, upgdconss[0], NULL);
3147 
3148  /* create constraint that is equal to cons except that lhs is now -infinity */
3149  if( !SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) )
3150  {
3151  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &upgdconss[1], SCIPconsGetName(cons),
3155  -SCIPinfinity(scip), SCIPgetRhsQuadratic(scip, cons),
3159  }
3160  }
3161  }
3162 
3163  cleanup:
3164  SCIPfreeBufferArray(scip, &lhsvars);
3165  SCIPfreeBufferArray(scip, &lhscoefs);
3166  SCIPfreeBufferArray(scip, &lhsoffsets);
3167 
3168  return SCIP_OKAY;
3169 } /*lint !e715*/
3170 #endif
3171 
3172 /*
3173  * Callback methods of constraint handler
3174  */
3175 
3176 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
3177 static
3178 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOC)
3179 { /*lint --e{715}*/
3180  assert(scip != NULL);
3181  assert(conshdlr != NULL);
3182  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3183 
3184  /* call inclusion method of constraint handler */
3186 
3187  *valid = TRUE;
3188 
3189  return SCIP_OKAY;
3190 }
3191 
3192 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
3193 static
3195 {
3196  SCIP_CONSHDLRDATA* conshdlrdata;
3197 
3198  assert( scip != NULL );
3199  assert( conshdlr != NULL );
3200  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3201 
3202  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3203  assert(conshdlrdata != NULL);
3204 
3205  SCIPfreeBlockMemory(scip, &conshdlrdata);
3206 
3207  return SCIP_OKAY;
3208 }
3209 
3210 
3211 /** initialization method of constraint handler (called after problem was transformed) */
3212 static
3214 { /*lint --e{715}*/
3215  SCIP_CONSHDLRDATA* conshdlrdata;
3216 
3217  assert(scip != NULL);
3218  assert(conshdlr != NULL);
3219 
3220  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3221  assert(conshdlrdata != NULL);
3222 
3223  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
3224  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
3225  conshdlrdata->haveexprint = (strcmp(SCIPexprintGetName(), "NONE") != 0);
3226 
3227  return SCIP_OKAY;
3228 }
3229 
3230 
3231 /** deinitialization method of constraint handler (called before transformed problem is freed) */
3232 static
3234 { /*lint --e{715}*/
3235  SCIP_CONSHDLRDATA* conshdlrdata;
3236 
3237  assert(scip != NULL);
3238  assert(conshdlr != NULL);
3239 
3240  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3241  assert(conshdlrdata != NULL);
3242 
3243  conshdlrdata->subnlpheur = NULL;
3244  conshdlrdata->trysolheur = NULL;
3245  conshdlrdata->haveexprint = FALSE;
3246 
3247  return SCIP_OKAY;
3248 }
3249 
3250 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
3251 static
3252 SCIP_DECL_CONSEXITPRE(consExitpreSOC)
3253 { /*lint --e{715}*/
3254  int c;
3255 
3256  assert(scip != NULL);
3257  assert(conshdlr != NULL);
3258  assert(conss != NULL || nconss == 0);
3259 
3260  /* tell SCIP that we have something nonlinear */
3261  for( c = 0; c < nconss; ++c )
3262  {
3263  if( SCIPconsIsAdded(conss[c]) ) /*lint !e613*/
3264  {
3265  SCIPenableNLP(scip);
3266  break;
3267  }
3268  }
3269 
3270  return SCIP_OKAY;
3271 }
3272 
3273 
3274 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
3275 static
3276 SCIP_DECL_CONSINITSOL(consInitsolSOC)
3277 {
3278  SCIP_CONSHDLRDATA* conshdlrdata;
3279  SCIP_CONSDATA* consdata;
3280  int c;
3281 
3282  assert(scip != NULL);
3283  assert(conshdlr != NULL);
3284 
3285  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3286  assert(conshdlrdata != NULL);
3287  assert(conshdlrdata->eventhdlr != NULL);
3288 
3289  /* add nlrow representation to NLP, if NLP has been enabled */
3290  if( SCIPisNLPConstructed(scip) )
3291  {
3292  for( c = 0; c < nconss; ++c )
3293  {
3294  if( SCIPconsIsEnabled(conss[c]) )
3295  {
3296  consdata = SCIPconsGetData(conss[c]);
3297  assert(consdata != NULL);
3298 
3299  if( consdata->nlrow == NULL )
3300  {
3301  SCIP_CALL( createNlRow(scip, conshdlr, conss[c]) );
3302  assert(consdata->nlrow != NULL);
3303  }
3304  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3305  }
3306  }
3307  }
3308 
3309  conshdlrdata->newsoleventfilterpos = -1;
3310  if( nconss != 0 )
3311  {
3312  SCIP_EVENTHDLR* eventhdlr;
3313 
3314  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
3315  assert(eventhdlr != NULL);
3316 
3317  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
3318  }
3319 
3320  /* reset flags and counters */
3321  conshdlrdata->sepanlp = FALSE;
3322  conshdlrdata->lastenfolpnode = NULL;
3323  conshdlrdata->nenfolprounds = 0;
3324 
3325  return SCIP_OKAY;
3326 }
3327 
3328 
3329 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
3330 static
3331 SCIP_DECL_CONSEXITSOL(consExitsolSOC)
3332 {
3333  SCIP_CONSHDLRDATA* conshdlrdata;
3334  SCIP_CONSDATA* consdata;
3335  int c;
3336 
3337  assert(scip != NULL);
3338  assert(conshdlr != NULL);
3339 
3340  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3341  assert(conshdlrdata != NULL);
3342  assert(conshdlrdata->eventhdlr != NULL);
3343 
3344  if( conshdlrdata->newsoleventfilterpos >= 0 )
3345  {
3346  SCIP_EVENTHDLR* eventhdlr;
3347 
3348  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
3349  assert(eventhdlr != NULL);
3350 
3351  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
3352  conshdlrdata->newsoleventfilterpos = -1;
3353  }
3354 
3355  for( c = 0; c < nconss; ++c )
3356  {
3357  consdata = SCIPconsGetData(conss[c]);
3358  assert(consdata != NULL);
3359 
3360  /* free nonlinear row representation */
3361  if( consdata->nlrow != NULL )
3362  {
3363  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3364  }
3365  }
3366 
3367  return SCIP_OKAY;
3368 } /*lint !e715*/
3369 
3370 
3371 /** frees specific constraint data */
3372 static
3373 SCIP_DECL_CONSDELETE(consDeleteSOC)
3374 {
3375  int i;
3376 
3377  assert(scip != NULL);
3378  assert(conshdlr != NULL);
3379  assert(cons != NULL);
3380  assert(consdata != NULL);
3381  assert(*consdata != NULL);
3382  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3383  assert((*consdata)->nlrow == NULL); /* should have been freed in exitsol */
3384 
3385  SCIPdebugMessage("Deleting SOC constraint <%s>.\n", SCIPconsGetName(cons) );
3386 
3387  if( SCIPconsIsTransformed(cons) )
3388  {
3389  SCIP_CONSHDLRDATA* conshdlrdata;
3390 
3391  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3392  assert(conshdlrdata != NULL);
3393 
3394  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
3395  }
3396 
3397  for( i = 0; i < (*consdata)->nvars; ++i )
3398  {
3399  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->vars[i]) );
3400  }
3401 
3402  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->nvars);
3403  SCIPfreeBlockMemoryArray(scip, &(*consdata)->coefs, (*consdata)->nvars);
3404  SCIPfreeBlockMemoryArray(scip, &(*consdata)->offsets, (*consdata)->nvars);
3405  assert((*consdata)->lhsbndchgeventdatas == NULL);
3406 
3407  if( (*consdata)->rhsvar != NULL )
3408  {
3409  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->rhsvar) );
3410  }
3411 
3412  SCIPfreeBlockMemory(scip, consdata);
3413 
3414  return SCIP_OKAY;
3415 }
3416 
3417 
3418 /** transforms constraint data into data belonging to the transformed problem */
3419 static
3420 SCIP_DECL_CONSTRANS(consTransSOC)
3421 {
3422  SCIP_CONSDATA* consdata;
3423  SCIP_CONSHDLRDATA* conshdlrdata;
3424  SCIP_CONSDATA* sourcedata;
3425  char s[SCIP_MAXSTRLEN];
3426  int i;
3427 
3428  assert(scip != NULL);
3429  assert(conshdlr != NULL);
3430  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3431  assert(sourcecons != NULL);
3432  assert(targetcons != NULL);
3433 
3434  /* get constraint handler data */
3435  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3436  assert(conshdlrdata != NULL);
3437 
3438  SCIPdebugMessage("Transforming SOC constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
3439 
3440  /* get data of original constraint */
3441  sourcedata = SCIPconsGetData(sourcecons);
3442  assert(sourcedata != NULL);
3443  assert(sourcedata->vars != NULL);
3444  assert(sourcedata->coefs != NULL);
3445  assert(sourcedata->offsets != NULL);
3446 
3447  /* create constraint data */
3448  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
3449 
3450  consdata->nvars = sourcedata->nvars;
3451  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
3452  SCIP_CALL( SCIPgetTransformedVars(scip, consdata->nvars, sourcedata->vars, consdata->vars) );
3453  for( i = 0; i < consdata->nvars; ++i )
3454  {
3455  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
3456  }
3457 
3458  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->coefs, sourcedata->coefs, consdata->nvars) );
3459  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->offsets, sourcedata->offsets, consdata->nvars) );
3460  consdata->constant = sourcedata->constant;
3461 
3462  SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->rhsvar, &consdata->rhsvar) );
3463  consdata->rhsoffset = sourcedata->rhsoffset;
3464  consdata->rhscoeff = sourcedata->rhscoeff;
3465 
3466  SCIP_CALL( SCIPcaptureVar(scip, consdata->rhsvar) );
3467 
3468  consdata->nlrow = NULL;
3469  consdata->lhsbndchgeventdatas = NULL;
3470  consdata->ispropagated = FALSE;
3471  consdata->isapproxadded = FALSE;
3472 
3473  /* create transformed constraint with the same flags */
3474  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
3475  SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
3476  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
3477  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
3478  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
3479  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
3480  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
3481 
3482  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *targetcons) );
3483 
3484  return SCIP_OKAY;
3485 }
3486 
3487 /** separation method of constraint handler for LP solutions */
3488 static
3489 SCIP_DECL_CONSSEPALP(consSepalpSOC)
3490 {
3491  SCIP_CONSHDLRDATA* conshdlrdata;
3492  SCIP_CONS* maxviolcon;
3493  SCIP_Bool sepasuccess;
3494  SCIP_Bool cutoff;
3495 
3496  assert(scip != NULL);
3497  assert(conshdlr != NULL);
3498  assert(conss != NULL || nconss == 0);
3499  assert(result != NULL);
3500 
3501  *result = SCIP_DIDNOTFIND;
3502 
3503  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3504  assert(conshdlrdata != NULL);
3505 
3506  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
3507  if( maxviolcon == NULL )
3508  return SCIP_OKAY;
3509 
3510  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
3511  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
3512  */
3513  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
3514  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
3515  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
3516  {
3517  SCIP_NLPSOLSTAT solstat;
3518  SCIP_Bool solvednlp;
3519 
3520  solstat = SCIPgetNLPSolstat(scip);
3521  solvednlp = FALSE;
3522  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
3523  {
3524  /* NLP is not solved yet, so we do it now and update solstat */
3525 
3526  /* ensure linear conss are in NLP */
3527  if( conshdlrdata->subnlpheur != NULL )
3528  {
3529  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
3530  }
3531 
3532  /* set LP solution as starting values, if available */
3534  {
3536  }
3537 
3538  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
3539  SCIP_CALL( SCIPsolveNLP(scip) );
3540 
3541  solstat = SCIPgetNLPSolstat(scip);
3542  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
3543 
3544  solvednlp = TRUE;
3545  }
3546 
3547  conshdlrdata->sepanlp = TRUE;
3548 
3549  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
3550  {
3551  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
3552  *result = SCIP_CUTOFF;
3553  return SCIP_OKAY;
3554  }
3555 
3556  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
3557  {
3558  /* if we have feasible NLP solution, generate linearization cuts there */
3559  SCIP_Bool lpsolseparated;
3560  SCIP_SOL* nlpsol;
3561 
3562  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
3563  assert(nlpsol != NULL);
3564 
3565  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
3566  if( solvednlp && conshdlrdata->trysolheur != NULL )
3567  {
3568  int nfracvars;
3569 
3570  nfracvars = 0;
3571  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
3572  {
3573  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
3574  }
3575 
3576  if( nfracvars == 0 )
3577  {
3578  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
3579  }
3580  }
3581 
3582  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->minefficacy, &cutoff) );
3583 
3584  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
3585 
3586  if( cutoff )
3587  {
3588  *result = SCIP_CUTOFF;
3589  return SCIP_OKAY;
3590  }
3591 
3592  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
3593  if( lpsolseparated )
3594  {
3595  SCIPdebugMessage("linearization cuts separate LP solution\n");
3596 
3597  *result = SCIP_SEPARATED;
3598 
3599  return SCIP_OKAY;
3600  }
3601  }
3602  }
3603  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
3604  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
3605  */
3606 
3607  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, FALSE, &cutoff, &sepasuccess) );
3608  if( cutoff )
3609  *result = SCIP_CUTOFF;
3610  else if ( sepasuccess )
3611  *result = SCIP_SEPARATED;
3612 
3613  return SCIP_OKAY;
3614 }
3615 
3616 
3617 /** separation method of constraint handler for arbitrary primal solutions */
3618 static
3619 SCIP_DECL_CONSSEPASOL(consSepasolSOC)
3620 {
3621  SCIP_CONS* maxviolcon;
3622  SCIP_Bool sepasuccess;
3623  SCIP_Bool cutoff;
3624 
3625  assert(scip != NULL);
3626  assert(conss != NULL || nconss == 0);
3627  assert(result != NULL);
3628  assert(sol != NULL);
3629 
3630  *result = SCIP_DIDNOTFIND;
3631 
3632  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
3633  if( maxviolcon == NULL )
3634  return SCIP_OKAY;
3635 
3636  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, &cutoff, &sepasuccess) );
3637  if( cutoff )
3638  *result = SCIP_CUTOFF;
3639  else if ( sepasuccess )
3640  *result = SCIP_SEPARATED;
3641 
3642  return SCIP_OKAY;
3643 }
3644 
3645 
3646 /** constraint enforcing method of constraint handler for LP solutions */
3647 static
3648 SCIP_DECL_CONSENFOLP(consEnfolpSOC)
3649 {
3650  SCIP_CONSHDLRDATA* conshdlrdata;
3651  SCIP_CONSDATA* consdata;
3652  SCIP_CONS* maxviolcons;
3653  SCIP_Bool success;
3654  SCIP_Bool cutoff;
3655  int nbndchg;
3656  int c;
3657 
3658  assert(scip != NULL);
3659  assert(conshdlr != NULL);
3660  assert(conss != NULL || nconss == 0);
3661  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3662  assert(result != NULL);
3663 
3664  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3665  assert(conshdlrdata != NULL);
3666 
3667  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
3668 
3669  if( maxviolcons == NULL )
3670  {
3671  *result = SCIP_FEASIBLE;
3672  return SCIP_OKAY;
3673  }
3674 
3675  /* if we are above the 100'th enforcement round for this node, something is strange
3676  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
3677  * 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
3678  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
3679  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
3680  * we only increment nenfolprounds until 101 to avoid an overflow
3681  */
3682  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
3683  {
3684  if( conshdlrdata->nenfolprounds > 100 )
3685  {
3686  if( SCIPisStopped(scip) )
3687  {
3688  SCIP_NODE* child;
3689 
3690  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
3691  *result = SCIP_BRANCHED;
3692 
3693  return SCIP_OKAY;
3694  }
3695  }
3696  else
3697  ++conshdlrdata->nenfolprounds;
3698  }
3699  else
3700  {
3701  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
3702  conshdlrdata->nenfolprounds = 0;
3703  }
3704 
3705  /* try separation, this should usually work */
3706  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, &cutoff, &success) );
3707  if( cutoff )
3708  {
3709  *result = SCIP_CUTOFF;
3710  return SCIP_OKAY;
3711  }
3712  if( success )
3713  {
3714  SCIPdebugMessage("enforced by separation\n");
3715  *result = SCIP_SEPARATED;
3716  return SCIP_OKAY;
3717  }
3718 
3719  /* try propagation */
3720  for( c = 0; c < nconss; ++c )
3721  {
3722  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3723  if( !SCIPisGT(scip, consdata->violation, SCIPfeastol(scip)) )
3724  continue;
3725 
3726  nbndchg = 0;
3727  SCIP_CALL( propagateBounds(scip, conss[c], result, &nbndchg) ); /*lint !e613*/
3728  if( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
3729  {
3730  SCIPdebugMessage("enforced by %s\n", *result == SCIP_CUTOFF ? "cutting off node" : "reducing domain");
3731  return SCIP_OKAY;
3732  }
3733  }
3734 
3735  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g feasible\n", SCIPconsGetData(maxviolcons)->violation);
3736  *result = SCIP_FEASIBLE;
3737 
3738  return SCIP_OKAY;
3739 } /*lint !e715*/
3740 
3741 
3742 /** constraint enforcing method of constraint handler for pseudo solutions */
3743 static
3744 SCIP_DECL_CONSENFOPS(consEnfopsSOC)
3745 {
3746  SCIP_CONS* maxviolcons;
3747 
3748  assert(scip != NULL);
3749  assert(conss != NULL || nconss == 0);
3750  assert(result != NULL);
3751 
3752  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
3753 
3754  if( maxviolcons == NULL )
3755  *result = SCIP_FEASIBLE;
3756 
3757  *result = SCIP_INFEASIBLE;
3758 
3759  return SCIP_OKAY;
3760 } /*lint !e715*/
3761 
3762 
3763 /** feasibility check method of constraint handler for integral solutions */
3764 static
3765 SCIP_DECL_CONSCHECK(consCheckSOC)
3766 {
3767  SCIP_CONSHDLRDATA* conshdlrdata;
3768  SCIP_CONSDATA* consdata;
3769  SCIP_Real maxviol;
3770  SCIP_Bool dolinfeasshift;
3771  SCIP_SOL* polishedsol;
3772  int c;
3773 
3774  assert(scip != NULL);
3775  assert(conshdlr != NULL);
3776  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3777  assert(conss != NULL || nconss == 0);
3778  assert(result != NULL );
3779 
3780  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3781  assert(conshdlrdata != NULL);
3782 
3783  *result = SCIP_FEASIBLE;
3784  maxviol = 0.0;
3785 
3786  dolinfeasshift = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL);
3787  polishedsol = NULL;
3788 
3789  for( c = 0; c < nconss; ++c )
3790  {
3791  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) ); /*lint !e613*/
3792 
3793  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3794  assert(consdata != NULL);
3795 
3796  /* if feasible, just continue */
3797  if( !SCIPisGT(scip, consdata->violation, SCIPfeastol(scip)) )
3798  continue;
3799 
3800  *result = SCIP_INFEASIBLE;
3801 
3802  if( consdata->violation > maxviol )
3803  maxviol = consdata->violation;
3804 
3805  if( printreason )
3806  {
3807  SCIP_Real unscaledviol;
3808 
3809  unscaledviol = consdata->lhsval;
3810  if( !SCIPisInfinity(scip, unscaledviol) )
3811  unscaledviol -= consdata->rhscoeff * (SCIPgetSolVal(scip, sol, consdata->rhsvar) + consdata->rhsoffset);
3812 
3813  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) ); /*lint !e613*/
3814  SCIPinfoMessage(scip, NULL, ";\n\tviolation: %g (scaled: %g)\n", unscaledviol, consdata->violation);
3815  }
3816 
3817  /* if we do linear feasibility shifting, then try to adjust solution */
3818  if( dolinfeasshift )
3819  {
3820  if( SCIPvarGetStatus(consdata->rhsvar) != SCIP_VARSTATUS_MULTAGGR &&
3821  !SCIPisInfinity(scip, REALABS(consdata->lhsval)) &&
3822  ( (consdata->rhscoeff > 0.0 && SCIPvarMayRoundUp (consdata->rhsvar)) ||
3823  (consdata->rhscoeff < 0.0 && SCIPvarMayRoundDown(consdata->rhsvar)) ) )
3824  {
3825  SCIP_Bool success;
3826 
3827  if( polishedsol == NULL )
3828  {
3829  if( sol != NULL )
3830  {
3831  SCIP_CALL( SCIPcreateSolCopy(scip, &polishedsol, sol) );
3832  }
3833  else
3834  {
3835  SCIP_CALL( SCIPcreateLPSol(scip, &polishedsol, NULL) );
3836  }
3837  SCIP_CALL( SCIPunlinkSol(scip, polishedsol) );
3838  }
3839  SCIP_CALL( polishSolution(scip, conss[c], polishedsol, &success) ); /*lint !e613*/
3840 
3841  /* disable solution polishing if we failed for this constraint */
3842  dolinfeasshift = success;
3843  }
3844  else /* if locks of the variable are bad or rhs is multi-aggregated, disable solution polishing */
3845  {
3846  dolinfeasshift = FALSE;
3847  }
3848  }
3849 
3850  /* if solution polishing is off and there is no NLP heuristic or we just check the LP solution,
3851  * then there is no need to check remaining constraints (NLP heuristic will pick up LP solution anyway) */
3852  if( !dolinfeasshift && (conshdlrdata->subnlpheur == NULL || sol == NULL))
3853  break;
3854  }
3855 
3856  /* if we failed to polish solution, clear the solution */
3857  if( !dolinfeasshift && polishedsol != NULL )
3858  {
3859  SCIP_CALL( SCIPfreeSol(scip, &polishedsol) );
3860  }
3861 
3862  if( polishedsol != NULL )
3863  {
3864  assert(*result == SCIP_INFEASIBLE);
3865  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, polishedsol) );
3866  SCIP_CALL( SCIPfreeSol(scip, &polishedsol) );
3867  }
3868  else if( conshdlrdata->subnlpheur != NULL && sol != NULL && *result == SCIP_INFEASIBLE )
3869  {
3870  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
3871  }
3872 
3873  return SCIP_OKAY;
3874 } /*lint !e715*/
3875 
3876 
3877 /** domain propagation method of constraint handler */
3878 static
3880 {
3881  SCIP_RESULT propresult;
3882  int c;
3883  int nchgbds;
3884 
3885  assert(scip != NULL);
3886  assert(conss != NULL || nconss == 0);
3887  assert(result != NULL);
3888 
3889  *result = SCIP_DIDNOTFIND;
3890  nchgbds = 0;
3891 
3892  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
3893  {
3894  SCIP_CALL( propagateBounds(scip, conss[c], &propresult, &nchgbds) ); /*lint !e613*/
3895  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
3896  *result = propresult;
3897  }
3898 
3899  return SCIP_OKAY;
3900 } /*lint !e715*/
3901 
3902 
3903 /** presolving method of constraint handler */
3904 static
3905 SCIP_DECL_CONSPRESOL(consPresolSOC)
3906 {
3907  SCIP_CONSHDLRDATA* conshdlrdata;
3908  SCIP_CONSDATA* consdata;
3909  int c;
3910  SCIP_RESULT propresult;
3911  SCIP_Bool iscutoff;
3912  SCIP_Bool isdeleted;
3913 
3914  assert(scip != NULL);
3915  assert(conss != NULL || nconss == 0);
3916  assert(conshdlr != NULL);
3917  assert(result != NULL);
3918 
3919  *result = SCIP_DIDNOTFIND;
3920 
3921  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3922  assert(conshdlrdata != NULL);
3923 
3924  for( c = 0; c < nconss; ++c )
3925  {
3926  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3927  assert(consdata != NULL);
3928 
3929  SCIP_CALL( presolveRemoveFixedVariables(scip, conshdlr, conss[c], ndelconss, nupgdconss, nchgbds, nfixedvars, &iscutoff, &isdeleted) ); /*lint !e613*/
3930  if( iscutoff )
3931  {
3932  *result = SCIP_CUTOFF;
3933  return SCIP_OKAY;
3934  }
3935  if( isdeleted )
3936  {
3937  /* conss[c] has been deleted */
3938  *result = SCIP_SUCCESS;
3939  continue;
3940  }
3941 
3942  if( conshdlrdata->nauxvars > 0 && !consdata->isapproxadded )
3943  {
3944  SCIP_CALL( presolveCreateOuterApprox(scip, consdata->nvars, consdata->vars, consdata->coefs, consdata->offsets, consdata->rhsvar, consdata->rhscoeff, consdata->rhscoeff, consdata->constant, SCIPconsGetName(conss[c]), conss[c], conshdlrdata->nauxvars, conshdlrdata->glineur, naddconss) ); /*lint !e613*/
3945  consdata->isapproxadded = TRUE;
3946  }
3947 
3948  SCIP_CALL( propagateBounds(scip, conss[c], &propresult, nchgbds) ); /*lint !e613*/
3949  switch( propresult )
3950  {
3951  case SCIP_DIDNOTRUN:
3952  case SCIP_DIDNOTFIND:
3953  break;
3954  case SCIP_REDUCEDDOM:
3955  *result = SCIP_SUCCESS;
3956  break;
3957  case SCIP_CUTOFF:
3958  *result = SCIP_CUTOFF;
3959  SCIPdebugMessage("infeasible in presolve due to propagation for constraint %s\n", SCIPconsGetName(conss[c])); /*lint !e613*/
3960  return SCIP_OKAY;
3961  default:
3962  SCIPerrorMessage("unexpected result from propagation: %d\n", propresult);
3963  return SCIP_ERROR;
3964  } /*lint !e788*/
3965  }
3966 
3967  /* ensure we are called again if we are about to finish, since another presolver may still fix some variable and we cannot remove these fixations in exitpre anymore */
3969  *result = SCIP_DELAYED;
3970 
3971  return SCIP_OKAY;
3972 } /*lint !e715*/
3973 
3974 
3975 /** variable rounding lock method of constraint handler */
3976 static
3978 {
3979  SCIP_CONSDATA* consdata;
3980  int i;
3981 
3982  assert(scip != NULL);
3983  assert(conshdlr != NULL);
3984  assert(cons != NULL);
3985  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3986  consdata = SCIPconsGetData(cons);
3987  assert(consdata != NULL);
3988 
3989  SCIPdebugMessage("Locking constraint <%s>.\n", SCIPconsGetName(cons));
3990 
3991  /* Changing variables x_i, i <= n, in both directions can lead to an infeasible solution. */
3992  for( i = 0; i < consdata->nvars; ++i )
3993  {
3994  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[i], nlockspos + nlocksneg, nlockspos + nlocksneg) );
3995  }
3996 
3997  /* Rounding x_{n+1} up will not violate a solution. */
3998  if( consdata->rhsvar != NULL )
3999  {
4000  SCIP_CALL( SCIPaddVarLocks(scip, consdata->rhsvar, consdata->rhscoeff > 0.0 ? nlockspos : nlocksneg, consdata->rhscoeff > 0.0 ? nlocksneg : nlockspos) );
4001  }
4002 
4003  return SCIP_OKAY;
4004 }
4005 
4006 /** constraint display method of constraint handler */
4007 static
4008 SCIP_DECL_CONSPRINT(consPrintSOC)
4009 {
4010  SCIP_CONSDATA* consdata;
4011  int i;
4012 
4013  assert(scip != NULL);
4014  assert(conshdlr != NULL);
4015  assert(cons != NULL);
4016  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4017 
4018  consdata = SCIPconsGetData(cons);
4019  assert(consdata != NULL);
4020 
4021  SCIPinfoMessage(scip, file, "sqrt( ");
4022  if( consdata->constant != 0.0 )
4023  {
4024  SCIPinfoMessage(scip, file, "%.15g", consdata->constant);
4025  }
4026 
4027  for( i = 0; i < consdata->nvars; ++i )
4028  {
4029  SCIPinfoMessage(scip, file, "+ (%.15g*(", consdata->coefs[i]);
4030  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
4031  SCIPinfoMessage(scip, file, "%+.15g))^2 ", consdata->offsets[i]);
4032  }
4033 
4034  SCIPinfoMessage(scip, file, ") <= ");
4035  if( consdata->rhsvar != NULL )
4036  {
4037  SCIPinfoMessage(scip, file, "%.15g*(", consdata->rhscoeff);
4038  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->rhsvar, TRUE) );
4039  SCIPinfoMessage(scip, file, "%+.15g)", consdata->rhsoffset);
4040  }
4041  else
4042  {
4043  SCIPinfoMessage(scip, file, "%.15g", consdata->rhscoeff*consdata->rhsoffset);
4044  }
4045 
4046  return SCIP_OKAY;
4047 }
4048 
4049 /** constraint copying method of constraint handler */
4050 static
4052 {
4053  SCIP_CONSDATA* consdata;
4054  SCIP_VAR** vars;
4055  SCIP_VAR* rhsvar;
4056  int i;
4057 
4058  assert(scip != NULL);
4059  assert(cons != NULL);
4060  assert(sourcescip != NULL);
4061  assert(sourceconshdlr != NULL);
4062  assert(sourcecons != NULL);
4063  assert(varmap != NULL);
4064  assert(valid != NULL);
4065  assert(stickingatnode == FALSE);
4066 
4067  consdata = SCIPconsGetData(sourcecons);
4068  assert(consdata != NULL);
4069 
4070  *valid = TRUE;
4071 
4072  SCIP_CALL( SCIPallocBufferArray(sourcescip, &vars, consdata->nvars) );
4073 
4074  /* map variables to active variables of the target SCIP */
4075  for( i = 0; i < consdata->nvars && *valid; ++i )
4076  {
4077  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->vars[i], &vars[i], varmap, consmap, global, valid) );
4078  assert(!(*valid) || vars[i] != NULL);
4079  }
4080 
4081  /* map rhs variable to active variable of the target SCIP */
4082  if( *valid )
4083  {
4084  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->rhsvar, &rhsvar, varmap, consmap, global, valid) );
4085  assert(!(*valid) || rhsvar != NULL);
4086  }
4087 
4088  /* only create the target constraint, if all variables could be copied */
4089  if( *valid )
4090  {
4091  SCIP_CALL( SCIPcreateConsSOC(scip, cons, name ? name : SCIPconsGetName(sourcecons),
4092  consdata->nvars, vars, consdata->coefs, consdata->offsets, consdata->constant,
4093  rhsvar, consdata->rhscoeff, consdata->rhsoffset,
4094  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) ); /*lint !e644 */
4095  }
4096 
4097  SCIPfreeBufferArray(sourcescip, &vars);
4098 
4099  return SCIP_OKAY;
4100 }
4101 
4102 
4103 /** constraint parsing method of constraint handler */
4104 static
4105 SCIP_DECL_CONSPARSE(consParseSOC)
4106 { /*lint --e{715}*/
4107  SCIP_VAR* var;
4108  SCIP_VAR** vars;
4109  SCIP_Real* coefs;
4110  SCIP_Real* offsets;
4111  int nvars;
4112  int varssize;
4113  SCIP_VAR* rhsvar;
4114  SCIP_Real rhscoef;
4115  SCIP_Real rhsoffset;
4116  SCIP_Real constant;
4117  SCIP_Real coef;
4118  SCIP_Real offset;
4119  char* endptr;
4120 
4121  assert(scip != NULL);
4122  assert(success != NULL);
4123  assert(str != NULL);
4124  assert(name != NULL);
4125  assert(cons != NULL);
4126 
4127  /* check that string starts with "sqrt( " */
4128  if( strncmp(str, "sqrt( ", 6) != 0 )
4129  {
4130  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected 'sqrt( ' at begin of soc constraint string '%s'\n", str);
4131  *success = FALSE;
4132  return SCIP_OKAY;
4133  }
4134  str += 6;
4135 
4136  *success = TRUE;
4137 
4138  /* check if we have a constant in the beginning */
4139  if( SCIPstrToRealValue(str, &constant, &endptr) )
4140  str = endptr;
4141  else
4142  constant = 0.0;
4143 
4144  nvars = 0;
4145  varssize = 5;
4146  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
4147  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, varssize) );
4148  SCIP_CALL( SCIPallocBufferArray(scip, &offsets, varssize) );
4149 
4150  /* read '+ (coef*(var+offset))^2' on lhs, as long as possible */
4151  while( *str != '\0' )
4152  {
4153  /* skip whitespace */
4154  while( isspace((int)*str) )
4155  ++str;
4156 
4157  /* stop if no more coefficients */
4158  if( strncmp(str, "+ (", 3) != 0 )
4159  break;
4160 
4161  str += 3;
4162 
4163  /* parse coef */
4164  if( !SCIPstrToRealValue(str, &coef, &endptr) )
4165  {
4166  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected coefficient at begin of '%s'\n", str);
4167  *success = FALSE;
4168  break;
4169  }
4170  str = endptr;
4171 
4172  if( strncmp(str, "*(", 2) != 0 )
4173  {
4174  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '*(' at begin of '%s'\n", str);
4175  *success = FALSE;
4176  break;
4177  }
4178  str += 2;
4179 
4180  /* parse variable name */
4181  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
4182  if( var == NULL )
4183  {
4184  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
4185  *success = FALSE;
4186  break;
4187  }
4188  str = endptr;
4189 
4190  /* parse offset */
4191  if( !SCIPstrToRealValue(str, &offset, &endptr) )
4192  {
4193  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected offset at begin of '%s'\n", str);
4194  *success = FALSE;
4195  break;
4196  }
4197  str = endptr;
4198 
4199  if( strncmp(str, "))^2", 4) != 0 )
4200  {
4201  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '))^2' at begin of '%s'\n", str);
4202  *success = FALSE;
4203  break;
4204  }
4205  str += 4;
4206 
4207  if( varssize <= nvars )
4208  {
4209  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
4210  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
4211  SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, varssize) );
4212  SCIP_CALL( SCIPreallocBufferArray(scip, &offsets, varssize) );
4213  }
4214  vars[nvars] = var;
4215  coefs[nvars] = coef;
4216  offsets[nvars] = offset;
4217  ++nvars;
4218  }
4219 
4220  if( strncmp(str, ") <=", 4) != 0 )
4221  {
4222  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected ') <=' at begin of '%s'\n", str);
4223  *success = FALSE;
4224  }
4225  str += 4;
4226 
4227  /* read rhs coef*(var+offset) or just a constant */
4228 
4229  /* parse coef */
4230  if( *success )
4231  {
4232  /* skip whitespace */
4233  while( isspace((int)*str) )
4234  ++str;
4235 
4236  if( !SCIPstrToRealValue(str, &rhscoef, &endptr) )
4237  {
4238  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected coefficient at begin of '%s'\n", str);
4239  *success = FALSE;
4240  }
4241  str = endptr;
4242 
4243  /* skip whitespace */
4244  while( isspace((int)*str) )
4245  ++str;
4246  }
4247 
4248  /* parse *(var+offset) */
4249  if( *str != '\0' )
4250  {
4251  if( *success )
4252  {
4253  if( strncmp(str, "*(", 2) != 0 )
4254  {
4255  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '*(' at begin of '%s'\n", str);
4256  *success = FALSE;
4257  }
4258  else
4259  {
4260  str += 2;
4261  }
4262  }
4263 
4264  /* parse variable name */
4265  if( *success )
4266  {
4267  SCIP_CALL( SCIPparseVarName(scip, str, &rhsvar, &endptr) );
4268  if( rhsvar == NULL )
4269  {
4270  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
4271  *success = FALSE;
4272  }
4273  else
4274  {
4275  str = endptr;
4276  }
4277  }
4278 
4279  /* parse offset */
4280  if( *success )
4281  {
4282  if( !SCIPstrToRealValue(str, &rhsoffset, &endptr) )
4283  {
4284  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected offset at begin of '%s'\n", str);
4285  *success = FALSE;
4286  }
4287  else
4288  {
4289  str = endptr;
4290  }
4291  }
4292 
4293  if( *success )
4294  {
4295  if( *str != ')' )
4296  {
4297  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected ')' at begin of '%s'\n", str);
4298  *success = FALSE;
4299  }
4300  }
4301  }
4302  else if( *success )
4303  {
4304  /* only a constant at right hand side */
4305  rhsoffset = rhscoef; /*lint !e644*/
4306  rhscoef = 1.0;
4307  rhsvar = NULL;
4308  }
4309 
4310  if( *success )
4311  {
4312  assert(!stickingatnode);
4313  SCIP_CALL( SCIPcreateConsSOC(scip, cons, name, nvars, vars, coefs, offsets, constant, rhsvar, rhscoef, rhsoffset,
4314  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) ); /*lint !e644 */
4315  }
4316 
4317  SCIPfreeBufferArray(scip, &vars);
4318  SCIPfreeBufferArray(scip, &coefs);
4319  SCIPfreeBufferArray(scip, &offsets);
4320 
4321  return SCIP_OKAY;
4322 }
4323 
4324 /** constraint method of constraint handler which returns the variables (if possible) */
4325 static
4326 SCIP_DECL_CONSGETVARS(consGetVarsSOC)
4327 { /*lint --e{715}*/
4328  SCIP_CONSDATA* consdata;
4329 
4330  consdata = SCIPconsGetData(cons);
4331  assert(consdata != NULL);
4332 
4333  if( varssize < consdata->nvars + 1 )
4334  (*success) = FALSE;
4335  else
4336  {
4337  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
4338  vars[consdata->nvars] = consdata->rhsvar;
4339  (*success) = TRUE;
4340  }
4341 
4342  return SCIP_OKAY;
4343 }
4344 
4345 /** constraint method of constraint handler which returns the number of variable (if possible) */
4346 static
4347 SCIP_DECL_CONSGETNVARS(consGetNVarsSOC)
4348 { /*lint --e{715}*/
4349  SCIP_CONSDATA* consdata;
4350 
4351  assert(cons != NULL);
4352 
4353  consdata = SCIPconsGetData(cons);
4354  assert(consdata != NULL);
4355 
4356  (*nvars) = consdata->nvars + 1;
4357  (*success) = TRUE;
4358 
4359  return SCIP_OKAY;
4360 }
4361 
4362 /*
4363  * constraint specific interface methods
4364  */
4365 
4366 /** creates the handler for second order cone constraints and includes it in SCIP */
4368  SCIP* scip /**< SCIP data structure */
4369  )
4370 {
4371  SCIP_CONSHDLRDATA* conshdlrdata;
4372  SCIP_CONSHDLR* conshdlr;
4373  SCIP_EVENTHDLR* eventhdlr;
4374 
4375  /* create constraint handler data */
4376  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
4377  conshdlrdata->subnlpheur = NULL;
4378  conshdlrdata->trysolheur = NULL;
4379 
4380  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, CONSHDLR_NAME"_boundchange",
4381  "signals a bound change to a second order cone constraint",
4382  processVarEvent, NULL) );
4383  conshdlrdata->eventhdlr = eventhdlr;
4384 
4385  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution",
4386  "handles the event that a new primal solution has been found",
4387  processNewSolutionEvent, NULL) );
4388 
4389  /* include constraint handler */
4392  consEnfolpSOC, consEnfopsSOC, consCheckSOC, consLockSOC,
4393  conshdlrdata) );
4394  assert(conshdlr != NULL);
4395 
4396  /* set non-fundamental callbacks via specific setter functions */
4397  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOC, consCopySOC) );
4398  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOC) );
4399  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitSOC) );
4400  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSOC) );
4401  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOC) );
4402  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOC) );
4403  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOC) );
4404  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOC) );
4405  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitSOC) );
4406  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSOC) );
4407  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOC) );
4408  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSOC, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
4409  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOC) );
4411  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOC, consSepasolSOC, CONSHDLR_SEPAFREQ,
4413  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOC) ); /* include constraint handler */
4414 
4415  if( SCIPfindConshdlr(scip,"quadratic") != NULL )
4416  {
4417  /* notify function that upgrades quadratic constraint to SOC's */
4419  }
4420 
4421  /* add soc constraint handler parameters */
4422  SCIP_CALL( SCIPaddCharParam(scip, "constraints/"CONSHDLR_NAME"/scaling",
4423  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
4424  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
4425 
4426  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/projectpoint",
4427  "whether the reference point of a cut should be projected onto the feasible set of the SOC constraint",
4428  &conshdlrdata->projectpoint, TRUE, FALSE, NULL, NULL) );
4429 
4430  SCIP_CALL( SCIPaddIntParam (scip, "constraints/"CONSHDLR_NAME"/nauxvars",
4431  "number of auxiliary variables to use when creating a linear outer approx. of a SOC3 constraint; 0 to turn off",
4432  &conshdlrdata->nauxvars, FALSE, 0, 0, INT_MAX, NULL, NULL) );
4433 
4434  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/glineur",
4435  "whether the Glineur Outer Approximation should be used instead of Ben-Tal Nemirovski",
4436  &conshdlrdata->glineur, FALSE, TRUE, NULL, NULL) );
4437 
4438  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacy",
4439  "minimal efficacy of a cut to be added to LP in separation",
4440  &conshdlrdata->minefficacy, FALSE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
4441 
4442  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/sparsify",
4443  "whether to sparsify cuts",
4444  &conshdlrdata->sparsify, TRUE, FALSE, NULL, NULL) );
4445 
4446  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sparsifymaxloss",
4447  "maximal loss in cut efficacy by sparsification",
4448  &conshdlrdata->sparsifymaxloss, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
4449 
4450  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sparsifynzgrowth",
4451  "growth rate of maximal allowed nonzeros in cuts in sparsification",
4452  &conshdlrdata->sparsifynzgrowth, TRUE, 1.3, 1.000001, SCIPinfinity(scip), NULL, NULL) );
4453 
4454  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linfeasshift",
4455  "whether to try to make solutions feasible in check by shifting the variable on the right hand side",
4456  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
4457 
4458  SCIP_CALL( SCIPaddCharParam(scip, "constraints/"CONSHDLR_NAME"/nlpform",
4459  "which formulation to use when adding a SOC constraint to the NLP (a: automatic, q: nonconvex quadratic form, s: convex sqrt form, e: convex exponential-sqrt form, d: convex division form)",
4460  &conshdlrdata->nlpform, FALSE, 'a', "aqsed", NULL, NULL) );
4461 
4462  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sepanlpmincont",
4463  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
4464  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
4465 
4466  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/enfocutsremovable",
4467  "are cuts added during enforcement removable from the LP in the same node?",
4468  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
4469 
4470  return SCIP_OKAY;
4471 }
4472 
4473 /** creates and captures a second order cone constraint
4474  *
4475  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4476  */
4478  SCIP* scip, /**< SCIP data structure */
4479  SCIP_CONS** cons, /**< pointer to hold the created constraint */
4480  const char* name, /**< name of constraint */
4481  int nvars, /**< number of variables on left hand side of constraint (n) */
4482  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
4483  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
4484  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
4485  SCIP_Real constant, /**< constant on left hand side (gamma) */
4486  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
4487  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
4488  SCIP_Real rhsoffset, /**< offset of variable on right hand side (beta_{n+1}) */
4489  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
4490  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
4491  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
4492  * Usually set to TRUE. */
4493  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
4494  * TRUE for model constraints, FALSE for additional, redundant constraints. */
4495  SCIP_Bool check, /**< should the constraint be checked for feasibility?
4496  * TRUE for model constraints, FALSE for additional, redundant constraints. */
4497  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
4498  * Usually set to TRUE. */
4499  SCIP_Bool local, /**< is constraint only valid locally?
4500  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
4501  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
4502  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
4503  * adds coefficients to this constraint. */
4504  SCIP_Bool dynamic, /**< is constraint subject to aging?
4505  * Usually set to FALSE. Set to TRUE for own cuts which
4506  * are separated as constraints. */
4507  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
4508  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
4509  )
4510 {
4511  SCIP_CONSHDLR* conshdlr;
4512  SCIP_CONSDATA* consdata;
4513  int i;
4514 
4515  assert(scip != NULL);
4516  assert(cons != NULL);
4517  assert(modifiable == FALSE); /* we do not support column generation */
4518 
4519  /* find the soc constraint handler */
4520  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
4521  if( conshdlr == NULL )
4522  {
4523  SCIPerrorMessage("SOC constraint handler not found\n");
4524  return SCIP_PLUGINNOTFOUND;
4525  }
4526 
4527  assert(vars != NULL);
4528  assert(nvars >= 2);
4529  assert(constant >= 0.0);
4530  assert(!SCIPisInfinity(scip, ABS(rhsoffset)));
4531  assert(!SCIPisInfinity(scip, constant));
4532  assert(rhsvar == NULL || rhscoeff <= 0.0 || SCIPisGE(scip, local ? SCIPcomputeVarLbLocal(scip, rhsvar) : SCIPcomputeVarLbGlobal(scip, rhsvar), -rhsoffset));
4533  assert(rhsvar == NULL || rhscoeff >= 0.0 || SCIPisLE(scip, local ? SCIPcomputeVarUbLocal(scip, rhsvar) : SCIPcomputeVarUbGlobal(scip, rhsvar), -rhsoffset));
4534 
4535  /* create constraint data */
4536  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
4537 
4538  consdata->nvars = nvars;
4539  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
4540  for( i = 0; i < nvars; ++i )
4541  {
4542  SCIP_CALL( SCIPcaptureVar(scip, vars[i]) );
4543  }
4544 
4545  if( coefs != NULL )
4546  {
4547  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->coefs, coefs, nvars) );
4548  for( i = 0; i < nvars; ++i )
4549  if( consdata->coefs[i] < 0.0 )
4550  consdata->coefs[i] = -consdata->coefs[i];
4551  }
4552  else
4553  {
4554  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->coefs, nvars) );
4555  for( i = 0; i < nvars; ++i )
4556  consdata->coefs[i] = 1.0;
4557  }
4558 
4559  if( offsets != NULL )
4560  {
4561  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->offsets, offsets, nvars) );
4562  }
4563  else
4564  {
4565  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->offsets, nvars) );
4566  BMSclearMemoryArray(consdata->offsets, nvars);
4567  }
4568 
4569  consdata->constant = constant;
4570  consdata->rhsvar = rhsvar;
4571  consdata->rhscoeff = rhscoeff;
4572  consdata->rhsoffset = rhsoffset;
4573 
4574  if( rhsvar != NULL )
4575  {
4576  SCIP_CALL( SCIPcaptureVar(scip, rhsvar) );
4577  }
4578 
4579  consdata->nlrow = NULL;
4580 
4581  consdata->lhsbndchgeventdatas = NULL;
4582  consdata->ispropagated = FALSE;
4583  consdata->isapproxadded = FALSE;
4584 
4585  /* create constraint */
4586  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
4587  local, modifiable, dynamic, removable, FALSE) );
4588 
4589  if( SCIPisTransformed(scip) )
4590  {
4591  SCIP_CONSHDLRDATA* conshdlrdata = SCIPconshdlrGetData(conshdlr);
4592  assert(conshdlrdata != NULL);
4593 
4594  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *cons) );
4595  }
4596 
4597  return SCIP_OKAY;
4598 }
4599 
4600 /** creates and captures a second order cone constraint with all its constraint flags
4601  * set to their default values
4602  *
4603  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4604  */
4606  SCIP* scip, /**< SCIP data structure */
4607  SCIP_CONS** cons, /**< pointer to hold the created constraint */
4608  const char* name, /**< name of constraint */
4609  int nvars, /**< number of variables on left hand side of constraint (n) */
4610  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
4611  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
4612  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
4613  SCIP_Real constant, /**< constant on left hand side (gamma) */
4614  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
4615  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
4616  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
4617  )
4618 {
4619  SCIP_CALL( SCIPcreateConsSOC(scip, cons, name, nvars, vars, coefs, offsets, constant,
4620  rhsvar, rhscoeff, rhsoffset,
4621  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
4622 
4623  return SCIP_OKAY;
4624 }
4625 
4626 /** Gets the SOC constraint as a nonlinear row representation.
4627  */
4629  SCIP* scip, /**< SCIP data structure */
4630  SCIP_CONS* cons, /**< constraint */
4631  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
4632  )
4633 {
4634  SCIP_CONSDATA* consdata;
4635 
4636  assert(cons != NULL);
4637  assert(nlrow != NULL);
4638 
4639  consdata = SCIPconsGetData(cons);
4640  assert(consdata != NULL);
4641 
4642  if( consdata->nlrow == NULL )
4643  {
4644  SCIP_CALL( createNlRow(scip, SCIPconsGetHdlr(cons), cons) );
4645  }
4646  assert(consdata->nlrow != NULL);
4647  *nlrow = consdata->nlrow;
4648 
4649  return SCIP_OKAY;
4650 }
4651 
4652 /** Gets the number of variables on the left hand side of a SOC constraint.
4653  */
4655  SCIP* scip, /**< SCIP data structure */
4656  SCIP_CONS* cons /**< constraint data */
4657  )
4658 {
4659  assert(cons != NULL);
4660  assert(SCIPconsGetData(cons) != NULL);
4661 
4662  return SCIPconsGetData(cons)->nvars;
4663 }
4664 
4665 /** Gets the variables on the left hand side of a SOC constraint.
4666  */
4668  SCIP* scip, /**< SCIP data structure */
4669  SCIP_CONS* cons /**< constraint data */
4670  )
4671 {
4672  assert(cons != NULL);
4673  assert(SCIPconsGetData(cons) != NULL);
4674 
4675  return SCIPconsGetData(cons)->vars;
4676 }
4677 
4678 /** Gets the coefficients of the variables on the left hand side of a SOC constraint, or NULL if all are equal to 1.0.
4679  */
4681  SCIP* scip, /**< SCIP data structure */
4682  SCIP_CONS* cons /**< constraint data */
4683  )
4684 {
4685  assert(cons != NULL);
4686  assert(SCIPconsGetData(cons) != NULL);
4687 
4688  return SCIPconsGetData(cons)->coefs;
4689 }
4690 
4691 /** Gets the offsets of the variables on the left hand side of a SOC constraint, or NULL if all are equal to 0.0.
4692  */
4694  SCIP* scip, /**< SCIP data structure */
4695  SCIP_CONS* cons /**< constraint data */
4696  )
4697 {
4698  assert(cons != NULL);
4699  assert(SCIPconsGetData(cons) != NULL);
4700 
4701  return SCIPconsGetData(cons)->offsets;
4702 }
4703 
4704 /** Gets the constant on the left hand side of a SOC constraint.
4705  */
4707  SCIP* scip, /**< SCIP data structure */
4708  SCIP_CONS* cons /**< constraint data */
4709  )
4710 {
4711  assert(cons != NULL);
4712  assert(SCIPconsGetData(cons) != NULL);
4713 
4714  return SCIPconsGetData(cons)->constant;
4715 }
4716 
4717 /** Gets the variable on the right hand side of a SOC constraint.
4718  */
4720  SCIP* scip, /**< SCIP data structure */
4721  SCIP_CONS* cons /**< constraint data */
4722  )
4723 {
4724  assert(cons != NULL);
4725  assert(SCIPconsGetData(cons) != NULL);
4726 
4727  return SCIPconsGetData(cons)->rhsvar;
4728 }
4729 
4730 /** Gets the coefficient of the variable on the right hand side of a SOC constraint.
4731  */
4733  SCIP* scip, /**< SCIP data structure */
4734  SCIP_CONS* cons /**< constraint data */
4735  )
4736 {
4737  assert(cons != NULL);
4738  assert(SCIPconsGetData(cons) != NULL);
4739 
4740  return SCIPconsGetData(cons)->rhscoeff;
4741 }
4742 
4743 /** Gets the offset of the variables on the right hand side of a SOC constraint.
4744  */
4746  SCIP* scip, /**< SCIP data structure */
4747  SCIP_CONS* cons /**< constraint data */
4748  )
4749 {
4750  assert(cons != NULL);
4751  assert(SCIPconsGetData(cons) != NULL);
4752 
4753  return SCIPconsGetData(cons)->rhsoffset;
4754 }
4755 
4756 /** Adds the constraint to an NLPI problem.
4757  * Uses nonconvex formulation as quadratic function.
4758  */
4760  SCIP* scip, /**< SCIP data structure */
4761  SCIP_CONS* cons, /**< SOC constraint */
4762  SCIP_NLPI* nlpi, /**< interface to NLP solver */
4763  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
4764  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
4765  SCIP_Bool names /**< whether to pass constraint names to NLPI */
4766  )
4767 {
4768  SCIP_CONSDATA* consdata;
4769  int nlininds;
4770  int* lininds;
4771  SCIP_Real* linvals;
4772  int nquadelems;
4773  SCIP_QUADELEM* quadelems;
4774  int j;
4775  int lincnt;
4776  SCIP_Real lhs;
4777  SCIP_Real rhs;
4778  const char* name;
4779 
4780  assert(scip != NULL);
4781  assert(cons != NULL);
4782  assert(nlpi != NULL);
4783  assert(nlpiprob != NULL);
4784  assert(scipvar2nlpivar != NULL);
4785 
4786  consdata = SCIPconsGetData(cons);
4787  assert(consdata != NULL);
4788 
4789  lhs = -SCIPinfinity(scip);
4790  rhs = -consdata->constant;
4791 
4792  /* count how length is the linear part, i.e., how many offsets we have */
4793  nlininds = consdata->rhsoffset != 0.0 ? 1 : 0;
4794  for( j = 0; j < consdata->nvars; ++j )
4795  if( consdata->offsets[j] != 0.0 )
4796  ++nlininds;
4797 
4798  lininds = NULL;
4799  linvals = NULL;
4800  if( nlininds )
4801  {
4802  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
4803  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
4804  }
4805  lincnt = 0;
4806 
4807  nquadelems = consdata->nvars + 1;
4808  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
4809 
4810  for( j = 0; j < consdata->nvars; ++j )
4811  {
4812  quadelems[j].idx1 = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->vars[j]);
4813  quadelems[j].idx2 = quadelems[j].idx1;
4814  quadelems[j].coef = consdata->coefs[j] * consdata->coefs[j];
4815 
4816  if( consdata->offsets[j] != 0.0 )
4817  {
4818  assert(lininds != NULL);
4819  assert(linvals != NULL);
4820  lininds[lincnt] = quadelems[j].idx1;
4821  linvals[lincnt] = 2 * quadelems[j].coef * consdata->offsets[j];
4822  ++lincnt;
4823 
4824  rhs -= quadelems[j].coef * consdata->offsets[j] * consdata->offsets[j];
4825  }
4826  }
4827  quadelems[consdata->nvars].idx1 = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->rhsvar);
4828  quadelems[consdata->nvars].idx2 = quadelems[consdata->nvars].idx1;
4829  quadelems[consdata->nvars].coef = - consdata->rhscoeff * consdata->rhscoeff;
4830 
4831  if( consdata->rhsoffset != 0.0 )
4832  {
4833  assert(lininds != NULL);
4834  assert(linvals != NULL);
4835  lininds[lincnt] = quadelems[consdata->nvars].idx1;
4836  linvals[lincnt] = -2.0 * consdata->rhscoeff * consdata->rhscoeff * consdata->rhsoffset;
4837  ++lincnt;
4838 
4839  rhs += consdata->rhscoeff * consdata->rhscoeff * consdata->rhsoffset * consdata->rhsoffset;
4840  }
4841 
4842  assert(lincnt == nlininds);
4843 
4844  name = names ? SCIPconsGetName(cons) : NULL;
4845 
4846  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
4847  &lhs, &rhs,
4848  &nlininds, &lininds, &linvals,
4849  &nquadelems, &quadelems,
4850  NULL, NULL, &name) );
4851 
4852  SCIPfreeBufferArrayNull(scip, &lininds);
4853  SCIPfreeBufferArrayNull(scip, &linvals);
4854  SCIPfreeBufferArray(scip, &quadelems);
4855 
4856  return SCIP_OKAY;
4857 }
4858