Scippy

SCIP

Solving Constraint Integer Programs

nlhdlr_quadratic.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file nlhdlr_quadratic.c
26 * @ingroup DEFPLUGINS_NLHDLR
27 * @brief nonlinear handler to handle quadratic expressions
28 * @author Felipe Serrano
29 * @author Antonia Chmiela
30 *
31 * Some definitions:
32 * - a `BILINEXPRTERM` is a product of two expressions
33 * - a `QUADEXPRTERM` stores an expression `expr` that is known to appear in a nonlinear, quadratic term, that is
34 * `expr^2` or `expr*other_expr`. It stores its `sqrcoef` (that can be 0), its linear coef and all the bilinear expression
35 * terms in which expr appears.
36 */
37
38/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39
40/* #define DEBUG_INTERSECTIONCUT */
41/* #define DEBUG_MONOIDAL */
42/* #define INTERCUT_MOREDEBUG */
43/* #define INTERCUTS_VERBOSE */
44
45#ifdef INTERCUTS_VERBOSE
46#define INTER_LOG
47#endif
48
49#ifdef INTER_LOG
50#define INTERLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
51#else
52#define INTERLOG(x)
53#endif
54
55#include "scip/cons_nonlinear.h"
56#include "scip/pub_nlhdlr.h"
58#include "scip/expr_pow.h"
59#include "scip/expr_sum.h"
60#include "scip/expr_var.h"
61#include "scip/expr_product.h"
63
64/* fundamental nonlinear handler properties */
65#define NLHDLR_NAME "quadratic"
66#define NLHDLR_DESC "handler for quadratic expressions"
67#define NLHDLR_DETECTPRIORITY 1
68#define NLHDLR_ENFOPRIORITY 100
69
70/* properties of the quadratic nlhdlr statistics table */
71#define TABLE_NAME_QUADRATIC "nlhdlr_quadratic"
72#define TABLE_DESC_QUADRATIC "quadratic nlhdlr statistics table"
73#define TABLE_POSITION_QUADRATIC 14700 /**< the position of the statistics table */
74#define TABLE_EARLIEST_STAGE_QUADRATIC SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
75
76/* some default values */
77#define INTERCUTS_MINVIOL 1e-4
78#define DEFAULT_USEINTERCUTS FALSE
79#define DEFAULT_USESTRENGTH FALSE
80#define DEFAULT_USEMONOIDAL TRUE
81#define DEFAULT_USEMINREP TRUE
82#define DEFAULT_USEBOUNDS FALSE
83#define BINSEARCH_MAXITERS 120
84#define DEFAULT_NCUTSROOT 20
85#define DEFAULT_NCUTS 2
86
87/*
88 * Data structures
89 */
90
91/** nonlinear handler expression data */
92struct SCIP_NlhdlrExprData
93{
94 SCIP_EXPR* qexpr; /**< quadratic expression (stored here again for convenient access) */
95
96 SCIP_EXPRCURV curvature; /**< curvature of the quadratic representation of the expression */
97
98 SCIP_INTERVAL linactivity; /**< activity of linear part */
99
100 /* activities of quadratic parts as defined in nlhdlrIntevalQuadratic */
101 SCIP_Real minquadfiniteact; /**< minimum activity of quadratic part where only terms with finite min
102 activity contribute */
103 SCIP_Real maxquadfiniteact; /**< maximum activity of quadratic part where only terms with finite max
104 activity contribute */
105 int nneginfinityquadact;/**< number of quadratic terms contributing -infinity to activity */
106 int nposinfinityquadact;/**< number of quadratic terms contributing +infinity to activity */
107 SCIP_INTERVAL* quadactivities; /**< activity of each quadratic term as defined in nlhdlrIntevalQuadratic */
108 SCIP_INTERVAL quadactivity; /**< activity of quadratic part (sum of quadactivities) */
109 SCIP_Longint activitiestag; /**< value of activities tag when activities were computed */
110
111 SCIP_CONS* cons; /**< if expr is the root of constraint cons, store cons; otherwise NULL */
112 SCIP_Bool separating; /**< whether we are using the nlhdlr also for separation */
113 SCIP_Bool origvars; /**< whether the quad expr in qexpr is in original (non-aux) variables */
114
115 int ncutsadded; /**< number of intersection cuts added for this quadratic */
116};
117
118/** nonlinear handler data */
119struct SCIP_NlhdlrData
120{
121 int ncutsgenerated; /**< total number of cuts that where generated by separateQuadratic */
122 int ncutsadded; /**< total number of cuts that where generated by separateQuadratic and actually added */
123 SCIP_Longint lastnodenumber; /**< number of last node for which cuts were (allowed to be) generated */
124 int lastncuts; /**< number of cuts already generated */
125
126 /* parameter */
127 SCIP_Bool useintersectioncuts; /**< whether to use intersection cuts for quadratic constraints or not */
128 SCIP_Bool usestrengthening; /**< whether the strengthening should be used */
129 SCIP_Bool usemonoidal; /**< whether monoidal strengthening should be used */
130 SCIP_Bool useminrep; /**< whether the minimal representation of the S-free set should be used (instead of the gauge) */
131 SCIP_Bool useboundsasrays; /**< use bounds of variables in quadratic as rays for intersection cuts */
132 int ncutslimit; /**< limit for number of cuts generated consecutively */
133 int ncutslimitroot; /**< limit for number of cuts generated at root node */
134 int maxrank; /**< maximal rank a slackvar can have */
135 SCIP_Real mincutviolation; /**< minimal cut violation the generated cuts must fulfill to be added to the LP */
136 SCIP_Real minviolation; /**< minimal violation the constraint must fulfill such that a cut can be generated */
137 int atwhichnodes; /**< determines at which nodes cut is used (if it's -1, it's used only at the root node,
138 if it's n >= 0, it's used at every multiple of n) */
139 int nstrengthlimit; /**< limit for number of rays we do the strengthening for */
140 SCIP_Bool sparsifycuts; /**< should we try to sparisfy the intersection cuts? */
141 SCIP_Bool ignorebadrayrestriction; /**< should cut be generated even with bad numerics when restricting to ray? */
142 SCIP_Bool ignorehighre; /**< should cut be added even when range / efficacy is large? */
143 SCIP_Bool trackmore; /**< for monoidal strengthening, should we track more statistics (more expensive) */
144
145 /* statistics */
146 int ncouldimprovedcoef; /**< number of times a coefficient could improve but didn't because of numerics */
147 int nbadrayrestriction; /**< number of times a cut was aborted because of numerics when restricting to ray */
148 int nbadnonbasic; /**< number of times a cut was aborted because the nonbasic row was not nonbasic enough */
149 int nhighre; /**< number of times a cut was not added because range / efficacy was too large */
150 int nphinonneg; /**< number of times a cut was aborted because phi is nonnegative at 0 */
151 int nstrengthenings; /**< number of successful strengthenings */
152 int nboundcuts; /**< number of successful bound cuts */
153 int nmonoidal; /**< number of successful monoidal strengthenings */
154 SCIP_Real ncalls; /**< number of calls to separation */
155 SCIP_Real densitysum; /**< sum of density of cuts */
156 SCIP_Real cutcoefsum; /**< sum of average cutcoefs of a cut */
157 SCIP_Real monoidalimprovementsum; /**< sum of average improvement of a cut when using monoidal strengthening */
158 SCIP_Real efficacysum; /**< sum of efficacy of cuts */
159 SCIP_Real currentavecutcoef; /**< average cutcoef of current cut */
160 SCIP_Real currentavemonoidalimprovement;/**< average improvement of current cut when using monoidal strengthening */
161};
162
163/* structure to store rays. note that for a given ray, the entries in raysidx are sorted. */
164struct Rays
165{
166 SCIP_Real* rays; /**< coefficients of rays */
167 int* raysidx; /**< to which var the coef belongs; vars are [quadvars, linvars, auxvar] */
168 int* raysbegin; /**< positions of rays: coefs of i-th ray [raybegin[i], raybegin[i+1]) */
169 int* lpposray; /**< lp pos of var associated with the ray;
170 >= 0 -> lppos of var; < 0 -> var is row -lpposray -1 */
171
172 int rayssize; /**< size of rays and rays idx */
173 int nrays; /**< size of raysbegin is nrays + 1; size of lpposray */
174};
175typedef struct Rays RAYS;
176
177
178/*
179 * Callback methods of the table
180 */
181
182/** output method of statistics table to output file stream 'file' */
183static
184SCIP_DECL_TABLEOUTPUT(tableOutputQuadratic)
185{ /*lint --e{715}*/
186 SCIP_NLHDLR* nlhdlr;
187 SCIP_NLHDLRDATA* nlhdlrdata;
188 SCIP_CONSHDLR* conshdlr;
189
190 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
191 assert(conshdlr != NULL);
192 nlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, NLHDLR_NAME);
193 assert(nlhdlr != NULL);
194 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
195 assert(nlhdlrdata);
196
197 /* print statistics */
198 SCIPinfoMessage(scip, file, "Quadratic Nlhdlr : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %20s %10s %10s %10s \n", "GenCuts", "AddCuts", "CouldImpr", "NLargeRE",
199 "AbrtBadRay", "AbrtPosPhi", "AbrtNonBas", "NStrength", "NMonoidal", "AveCutcoef", "AveMonoidalImprov", "AveDensity", "AveEfficacy", "AveBCutsFrac");
200 SCIPinfoMessage(scip, file, " %-17s:", "Quadratic Nlhdlr");
201 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncutsgenerated);
202 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncutsadded);
203 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncouldimprovedcoef);
204 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nhighre);
205 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nbadrayrestriction);
206 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nphinonneg);
207 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nbadnonbasic);
208 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nstrengthenings);
209 SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nmonoidal);
210 SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->cutcoefsum / nlhdlrdata->ncutsgenerated : 0.0);
211 SCIPinfoMessage(scip, file, " %20g", (nlhdlrdata->nmonoidal > 0 && nlhdlrdata->trackmore) ? nlhdlrdata->monoidalimprovementsum / nlhdlrdata->nmonoidal : -1.0);
212 SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->densitysum / nlhdlrdata->ncutsgenerated : 0.0);
213 SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->efficacysum / nlhdlrdata->ncutsgenerated : 0.0);
214 SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncalls > 0 ? nlhdlrdata->nboundcuts / nlhdlrdata->ncalls : 0.0);
215 SCIPinfoMessage(scip, file, "\n");
216
217 return SCIP_OKAY;
218}
219
220/** collects quadratic nonlinear handler statistics into a SCIP_DATATREE object */
221static
222SCIP_DECL_TABLECOLLECT(tableCollectQuadratic)
223{
224 SCIP_NLHDLR* nlhdlr;
225 SCIP_NLHDLRDATA* nlhdlrdata;
226 SCIP_CONSHDLR* conshdlr;
227
228 assert(scip != NULL);
229 assert(table != NULL);
230 assert(datatree != NULL);
231
232 /* Find the nonlinear constraint handler */
233 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
234 assert(conshdlr != NULL);
235
236 /* Find the quadratic nonlinear handler */
237 nlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, NLHDLR_NAME);
238 assert(nlhdlr != NULL);
239
240 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
241 assert(nlhdlrdata != NULL);
242
243 /* Insert statistics into the data tree */
244 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "ngeneratedcuts", nlhdlrdata->ncutsgenerated) );
245 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "naddedcuts", nlhdlrdata->ncutsadded) );
246 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "couldimprovecoef", nlhdlrdata->ncouldimprovedcoef) );
247 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nlargerejections", nlhdlrdata->nhighre) );
248 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nabortbadray", nlhdlrdata->nbadrayrestriction) );
249 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nabortposphi", nlhdlrdata->nphinonneg) );
250 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nabortnonbasic", nlhdlrdata->nbadnonbasic) );
251 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nstrengthenings", nlhdlrdata->nstrengthenings) );
252 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "nmonoidal", nlhdlrdata->nmonoidal) );
253
254 /* Insert calculated averages */
255 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "averagecutcoefficient",
256 nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->cutcoefsum / nlhdlrdata->ncutsgenerated : 0.0) );
257
258 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "averagemonoidalimprovement",
259 (nlhdlrdata->nmonoidal > 0 && nlhdlrdata->trackmore) ? nlhdlrdata->monoidalimprovementsum / nlhdlrdata->nmonoidal : -1.0) );
260
261 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "averagedensity",
262 nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->densitysum / nlhdlrdata->ncutsgenerated : 0.0) );
263
264 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "averageefficacy",
265 nlhdlrdata->ncutsgenerated > 0 ? nlhdlrdata->efficacysum / nlhdlrdata->ncutsgenerated : 0.0) );
266
267 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "averagebcutsfraction",
268 nlhdlrdata->ncalls > 0 ? nlhdlrdata->nboundcuts / nlhdlrdata->ncalls : 0.0) );
269
270 return SCIP_OKAY;
271}
272
273
274/*
275 * static methods
276 */
277
278/** adds cutcoef * (col - col*) to rowprep */
279static
281 SCIP* scip, /**< SCIP data structure */
282 SCIP_ROWPREP* rowprep, /**< rowprep to store intersection cut */
283 SCIP_SOL* sol, /**< solution to separate */
284 SCIP_Real cutcoef, /**< cut coefficient */
285 SCIP_COL* col /**< column to add to rowprep */
286 )
287{
288 assert(col != NULL);
289
290#ifdef DEBUG_INTERCUTS_NUMERICS
291 SCIPinfoMessage(scip, NULL, "adding col %s to cut. %g <= col <= %g\n", SCIPvarGetName(SCIPcolGetVar(col)),
293 SCIPinfoMessage(scip, NULL, "col is active at %s. Value %.15f\n", SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_LOWER ? "lower bound" :
294 "upper bound" , SCIPcolGetPrimsol(col));
295#endif
296
297 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPcolGetVar(col), cutcoef) );
298 SCIProwprepAddConstant(rowprep, -cutcoef * SCIPgetSolVal(scip, sol, SCIPcolGetVar(col)) );
299
300 return SCIP_OKAY;
301}
302
303/** adds cutcoef * (slack - slack*) to rowprep
304 *
305 * row is lhs &le; <coefs, vars> + constant &le; rhs, thus slack is defined by
306 * slack + <coefs.vars> + constant = side
307 *
308 * If row (slack) is at upper, it means that <coefs,vars*> + constant = rhs, and so
309 * slack* = side - rhs --> slack - slack* = rhs - <coefs, vars> - constant.
310 *
311 * If row (slack) is at lower, then <coefs,vars*> + constant = lhs, and so
312 * slack* = side - lhs --> slack - slack* = lhs - <coefs, vars> - constant.
313 */
314static
316 SCIP* scip, /**< SCIP data structure */
317 SCIP_ROWPREP* rowprep, /**< rowprep to store intersection cut */
318 SCIP_Real cutcoef, /**< cut coefficient */
319 SCIP_ROW* row, /**< row, whose slack we are ading to rowprep */
320 SCIP_Bool* success /**< if the row is nonbasic enough */
321 )
322{
323 int i;
324 SCIP_COL** rowcols;
325 SCIP_Real* rowcoefs;
326 int nnonz;
327
328 assert(row != NULL);
329
330 rowcols = SCIProwGetCols(row);
331 rowcoefs = SCIProwGetVals(row);
332 nnonz = SCIProwGetNLPNonz(row);
333
334#ifdef DEBUG_INTERCUTS_NUMERICS
335 SCIPinfoMessage(scip, NULL, "adding slack var row_%d to cut. %g <= row <= %g\n", SCIProwGetLPPos(row), SCIProwGetLhs(row), SCIProwGetRhs(row));
336 SCIPinfoMessage(scip, NULL, "row is active at %s = %.15f Activity %.15f\n", SCIProwGetBasisStatus(row) == SCIP_BASESTAT_LOWER ? "lhs" :
339#endif
340
342 {
343 assert(!SCIPisInfinity(scip, -SCIProwGetLhs(row)));
345 {
346 *success = FALSE;
347 return SCIP_OKAY;
348 }
349
350 SCIProwprepAddConstant(rowprep, SCIProwGetLhs(row) * cutcoef);
351 }
352 else
353 {
354 assert(!SCIPisInfinity(scip, SCIProwGetRhs(row)));
356 {
357 *success = FALSE;
358 return SCIP_OKAY;
359 }
360
361 SCIProwprepAddConstant(rowprep, SCIProwGetRhs(row) * cutcoef);
362 }
363
364 for( i = 0; i < nnonz; i++ )
365 {
366 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPcolGetVar(rowcols[i]), -rowcoefs[i] * cutcoef) );
367 }
368
369 SCIProwprepAddConstant(rowprep, -SCIProwGetConstant(row) * cutcoef);
370
371 return SCIP_OKAY;
372}
373
374/** constructs map between lp position of a basic variable and its row in the tableau */
375static
377 SCIP* scip, /**< SCIP data structure */
378 int* map /**< buffer to store the map */
379 )
380{
381 int* basisind;
382 int nrows;
383 int i;
384
385 nrows = SCIPgetNLPRows(scip);
386 SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
387
388 SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
389 for( i = 0; i < nrows; ++i )
390 {
391 if( basisind[i] >= 0 )
392 map[basisind[i]] = i;
393 }
394
395 SCIPfreeBufferArray(scip, &basisind);
396
397 return SCIP_OKAY;
398}
399
400/** counts the number of basic variables in the quadratic expr */
401static
403 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
404 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
405 SCIP_Bool* nozerostat /**< whether there is no variable with basis status zero */
406 )
407{
408 SCIP_EXPR* qexpr;
409 SCIP_EXPR** linexprs;
410 SCIP_COL* col;
411 int i;
412 int nbasicvars = 0;
413 int nquadexprs;
414 int nlinexprs;
415
416 *nozerostat = TRUE;
417
418 qexpr = nlhdlrexprdata->qexpr;
419 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
420
421 /* loop over quadratic vars */
422 for( i = 0; i < nquadexprs; ++i )
423 {
424 SCIP_EXPR* expr;
425
426 SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
427
430 nbasicvars += 1;
432 {
433 *nozerostat = FALSE;
434 return 0;
435 }
436 }
437
438 /* loop over linear vars */
439 for( i = 0; i < nlinexprs; ++i )
440 {
441 col = SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i]));
443 nbasicvars += 1;
445 {
446 *nozerostat = FALSE;
447 return 0;
448 }
449 }
450
451 /* finally consider the aux var (if it exists) */
452 if( auxvar != NULL )
453 {
454 col = SCIPvarGetCol(auxvar);
456 nbasicvars += 1;
458 {
459 *nozerostat = FALSE;
460 return 0;
461 }
462 }
463
464 return nbasicvars;
465}
466
467/** stores the row of the tableau where `col` is basic
468 *
469 * In general, we will have
470 *
471 * basicvar1 = tableaurow var1
472 * basicvar2 = tableaurow var2
473 * ...
474 * basicvarn = tableaurow varn
475 *
476 * However, we want to store the the tableau row by columns. Thus, we need to know which of the basic vars `col` is.
477 *
478 * Note we only store the entries of the nonbasic variables
479 */
480static
482 SCIP* scip, /**< SCIP data structure */
483 SCIP_COL* col, /**< basic columns to store its tableau row */
484 int* basicvarpos2tableaurow,/**< map between basic var and its tableau row */
485 int nbasiccol, /**< which basic var this is */
486 int raylength, /**< the length of a ray (the total number of basic vars) */
487 SCIP_Real* binvrow, /**< buffer to store row of Binv */
488 SCIP_Real* binvarow, /**< buffer to store row of Binv A */
489 SCIP_Real* tableaurows /**< pointer to store the tableau rows */
490 )
491{
492 int nrows;
493 int ncols;
494 int lppos;
495 int i;
496 SCIP_COL** cols;
497 SCIP_ROW** rows;
498 int nray;
499
500 assert(nbasiccol < raylength);
501 assert(col != NULL);
502 assert(binvrow != NULL);
503 assert(binvarow != NULL);
504 assert(tableaurows != NULL);
505 assert(basicvarpos2tableaurow != NULL);
507
508 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
509 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
510
511 lppos = SCIPcolGetLPPos(col);
512
513 assert(basicvarpos2tableaurow[lppos] >= 0);
514
515 SCIP_CALL( SCIPgetLPBInvRow(scip, basicvarpos2tableaurow[lppos], binvrow, NULL, NULL) );
516 SCIP_CALL( SCIPgetLPBInvARow(scip, basicvarpos2tableaurow[lppos], binvrow, binvarow, NULL, NULL) );
517
518 nray = 0;
519 for( i = 0; i < ncols; ++i )
521 {
522 tableaurows[nbasiccol + nray * raylength] = binvarow[i];
523 nray++;
524 }
525 for( ; i < ncols + nrows; ++i )
526 if( SCIProwGetBasisStatus(rows[i - ncols]) != SCIP_BASESTAT_BASIC )
527 {
528 tableaurows[nbasiccol + nray * raylength] = binvrow[i - ncols];
529 nray++;
530 }
531
532 return SCIP_OKAY;
533}
534
535/** stores the rows of the tableau corresponding to the basic variables in the quadratic expression
536 *
537 * Also return a map storing to which var the entry of a ray corresponds, i.e., if the tableau is
538 *
539 * basicvar_1 = ray1_1 nonbasicvar_1 + ...
540 * basicvar_2 = ray1_2 nonbasicvar_1 + ...
541 * ...
542 * basicvar_n = ray1_n nonbasicvar_1 + ...
543 *
544 * The map maps k to the position of basicvar_k in the variables of the constraint assuming the variables are sorted as
545 * [quadratic vars, linear vars, auxvar].
546 */
547static
549 SCIP* scip, /**< SCIP data structure */
550 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
551 int raylength, /**< length of a ray of the tableau */
552 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
553 SCIP_Real* tableaurows, /**< buffer to store the tableau rows */
554 int* rayentry2conspos /**< buffer to store the map */
555 )
556{
557 SCIP_EXPR* qexpr;
558 SCIP_EXPR** linexprs;
559 SCIP_Real* binvarow;
560 SCIP_Real* binvrow;
561 SCIP_COL* col;
562 int* basicvarpos2tableaurow; /* map between basic var and its tableau row */
563 int nrayentries;
564 int nquadexprs;
565 int nlinexprs;
566 int nrows;
567 int ncols;
568 int i;
569
570 nrows = SCIPgetNLPRows(scip);
571 ncols = SCIPgetNLPCols(scip);
572
573 SCIP_CALL( SCIPallocBufferArray(scip, &basicvarpos2tableaurow, ncols) );
574 SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
575 SCIP_CALL( SCIPallocBufferArray(scip, &binvarow, ncols) );
576
577 for( i = 0; i < ncols; ++i )
578 basicvarpos2tableaurow[i] = -1;
579 SCIP_CALL( constructBasicVars2TableauRowMap(scip, basicvarpos2tableaurow) );
580
581 qexpr = nlhdlrexprdata->qexpr;
582 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
583
584 /* entries of quadratic basic vars */
585 nrayentries = 0;
586 for( i = 0; i < nquadexprs; ++i )
587 {
588 SCIP_EXPR* expr;
589 SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
590
593 {
594 SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
595 tableaurows) );
596
597 rayentry2conspos[nrayentries] = i;
598 nrayentries++;
599 }
600 }
601 /* entries of linear vars */
602 for( i = 0; i < nlinexprs; ++i )
603 {
604 col = SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i]));
606 {
607 SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
608 tableaurows) );
609
610 rayentry2conspos[nrayentries] = nquadexprs + i;
611 nrayentries++;
612 }
613 }
614 /* entry of aux var (if it exists) */
615 if( auxvar != NULL )
616 {
617 col = SCIPvarGetCol(auxvar);
619 {
620 SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
621 tableaurows) );
622
623 rayentry2conspos[nrayentries] = nquadexprs + nlinexprs;
624 nrayentries++;
625 }
626 }
627 assert(nrayentries == raylength);
628
629#ifdef DEBUG_INTERSECTIONCUT
630 for( i = 0; i < ncols; ++i )
631 {
632 SCIPinfoMessage(scip, NULL, "%d column of tableau is: ",i);
633 for( int j = 0; j < raylength; ++j )
634 SCIPinfoMessage(scip, NULL, "%g ", tableaurows[i * raylength + j]);
635 SCIPinfoMessage(scip, NULL, "\n");
636 }
637#endif
638
639 SCIPfreeBufferArray(scip, &binvarow);
640 SCIPfreeBufferArray(scip, &binvrow);
641 SCIPfreeBufferArray(scip, &basicvarpos2tableaurow);
642
643 return SCIP_OKAY;
644}
645
646/** initializes rays data structure */
647static
649 SCIP* scip, /**< SCIP data structure */
650 RAYS** rays /**< rays data structure */
651 )
652{
655
657 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysidx, SCIPgetNLPCols(scip)) );
658
659 /* overestimate raysbegin and lpposray */
660 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysbegin, SCIPgetNLPCols(scip) + SCIPgetNLPRows(scip) + 1) );
662 (*rays)->raysbegin[0] = 0;
663
664 (*rays)->rayssize = SCIPgetNLPCols(scip);
665
666 return SCIP_OKAY;
667}
668
669/** initializes rays data structure for bound rays */
670static
672 SCIP* scip, /**< SCIP data structure */
673 RAYS** rays, /**< rays data structure */
674 int size /**< number of rays to allocate */
675 )
676{
679
680 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->rays, size) );
681 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysidx, size) );
682
683 /* overestimate raysbegin and lpposray */
684 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysbegin, size + 1) );
685 SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->lpposray, size) );
686 (*rays)->raysbegin[0] = 0;
687
688 (*rays)->rayssize = size;
689
690 return SCIP_OKAY;
691}
692
693/** frees rays data structure */
694static
696 SCIP* scip, /**< SCIP data structure */
697 RAYS** rays /**< rays data structure */
698 )
699{
700 if( *rays == NULL )
701 return;
702
703 SCIPfreeBufferArray(scip, &(*rays)->lpposray);
704 SCIPfreeBufferArray(scip, &(*rays)->raysbegin);
705 SCIPfreeBufferArray(scip, &(*rays)->raysidx);
706 SCIPfreeBufferArray(scip, &(*rays)->rays);
707
709}
710
711/** inserts entry to rays data structure; checks and resizes if more space is needed */
712static
714 SCIP* scip, /**< SCIP data structure */
715 RAYS* rays, /**< rays data structure */
716 SCIP_Real coef, /**< coefficient to insert */
717 int coefidx, /**< index of coefficient (conspos of var it corresponds to) */
718 int coefpos /**< where to insert coefficient */
719 )
720{
721 /* check for size */
722 if( rays->rayssize <= coefpos + 1 )
723 {
724 int newsize;
725
726 newsize = SCIPcalcMemGrowSize(scip, coefpos + 1);
727 SCIP_CALL( SCIPreallocBufferArray(scip, &(rays->rays), newsize) );
728 SCIP_CALL( SCIPreallocBufferArray(scip, &(rays->raysidx), newsize) );
729 rays->rayssize = newsize;
730 }
731
732 /* insert entry */
733 rays->rays[coefpos] = coef;
734 rays->raysidx[coefpos] = coefidx;
735
736 return SCIP_OKAY;
737}
738
739/** constructs map between the lppos of a variables and its position in the constraint assuming the constraint variables
740 * are sorted as [quad vars, lin vars, aux var (if it exists)]
741 *
742 * If a variable doesn't appear in the constraint, then its position is -1.
743 */
744static
746 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
747 SCIP_VAR* auxvar, /**< aux var of the expr */
748 int* map /**< buffer to store the mapping */
749 )
750{
751 SCIP_EXPR* qexpr;
752 SCIP_EXPR** linexprs;
753 int nquadexprs;
754 int nlinexprs;
755 int lppos;
756 int i;
757
758 qexpr = nlhdlrexprdata->qexpr;
759 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
760
761 /* set pos of quadratic vars */
762 for( i = 0; i < nquadexprs; ++i )
763 {
764 SCIP_EXPR* expr;
765 SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
766
768 map[lppos] = i;
769 }
770 /* set pos of lin vars */
771 for( i = 0; i < nlinexprs; ++i )
772 {
774 map[lppos] = nquadexprs + i;
775 }
776 /* set pos of aux var (if it exists) */
777 if( auxvar != NULL )
778 {
779 lppos = SCIPcolGetLPPos(SCIPvarGetCol(auxvar));
780 map[lppos] = nquadexprs + nlinexprs;
781 }
782
783 return;
784}
785
786/** inserts entries of factor * nray-th column of densetableaucols into rays data structure */
787static
789 SCIP* scip, /**< SCIP data structure */
790 RAYS* rays, /**< rays data structure */
791 SCIP_Real* densetableaucols, /**< column of the tableau in dense format */
792 int* rayentry2conspos, /**< map between rayentry and conspos of associated var */
793 int raylength, /**< length of a tableau column */
794 int nray, /**< which tableau column to insert */
795 int conspos, /**< conspos of ray's nonbasic var in the cons; -1 if not in the cons */
796 SCIP_Real factor, /**< factor to multiply each tableau col */
797 int* nnonz, /**< position to start adding the ray in rays and buffer to store nnonz */
798 SCIP_Bool* success /**< we can't separate if there is a nonzero ray with basis status ZERO */
799 )
800{
801 int i;
802
803 *success = TRUE;
804
805 for( i = 0; i < raylength; ++i )
806 {
807 SCIP_Real coef;
808
809 /* we have a nonzero ray with base stat zero -> can't generate cut */
810 if( factor == 0.0 && ! SCIPisZero(scip, densetableaucols[nray * raylength + i]) )
811 {
812 *success = FALSE;
813 return SCIP_OKAY;
814 }
815
816 coef = factor * densetableaucols[nray * raylength + i];
817
818 /* this might be a source of numerical issues
819 * TODO: in case of problems, an idea would be to scale the ray entries; compute the cut coef and scale it back down
820 * another idea would be to check against a smaller epsilion.
821 * The problem is that if the cut coefficient is 1/t where lpsol + t*ray intersects the S-free set.
822 * Now if t is super big, then a super small coefficient would have had an impact...
823 */
824 if( SCIPisZero(scip, coef) )
825 continue;
826
827 /* check if nonbasic var entry should come before this one */
828 if( conspos > -1 && conspos < rayentry2conspos[i] )
829 {
830 /* add nonbasic entry */
831 assert(factor != 0.0);
832
833#ifdef DEBUG_INTERSECTIONCUT
834 SCIPinfoMessage(scip, NULL, "ray belongs to nonbasic var pos %d in cons\n", conspos);
835#endif
836
837 SCIP_CALL( insertRayEntry(scip, rays, -factor, conspos, *nnonz) );
838 (*nnonz)++;
839
840 /* we are done with nonbasic entry */
841 conspos = -1;
842 }
843
844 SCIP_CALL( insertRayEntry(scip, rays, coef, rayentry2conspos[i], *nnonz) );
845 (*nnonz)++;
846 }
847
848 /* if nonbasic entry was not added and should still be added, then it should go at the end */
849 if( conspos > -1 )
850 {
851 /* add nonbasic entry */
852 assert(factor != 0.0);
853
854#ifdef DEBUG_INTERSECTIONCUT
855 SCIPinfoMessage(scip, NULL, "ray belongs to nonbasic var pos %d in cons\n", conspos);
856#endif
857
858 SCIP_CALL( insertRayEntry(scip, rays, -factor, conspos, *nnonz) );
859 (*nnonz)++;
860 }
861
862 /* finished ray entry; store its end */
863 rays->raysbegin[rays->nrays + 1] = *nnonz;
864
865#ifdef DEBUG_INTERSECTIONCUT
866 SCIPinfoMessage(scip, NULL, "entries of ray %d are between [%d, %d):\n", rays->nrays, rays->raysbegin[rays->nrays], *nnonz);
867 for( i = rays->raysbegin[rays->nrays]; i < *nnonz; ++i )
868 SCIPinfoMessage(scip, NULL, "(%d, %g), ", rays->raysidx[i], rays->rays[i]);
869 SCIPinfoMessage(scip, NULL, "\n");
870#endif
871
872 return SCIP_OKAY;
873}
874
875/** stores rays in sparse form
876 *
877 * The first rays correspond to the nonbasic variables
878 * and the last rays to the nonbasic slack variables.
879 *
880 * More details: The LP tableau is of the form
881 *
882 * basicvar_1 = ray1_1 nonbasicvar_1 + ... + raym_1 nonbasicvar_m
883 * basicvar_2 = ray1_2 nonbasicvar_1 + ... + raym_2 nonbasicvar_m
884 * ...
885 * basicvar_n = ray1_n nonbasicvar_1 + ... + raym_n nonbasicvar_m
886 * nonbasicvar_1 = 1.0 nonbasicvar_1 + ... + 0.0 nonbasicvar_m
887 * ...
888 * nonbasicvar_m = 0.0 nonbasicvar_1 + ... + 1.0 nonbasicvar_m
889 *
890 * so rayk = (rayk_1, ... rayk_n, e_k)
891 * We store the entries of the rays associated to the variables present in the quadratic expr.
892 * We do not store zero rays.
893 *
894 * Also, we store the rays as if every nonbasic variable was at lower (so that all rays moves to infinity)
895 * Since the tableau is:
896 *
897 * basicvar + Binv L (nonbasic_lower - lb) + Binv U (nonbasic_upper - ub) = basicvar_sol
898 *
899 * then:
900 *
901 * basicvar = basicvar_sol - Binv L (nonbasic_lower - lb) + Binv U (ub - nonbasic_upper)
902 *
903 * and so the entries of the rays associated with the basic variables are:
904 * rays_basicvars = [-BinvL, BinvU].
905 *
906 * So we flip the sign of the rays associated to nonbasic vars at lower.
907 * In constrast, the nonbasic part of the ray has a 1.0 for nonbasic at lower and a -1.0 for nonbasic at upper, i.e.
908 * nonbasic_lower = lb + 1.0(nonbasic_lower - lb) and
909 * nonbasic_upper = ub - 1.0(ub - nonbasic_upper)
910 */
911static
913 SCIP* scip, /**< SCIP data structure */
914 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
915 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
916 RAYS** raysptr, /**< buffer to store rays datastructure */
917 SCIP_Bool* success /**< we can't separate if there is a var with basis status ZERO */
918 )
919{
920 SCIP_Real* densetableaucols;
921 SCIP_COL** cols;
922 SCIP_ROW** rows;
923 RAYS* rays;
924 int* rayentry2conspos;
925 int* lppos2conspos;
926 int nnonbasic;
927 int nrows;
928 int ncols;
929 int nnonz;
930 int raylength;
931 int i;
932
933 nrows = SCIPgetNLPRows(scip);
934 ncols = SCIPgetNLPCols(scip);
935
936 *success = TRUE;
937
938 raylength = countBasicVars(nlhdlrexprdata, auxvar, success);
939 if( ! *success )
940 {
941 SCIPdebugMsg(scip, "failed to store sparse rays: there is a var with base status zero\n");
942 return SCIP_OKAY;
943 }
944
945 SCIP_CALL( SCIPallocBufferArray(scip, &densetableaucols, raylength * (ncols + nrows)) );
946 SCIP_CALL( SCIPallocBufferArray(scip, &rayentry2conspos, raylength) );
947
948 /* construct dense tableau and map between ray entries and position of corresponding var in quad cons */
949 SCIP_CALL( storeDenseTableauRowsByColumns(scip, nlhdlrexprdata, raylength, auxvar,
950 densetableaucols, rayentry2conspos) );
951
952 /* build rays sparsely now */
953 SCIP_CALL( SCIPallocBufferArray(scip, &lppos2conspos, ncols) );
954 for( i = 0; i < ncols; ++i )
955 lppos2conspos[i] = -1;
956
957 constructLPPos2ConsPosMap(nlhdlrexprdata, auxvar, lppos2conspos);
958
959 /* store sparse rays */
960 SCIP_CALL( createRays(scip, raysptr) );
961 rays = *raysptr;
962
963 nnonz = 0;
964 nnonbasic = 0;
965
966 /* go through nonbasic variables */
967 cols = SCIPgetLPCols(scip);
968 for( i = 0; i < ncols; ++i )
969 {
970 int oldnnonz = nnonz;
971 SCIP_COL* col;
972 SCIP_Real factor;
973
974 col = cols[i];
975
976 /* set factor to store basic entries of ray as = [-BinvL, BinvU] */
978 factor = -1.0;
980 factor = 1.0;
982 factor = 0.0;
983 else
984 continue;
985
986 SCIP_CALL( insertRayEntries(scip, rays, densetableaucols, rayentry2conspos, raylength, nnonbasic,
987 lppos2conspos[SCIPcolGetLPPos(col)], factor, &nnonz, success) );
988
989#ifdef DEBUG_INTERSECTIONCUT
990 SCIPinfoMessage(scip, NULL, "looked at ray of var %s with basestat %d, it has %d nonzeros\n-----------------\n",
991 SCIPvarGetName(SCIPcolGetVar(col)), SCIPcolGetBasisStatus(col), nnonz - oldnnonz);
992#endif
993 if( ! (*success) )
994 {
995#ifdef DEBUG_INTERSECTIONCUT
996 SCIPdebugMsg(scip, "nonzero ray associated with variable <%s> has base status zero -> abort storing rays\n",
998#endif
999 goto CLEANUP;
1000 }
1001
1002 /* if ray is non zero remember who it belongs to */
1003 assert(oldnnonz <= nnonz);
1004 if( oldnnonz < nnonz )
1005 {
1006 rays->lpposray[rays->nrays] = SCIPcolGetLPPos(col);
1007 (rays->nrays)++;
1008 }
1009 nnonbasic++;
1010 }
1011
1012 /* go through nonbasic slack variables */
1013 rows = SCIPgetLPRows(scip);
1014 for( i = 0; i < nrows; ++i )
1015 {
1016 int oldnnonz = nnonz;
1017 SCIP_ROW* row;
1018 SCIP_Real factor;
1019
1020 row = rows[i];
1021
1022 /* set factor to store basic entries of ray as = [-BinvL, BinvU]; basic status of rows are flipped! See lpi.h! */
1025 factor = 1.0;
1027 factor =-1.0;
1028 else
1029 continue;
1030
1031 SCIP_CALL( insertRayEntries(scip, rays, densetableaucols, rayentry2conspos, raylength, nnonbasic, -1, factor,
1032 &nnonz, success) );
1033 assert(*success);
1034
1035 /* if ray is non zero remember who it belongs to */
1036#ifdef DEBUG_INTERSECTIONCUT
1037 SCIPinfoMessage(scip, NULL, "looked at ray of row %d, it has %d nonzeros\n-----------------\n", i, nnonz - oldnnonz);
1038#endif
1039 assert(oldnnonz <= nnonz);
1040 if( oldnnonz < nnonz )
1041 {
1042 rays->lpposray[rays->nrays] = -SCIProwGetLPPos(row) - 1;
1043 (rays->nrays)++;
1044 }
1045 nnonbasic++;
1046 }
1047
1048CLEANUP:
1049 SCIPfreeBufferArray(scip, &lppos2conspos);
1050 SCIPfreeBufferArray(scip, &rayentry2conspos);
1051 SCIPfreeBufferArray(scip, &densetableaucols);
1052
1053 if( ! *success )
1054 {
1055 freeRays(scip, &rays);
1056 }
1057
1058 return SCIP_OKAY;
1059}
1060
1061/* TODO: which function this comment belongs to? */
1062/* this function determines how the maximal S-free set is going to look like
1063 *
1064 * There are 4 possibilities: after writing the quadratic constraint
1065 * \f$q(z) \leq 0\f$
1066 * as
1067 * \f$\Vert x(z)\Vert^2 - \Vert y\Vert^2 + w(z) + kappa \leq 0\f$,
1068 * the cases are determined according to the following:
1069 * - Case 1: w = 0 and kappa = 0
1070 * - Case 2: w = 0 and kappa > 0
1071 * - Case 3: w = 0 and kappa < 0
1072 * - Case 4: w != 0
1073 */
1074
1075/** compute quantities for intersection cuts
1076 *
1077 * Assume the quadratic is stored as
1078 * \f[ q(z) = z_q^T Q z_q + b_q^T z_q + b_l z_l + c - z_a \f]
1079 * where:
1080 * - \f$z_q\f$ are the quadratic vars
1081 * - \f$z_l\f$ are the linear vars
1082 * - \f$z_a\f$ is the aux var if it exists
1083 *
1084 * We can rewrite it as
1085 * \f[ \Vert x(z)\Vert^2 - \Vert y\Vert^2 + w(z) + \kappa \leq 0. \f]
1086 * To do this transformation and later to compute the actual cut we need to compute and store some quantities.
1087 * Let
1088 * - \f$I_0\f$, \f$I_+\f$, and \f$I_-\f$ be the index set of zero, positive, and negative eigenvalues, respectively
1089 * - \f$v_i\f$ be the i-th eigenvector of \f$Q\f$
1090 * - \f$zlp\f$ be the lp value of the variables \f$z\f$
1091 *
1092 * The quantities we need are:
1093 * - \f$vb_i = v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$
1094 * - \f$vzlp_i = v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$
1095 * - \f$\kappa = c - 1/4 \sum_{i \in I_+ \cup I_-} (v_i^T b_q)^2 / eigval_i\f$
1096 * - \f$w(z) = (\sum_{i \in I_0} v_i^T b_q v_i^T) z_q + b_l^T z_l - z_a\f$
1097 * - \f$w(zlp)\f$
1098 *
1099 * @return \f$\kappa\f$ and the vector \f$\sum_{i \in I_0} v_i^T b_q v_i^T\f$
1100 *
1101 * @note if the constraint is q(z) &le; rhs, then the constant when writing the constraint as quad &le; 0 is c - rhs.
1102 * @note if the quadratic constraint we are separating is q(z) &ge; lhs, then we multiply by -1.
1103 * In practice, what changes is
1104 * - the sign of the eigenvalues
1105 * - the sign of \f$b_q\f$ and \f$b_l\f$
1106 * - the sign of the coefficient of the auxvar (if it exists)
1107 * - the constant of the quadratic written as quad &le; 0 is lhs - c
1108 * @note The eigenvectors _do not_ change sign!
1109 */
1110static
1112 SCIP* scip, /**< SCIP data structure */
1113 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1114 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
1115 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1116 SCIP_SOL* sol, /**< solution to separate */
1117 SCIP_Real* vb, /**< buffer to store \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1118 SCIP_Real* vzlp, /**< buffer to store \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1119 SCIP_Real* wcoefs, /**< buffer to store the coefs of quad vars of w */
1120 SCIP_Real* wzlp, /**< pointer to store the value of w at zlp */
1121 SCIP_Real* kappa /**< pointer to store the value of kappa */
1122 )
1123{
1124 SCIP_EXPR* qexpr;
1125 SCIP_EXPR** linexprs;
1126 SCIP_Real* eigenvectors;
1127 SCIP_Real* eigenvalues;
1128 SCIP_Real* lincoefs;
1129 SCIP_Real constant; /* constant of the quadratic when written as <= 0 */
1130 int nquadexprs;
1131 int nlinexprs;
1132 int i;
1133 int j;
1134
1135 assert(sidefactor == 1.0 || sidefactor == -1.0);
1136 assert(nlhdlrexprdata->cons != NULL || auxvar != NULL );
1137
1138 qexpr = nlhdlrexprdata->qexpr;
1139 SCIPexprGetQuadraticData(qexpr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, &eigenvalues,
1140 &eigenvectors);
1141
1142 assert( eigenvalues != NULL );
1143
1144 /* first get constant of quadratic when written as quad <= 0 */
1145 if( nlhdlrexprdata->cons != NULL )
1146 constant = (sidefactor == 1.0) ? constant - SCIPgetRhsNonlinear(nlhdlrexprdata->cons) :
1147 SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - constant;
1148 else
1149 constant = (sidefactor * constant);
1150
1151 *kappa = 0.0;
1152 *wzlp = 0.0;
1153 BMSclearMemoryArray(wcoefs, nquadexprs);
1154
1155 for( i = 0; i < nquadexprs; ++i )
1156 {
1157 SCIP_Real vdotb;
1158 SCIP_Real vdotzlp;
1159 int offset;
1160
1161 offset = i * nquadexprs;
1162
1163 /* compute v_i^T b and v_i^T zlp */
1164 vdotb = 0;
1165 vdotzlp = 0;
1166 for( j = 0; j < nquadexprs; ++j )
1167 {
1168 SCIP_EXPR* expr;
1169 SCIP_Real lincoef;
1170
1171 SCIPexprGetQuadraticQuadTerm(qexpr, j, &expr, &lincoef, NULL, NULL, NULL, NULL);
1172
1173 vdotb += (sidefactor * lincoef) * eigenvectors[offset + j];
1174
1175#ifdef INTERCUT_MOREDEBUG
1176 printf("vdotb: offset %d, eigenvector %d = %g, lincoef quad %g\n", offset, j,
1177 eigenvectors[offset + j], lincoef);
1178#endif
1179 vdotzlp += SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr)) * eigenvectors[offset + j];
1180 }
1181 vb[i] = vdotb;
1182 vzlp[i] = vdotzlp;
1183
1184 if( ! SCIPisZero(scip, eigenvalues[i]) )
1185 {
1186 /* nonzero eigenvalue: compute kappa */
1187 *kappa += SQR(vdotb) / (sidefactor * eigenvalues[i]);
1188 }
1189 else
1190 {
1191 /* compute coefficients of w and compute w at zlp */
1192 for( j = 0; j < nquadexprs; ++j )
1193 wcoefs[j] += vdotb * eigenvectors[offset + j];
1194
1195 *wzlp += vdotb * vdotzlp;
1196 }
1197 }
1198
1199 /* finish kappa computation */
1200 *kappa *= -0.25;
1201 *kappa += constant;
1202
1203 if( SCIPisZero(scip, *kappa) )
1204 *kappa = 0.0;
1205
1206 /* finish w(zlp) computation: linear part (including auxvar, if applicable) */
1207 for( i = 0; i < nlinexprs; ++i )
1208 {
1209 *wzlp += (sidefactor * lincoefs[i]) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
1210 }
1211 if( auxvar != NULL )
1212 {
1213 *wzlp += (sidefactor * -1.0) * SCIPgetSolVal(scip, sol, auxvar);
1214 }
1215
1216#ifdef DEBUG_INTERSECTIONCUT
1217 SCIPinfoMessage(scip, NULL, "Computed common quantities needed for intercuts:\n");
1218 SCIPinfoMessage(scip, NULL, " kappa = %g\n quad part w = ", *kappa);
1219 for( i = 0; i < nquadexprs; ++i )
1220 {
1221 SCIPinfoMessage(scip, NULL, "%g ", wcoefs[i]);
1222 }
1223 SCIPinfoMessage(scip, NULL, "\n");
1224#endif
1225 return SCIP_OKAY;
1226}
1227
1228/** computes eigenvec^T ray */
1229static
1231 SCIP_Real* eigenvec, /**< eigenvector */
1232 int nquadvars, /**< number of quadratic vars (length of eigenvec) */
1233 SCIP_Real* raycoefs, /**< coefficients of ray */
1234 int* rayidx, /**< index of consvar the ray coef is associated to */
1235 int raynnonz /**< length of raycoefs and rayidx */
1236 )
1237{
1238 SCIP_Real retval;
1239 int i;
1240
1241 retval = 0.0;
1242 for( i = 0; i < raynnonz; ++i )
1243 {
1244 /* rays are sorted; the first entries correspond to the quad vars, so we stop after first nonquad var entry */
1245 if( rayidx[i] >= nquadvars )
1246 break;
1247
1248 retval += eigenvec[rayidx[i]] * raycoefs[i];
1249 }
1250
1251 return retval;
1252}
1253
1254/** computes linear part of evaluation of w(ray): \f$b_l^T ray_l - ray_a\f$
1255 *
1256 * @note we can know whether the auxiliary variable appears by the entries of the ray
1257 */
1258static
1260 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1261 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1262 SCIP_Real* raycoefs, /**< coefficients of ray */
1263 int* rayidx, /**< ray coef[i] affects var at pos rayidx[i] in consvar */
1264 int raynnonz /**< length of raycoefs and rayidx */
1265 )
1266{
1267 SCIP_EXPR* qexpr;
1268 SCIP_Real* lincoefs;
1269 SCIP_Real retval;
1270 int nquadexprs;
1271 int nlinexprs;
1272
1273 int i;
1274 int start;
1275
1276#ifdef INTERCUT_MOREDEBUG
1277 printf("Computing w(ray) \n");
1278#endif
1279 retval = 0.0;
1280 start = raynnonz - 1;
1281
1282 qexpr = nlhdlrexprdata->qexpr;
1283 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, NULL, &lincoefs, &nquadexprs, NULL, NULL, NULL);
1284
1285 /* process ray entry associated to the auxvar if it applies */
1286 if( rayidx[raynnonz - 1] == nquadexprs + nlinexprs )
1287 {
1288#ifdef INTERCUT_MOREDEBUG
1289 printf("wray auxvar term %g \n", (sidefactor * -1.0) * raycoefs[raynnonz - 1]);
1290#endif
1291 retval += (sidefactor * -1.0) * raycoefs[raynnonz - 1];
1292 start--;
1293 }
1294
1295 /* process the rest of the entries */
1296 for( i = start; i >= 0; --i )
1297 {
1298 /* rays are sorted; last entries correspond to the lin vars, so we stop after first quad var entry */
1299 if( rayidx[i] < nquadexprs )
1300 break;
1301
1302#ifdef INTERCUT_MOREDEBUG
1303 printf("wray var in pos %d term %g:: lincoef %g raycoef %g\n", rayidx[i], (sidefactor *
1304 lincoefs[rayidx[i] - nquadexprs]) * raycoefs[i], lincoefs[rayidx[i] - nquadexprs] ,raycoefs[i]);
1305#endif
1306 retval += (sidefactor * lincoefs[rayidx[i] - nquadexprs]) * raycoefs[i] ;
1307 }
1308
1309 return retval;
1310}
1311
1312/** computes the dot product of v_i and the current ray as well as of v_i and the apex where v_i
1313 * is the i-th eigenvalue
1314 */
1315static
1317 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1318 SCIP_Real* apex, /**< array containing the apex of the S-free set in the original space */
1319 SCIP_Real* raycoefs, /**< coefficients of ray */
1320 int* rayidx, /**< index of consvar the ray coef is associated to */
1321 int raynnonz, /**< length of raycoefs and rayidx */
1322 SCIP_Real* vapex, /**< array to store \f$v_i^T apex\f$ */
1323 SCIP_Real* vray /**< array to store \f$v_i^T ray\f$ */
1324 )
1325{
1326 SCIP_EXPR* qexpr;
1327 int nquadexprs;
1328 SCIP_Real* eigenvectors;
1329 SCIP_Real* eigenvalues;
1330 int i;
1331
1332 qexpr = nlhdlrexprdata->qexpr;
1333 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
1334
1335 for( i = 0; i < nquadexprs; ++i )
1336 {
1337 SCIP_Real vdotapex;
1338 SCIP_Real vdotray;
1339 int offset;
1340 int j;
1341 int k;
1342
1343 offset = i * nquadexprs;
1344
1345 /* compute v_i^T apex and v_i^T ray */
1346 vdotapex = 0.0;
1347 vdotray = 0.0;
1348 k = 0;
1349 for( j = 0; j < nquadexprs; ++j )
1350 {
1351 SCIP_Real rayentry;
1352
1353 /* get entry of ray -> check if current var index corresponds to a non-zero entry in ray */
1354 if( k < raynnonz && j == rayidx[k] )
1355 {
1356 rayentry = raycoefs[k];
1357 ++k;
1358 }
1359 else
1360 rayentry = 0.0;
1361
1362 vdotray += rayentry * eigenvectors[offset + j];
1363 vdotapex += apex[j] * eigenvectors[offset + j];
1364 }
1365
1366 vray[i] = vdotray;
1367 vapex[i] = vdotapex;
1368 }
1369}
1370
1371/** calculate coefficients of restriction of the function to given ray.
1372 *
1373 * The restriction of the function representing the maximal S-free set to zlp + t * ray has the form
1374 * sqrt(A t^2 + B t + C) - (D t + E) for cases 1, 2, and 3.
1375 * For case 4 it is a piecewise defined function and each piece is of the aforementioned form.
1376 *
1377 * This function computes the coefficients A, B, C, D, E for the given ray.
1378 * In case 4, it computes the coefficients for both pieces, in addition to coefficients needed to evaluate the condition
1379 * in the piecewise definition of the function.
1380 *
1381 * The parameter iscase4 tells the function if it is case 4 or not.
1382 */
1383static
1385 SCIP* scip, /**< SCIP data structure */
1386 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1387 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1388 SCIP_Real* raycoefs, /**< coefficients of ray */
1389 int* rayidx, /**< index of consvar the ray coef is associated to */
1390 int raynnonz, /**< length of raycoefs and rayidx */
1391 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1392 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1393 SCIP_Real kappa, /**< value of kappa */
1394 SCIP_Real* apex, /**< apex of C */
1395 SCIP_Real* coefs2, /**< buffer to store A, B, C, D, and E of case 2 */
1396 SCIP_Bool* success /**< did we successfully compute the coefficients? */
1397 )
1398{
1399 SCIP_EXPR* qexpr;
1400 int nquadexprs;
1401 SCIP_Real* eigenvectors;
1402 SCIP_Real* eigenvalues;
1403 SCIP_Real* a;
1404 SCIP_Real* b;
1405 SCIP_Real* c;
1406 SCIP_Real* d;
1407 SCIP_Real* e;
1408 SCIP_Real* vray;
1409 SCIP_Real* vapex;
1410 SCIP_Real norm;
1411 int i;
1412
1413 *success = TRUE;
1414
1415 qexpr = nlhdlrexprdata->qexpr;
1416 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
1417
1418#ifdef DEBUG_INTERSECTIONCUT
1419 SCIPinfoMessage(scip, NULL, "\n############################################\n");
1420 SCIPinfoMessage(scip, NULL, "Restricting to line:\n");
1421#endif
1422
1423 assert(coefs2 != NULL);
1424
1425 /* set all coefficients to zero */
1426 BMSclearMemoryArray(coefs2, 5);
1427
1428 /* compute v_i^T apex in vapex[i] and v_i^T ray in vray[i] */
1429 SCIP_CALL( SCIPallocBufferArray(scip, &vapex, nquadexprs) );
1430 SCIP_CALL( SCIPallocBufferArray(scip, &vray, nquadexprs) );
1431 computeVApexAndVRay(nlhdlrexprdata, apex, raycoefs, rayidx, raynnonz, vapex, vray);
1432
1433 a = coefs2;
1434 b = coefs2 + 1;
1435 c = coefs2 + 2;
1436 d = coefs2 + 3;
1437 e = coefs2 + 4;
1438
1439 norm = 0.0;
1440 for( i = 0; i < nquadexprs; ++i )
1441 {
1442 SCIP_Real dot;
1443 SCIP_Real eigval;
1444
1445 eigval = sidefactor * eigenvalues[i];
1446
1447 if( SCIPisZero(scip, eigval) )
1448 continue;
1449
1450 dot = vzlp[i] + vb[i] / (2.0 * eigval);
1451
1452 if( eigval > 0.0 )
1453 {
1454 *d += eigval * dot * (vzlp[i] - vapex[i]);
1455 *e += eigval * dot * (vray[i] + vapex[i] + vb[i] / (2.0 * eigval));
1456 norm += eigval * SQR(dot);
1457 }
1458 else
1459 {
1460 *a -= eigval * SQR(vzlp[i] - vapex[i]);
1461 *b -= eigval * (vzlp[i] - vapex[i]) * (vray[i] + vapex[i] + vb[i] / (2.0 * eigval));
1462 *c -= eigval * SQR(vray[i] + vapex[i] + vb[i] / (2.0 * eigval));
1463 }
1464 }
1465
1466 norm = sqrt(norm / kappa + 1.0);
1467 *a /= kappa;
1468 *b /= kappa;
1469 *c /= kappa;
1470 *d /= (kappa * norm);
1471 *e /= (kappa * norm);
1472 *e += 1.0 / norm;
1473
1474 /* In theory, the function at 0 must be negative. Because of bad numerics this might not always hold, so we abort
1475 * the generation of the cut in this case.
1476 */
1477 if( sqrt(*c) - *e >= 0 )
1478 {
1479 /* check if it's really a numerical problem */
1480 assert(sqrt(*c) > 10e+15 || *e > 10e+15 || sqrt(*c) - *e < 10e+9);
1481
1482 INTERLOG(printf("Bad numerics: phi(0) >= 0\n"); )
1483 *success = FALSE;
1484 goto TERMINATE;
1485 }
1486
1487#ifdef DEBUG_INTERSECTIONCUT
1488 SCIPinfoMessage(scip, NULL, "Restriction yields case 2: a,b,c,d,e %g %g %g %g %g\n", coefs1234a[0], coefs1234a[1], coefs1234a[2],
1489 coefs1234a[3], coefs1234a[4]);
1490#endif
1491
1492 /* some sanity check applicable to all cases */
1493 assert(*a >= 0); /* the function inside the root is convex */
1494 assert(*c >= 0); /* radicand at zero */
1495
1496TERMINATE:
1497 /* free memory */
1498 SCIPfreeBufferArray(scip, &vray);
1499 SCIPfreeBufferArray(scip, &vapex);
1500
1501 return SCIP_OKAY;
1502}
1503
1504/** calculate coefficients of restriction of the function to given ray.
1505 *
1506 * The restriction of the function representing the maximal S-free set to zlp + t * ray has the form
1507 * sqrt(A t^2 + B t + C) - (D t + E) for cases 1, 2, and 3.
1508 * For case 4 it is a piecewise defined function and each piece is of the aforementioned form.
1509 *
1510 * This function computes the coefficients A, B, C, D, E for the given ray.
1511 * In case 4, it computes the coefficients for both pieces, in addition to coefficients needed to evaluate the condition
1512 * in the piecewise definition of the function.
1513 *
1514 * The parameter iscase4 tells the function if it is case 4 or not.
1515 */
1516static
1518 SCIP* scip, /**< SCIP data structure */
1519 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1520 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1521 SCIP_Bool iscase4, /**< whether we are in case 4 */
1522 SCIP_Real* raycoefs, /**< coefficients of ray */
1523 int* rayidx, /**< index of consvar the ray coef is associated to */
1524 int raynnonz, /**< length of raycoefs and rayidx */
1525 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1526 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1527 SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
1528 SCIP_Real wzlp, /**< value of w at zlp */
1529 SCIP_Real kappa, /**< value of kappa */
1530 SCIP_Real* coefs1234a, /**< buffer to store A, B, C, D, and E of cases 1, 2, 3, or 4a */
1531 SCIP_Real* coefs4b, /**< buffer to store A, B, C, D, and E of case 4b (or NULL if not needed) */
1532 SCIP_Real* coefscondition, /**< buffer to store data to evaluate condition to decide case 4a or 4b */
1533 SCIP_Bool* success /**< did we successfully compute the coefficients? */
1534 )
1535{
1536 SCIP_EXPR* qexpr;
1537 int nquadexprs;
1538 SCIP_Real* eigenvectors;
1539 SCIP_Real* eigenvalues;
1540 SCIP_Real* a;
1541 SCIP_Real* b;
1542 SCIP_Real* c;
1543 SCIP_Real* d;
1544 SCIP_Real* e;
1545 SCIP_Real wray;
1546 int i;
1547
1548 *success = TRUE;
1549
1550 qexpr = nlhdlrexprdata->qexpr;
1551 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
1552
1553#ifdef DEBUG_INTERSECTIONCUT
1554 SCIPinfoMessage(scip, NULL, "\n############################################\n");
1555 SCIPinfoMessage(scip, NULL, "Restricting to ray:\n");
1556 for( i = 0; i < raynnonz; ++i )
1557 {
1558 SCIPinfoMessage(scip, NULL, "(%d, %g), ", rayidx[i], raycoefs[i]);
1559 }
1560 SCIPinfoMessage(scip, NULL, "\n");
1561#endif
1562
1563 assert(coefs1234a != NULL);
1564
1565 /* set all coefficients to zero */
1566 BMSclearMemoryArray(coefs1234a, 5);
1567 if( iscase4 )
1568 {
1569 assert(coefs4b != NULL);
1570 assert(coefscondition != NULL);
1571 assert(wcoefs != NULL);
1572
1573 BMSclearMemoryArray(coefs4b, 5);
1574 BMSclearMemoryArray(coefscondition, 3);
1575 }
1576
1577 a = coefs1234a;
1578 b = coefs1234a + 1;
1579 c = coefs1234a + 2;
1580 d = coefs1234a + 3;
1581 e = coefs1234a + 4;
1582 wray = 0;
1583
1584 for( i = 0; i < nquadexprs; ++i )
1585 {
1586 SCIP_Real dot = 0.0;
1587 SCIP_Real vdotray;
1588
1589 if( SCIPisZero(scip, eigenvalues[i]) )
1590 {
1591 if( wcoefs == NULL )
1592 continue;
1593 }
1594 else
1595 {
1596 dot = vzlp[i] + vb[i] / (2.0 * (sidefactor * eigenvalues[i]));
1597 }
1598 vdotray = computeEigenvecDotRay(&eigenvectors[i * nquadexprs], nquadexprs, raycoefs, rayidx, raynnonz);
1599
1600 if( SCIPisZero(scip, eigenvalues[i]) )
1601 {
1602 /* zero eigenvalue (and wcoefs not null) -> case 4: compute w(r) */
1603 assert(wcoefs != NULL);
1604 wray += vb[i] * vdotray;
1605#ifdef INTERCUT_MOREDEBUG
1606 printf(" wray += %g, vb[i] %g and vdotray %g\n", vb[i] * vdotray,vb[i],vdotray);
1607#endif
1608 }
1609 else if( sidefactor * eigenvalues[i] > 0 )
1610 {
1611 /* positive eigenvalue: compute common part of D and E */
1612 *d += (sidefactor * eigenvalues[i]) * dot * vdotray;
1613 *e += (sidefactor * eigenvalues[i]) * SQR( dot );
1614
1615#ifdef INTERCUT_MOREDEBUG
1616 printf("Positive eigenvalue: computing D: v^T ray %g, v^T( zlp + b/theta ) %g and theta %g \n", vdotray, dot, (sidefactor * eigenvalues[i]));
1617#endif
1618 }
1619 else
1620 {
1621 /* negative eigenvalue: compute common part of A, B, and C */
1622 *a -= (sidefactor * eigenvalues[i]) * SQR( vdotray );
1623 *b -= 2.0 * (sidefactor * eigenvalues[i]) * dot * vdotray;
1624 *c -= (sidefactor * eigenvalues[i]) * SQR( dot );
1625
1626#ifdef INTERCUT_MOREDEBUG
1627 printf("Negative eigenvalue: computing A: v^T ray %g, and theta %g \n", vdotray, (sidefactor * eigenvalues[i]));
1628#endif
1629 }
1630 }
1631
1632 if( ! iscase4 )
1633 {
1634 /* We are in one of the first 3 cases */
1635 *e += MAX(kappa, 0.0);
1636 *c -= MIN(kappa, 0.0);
1637
1638 /* finish computation of D and E */
1639 assert(*e > 0);
1640 *e = sqrt(*e);
1641 *d /= *e;
1642
1643 /* some sanity checks only applicable to these cases (more at the end) */
1644 assert(*c >= 0);
1645
1646 /* In theory, the function at 0 must be negative. Because of bad numerics this might not always hold, so we abort
1647 * the generation of the cut in this case.
1648 */
1649 if( sqrt(*c) - *e >= 0 )
1650 {
1651 /* check if it's really a numerical problem */
1652 assert(sqrt(*c) > 10e+15 || *e > 10e+15 || sqrt(*c) - *e < 10e+9);
1653
1654 INTERLOG(printf("Bad numerics: phi(0) >= 0\n"); )
1655 *success = FALSE;
1656 return SCIP_OKAY;
1657 }
1658 }
1659 else
1660 {
1661 SCIP_Real norm;
1662 SCIP_Real xextra;
1663 SCIP_Real yextra;
1664
1665 norm = sqrt(1.0 + SQR( kappa ));
1666 xextra = wzlp + kappa + norm;
1667 yextra = wzlp + kappa - norm;
1668
1669 /* finish computing w(ray), the linear part is missing */
1670 wray += computeWRayLinear(nlhdlrexprdata, sidefactor, raycoefs, rayidx, raynnonz);
1671
1672 /*
1673 * coefficients of case 4b
1674 */
1675 /* at this point E is \|x(zlp)\|^2, so we can finish A, B, and C */
1676 coefs4b[0] = (*a) * (*e);
1677 coefs4b[1] = (*b) * (*e);
1678 coefs4b[2] = (*c) * (*e);
1679
1680 /* finish D and E */
1681 coefs4b[3] = *d;
1682 coefs4b[4] = (*e) + xextra / 2.0;
1683
1684 /* when \|x(zlp)\|^2 is too large, we can divide everything by \|x(zlp)\| */
1685 if( *e > 100 )
1686 {
1687 coefs4b[0] = (*a);
1688 coefs4b[1] = (*b);
1689 coefs4b[2] = (*c);
1690
1691 /* finish D and E */
1692 coefs4b[3] = *d / sqrt(*e);
1693 coefs4b[4] = sqrt(*e) + (xextra / (2.0 * sqrt(*e)));
1694 }
1695
1696 /*
1697 * coefficients of case 4a
1698 */
1699 /* finish A, B, and C */
1700 *a += SQR( wray ) / (4.0 * norm);
1701 *b += 2.0 * yextra * (wray) / (4.0 * norm);
1702 *c += SQR( yextra ) / (4.0 * norm);
1703
1704 /* finish D and E */
1705 *e += SQR( xextra ) / (4.0 * norm);
1706 *e = sqrt(*e);
1707
1708 *d += xextra * (wray) / (4.0 * norm);
1709 *d /= *e;
1710
1711 /*
1712 * coefficients of condition: stores -numerator of x_{r+1}/ norm xhat, w(ray), and numerator of y_{s+1} at zlp
1713 *
1714 */
1715 /* at this point E is \| \hat{x} (zlp)\| */
1716 coefscondition[0] = - xextra / (*e);
1717 coefscondition[1] = wray;
1718 coefscondition[2] = yextra;
1719 }
1720
1721#ifdef DEBUG_INTERSECTIONCUT
1722 if( ! iscase4 )
1723 {
1724 SCIPinfoMessage(scip, NULL, "Restriction yields case 1,2 or 3: a,b,c,d,e %g %g %g %g %g\n", coefs1234a[0], coefs1234a[1], coefs1234a[2],
1725 coefs1234a[3], coefs1234a[4]);
1726 }
1727 else
1728 {
1729 SCIPinfoMessage(scip, NULL, "Restriction yields\n Case 4a: a,b,c,d,e %g %g %g %g %g\n", coefs1234a[0],
1730 coefs1234a[1], coefs1234a[2], coefs1234a[3], coefs1234a[4]);
1731 SCIPinfoMessage(scip, NULL, " Case 4b: a,b,c,d,e %g %g %g %g %g\n", coefs4b[0], coefs4b[1], coefs4b[2],
1732 coefs4b[3], coefs4b[4]);
1733 SCIPinfoMessage(scip, NULL, " Condition: xextra/e, wray, yextra %g %g %g g\n", coefscondition[0],
1734 coefscondition[1], coefscondition[2]);
1735 }
1736#endif
1737
1738 /* some sanity check applicable to all cases */
1739 assert(*a >= 0); /* the function inside the root is convex */
1740 assert(*c >= 0); /* radicand at zero */
1741
1742 if( iscase4 )
1743 {
1744 assert(coefs4b[0] >= 0); /* the function inside the root is convex */
1745 assert(coefs4b[2] >= 0); /* radicand at zero */
1746 }
1747 /*assert(4.0 * (*a) * (*c) >= SQR( *b ) ); *//* the function is defined everywhere, so minimum of radicand must be nonnegative */
1748
1749 return SCIP_OKAY;
1750}
1751
1752/** returns phi(zlp + t * ray) = sqrt(A t^2 + B t + C) - (D t + E) */
1753static
1755 SCIP_Real t, /**< argument of phi restricted to ray */
1756 SCIP_Real a, /**< value of A */
1757 SCIP_Real b, /**< value of B */
1758 SCIP_Real c, /**< value of C */
1759 SCIP_Real d, /**< value of D */
1760 SCIP_Real e /**< value of E */
1761 )
1762{
1763#ifdef INTERCUTS_DBLDBL
1764 SCIP_Real QUAD(lin);
1765 SCIP_Real QUAD(disc);
1766 SCIP_Real QUAD(tmp);
1767 SCIP_Real QUAD(root);
1768
1769 /* d * t + e */
1770 SCIPquadprecProdDD(lin, d, t);
1771 SCIPquadprecSumQD(lin, lin, e);
1772
1773 /* a * t * t */
1774 SCIPquadprecSquareD(disc, t);
1775 SCIPquadprecProdQD(disc, disc, a);
1776
1777 /* b * t */
1778 SCIPquadprecProdDD(tmp, b, t);
1779
1780 /* a * t * t + b * t */
1781 SCIPquadprecSumQQ(disc, disc, tmp);
1782
1783 /* a * t * t + b * t + c */
1784 SCIPquadprecSumQD(disc, disc, c);
1785
1786 /* sqrt(above): can't take sqrt of 0! */
1787 if( QUAD_TO_DBL(disc) == 0 )
1788 {
1789 QUAD_ASSIGN(root, 0.0);
1790 }
1791 else
1792 {
1793 SCIPquadprecSqrtQ(root, disc);
1794 }
1795
1796 /* final result */
1797 QUAD_SCALE(lin, -1.0);
1798 SCIPquadprecSumQQ(tmp, root, lin);
1799
1800 assert(t != 1e20 || QUAD_TO_DBL(tmp) <= 0);
1801
1802 return QUAD_TO_DBL(tmp);
1803#else
1804 return sqrt(a * t * t + b * t + c) - ( d * t + e );
1805#endif
1806}
1807
1808/** checks whether case 4a applies
1809 *
1810 * The condition for being in case 4a is
1811 * \f[ -\lambda_{r+1} \Vert \hat y(zlp + tsol\, ray)\Vert + \hat y_{s+1}(zlp + tsol\, ray) \leq 0\f]
1812 *
1813 * This reduces to
1814 * \f[ -num(\hat x_{r+1}(zlp)) \sqrt{A t^2 + B t + C} / E + w(ray) \cdot t + num(\hat y_{s+1}(zlp)) \leq 0\f]
1815 * where num is the numerator.
1816 */
1817static
1819 SCIP_Real tsol, /**< t in the above formula */
1820 SCIP_Real* coefs4a, /**< coefficients A, B, C, D, and E of case 4a */
1821 SCIP_Real* coefscondition /**< extra coefficients needed for the evaluation of the condition:
1822 * \f$num(\hat x_{r+1}(zlp)) / E\f$; \f$w(ray)\f$; \f$num(\hat y_{s+1}(zlp))\f$ */
1823 )
1824{
1825 return (coefscondition[0] * sqrt(coefs4a[0] * SQR( tsol ) + coefs4a[1] * tsol + coefs4a[2]) + coefscondition[1] *
1826 tsol + coefscondition[2]) <= 0.0;
1827}
1828
1829/** helper function of computeRoot: we want phi to be &le; 0 */
1830static
1832 SCIP* scip, /**< SCIP data structure */
1833 SCIP_Real a, /**< value of A */
1834 SCIP_Real b, /**< value of B */
1835 SCIP_Real c, /**< value of C */
1836 SCIP_Real d, /**< value of D */
1837 SCIP_Real e, /**< value of E */
1838 SCIP_Real* sol /**< buffer to store solution; also gives initial point */
1839 )
1840{
1841 SCIP_Real lb = 0.0;
1842 SCIP_Real ub = *sol;
1843 SCIP_Real curr;
1844 int i;
1845
1846 for( i = 0; i < BINSEARCH_MAXITERS; ++i )
1847 {
1848 SCIP_Real phival;
1849
1850 curr = (lb + ub) / 2.0;
1851 phival = evalPhiAtRay(curr, a, b, c, d, e);
1852#ifdef INTERCUT_MOREDEBUG
1853 printf("%d: lb,ub %.10f, %.10f. curr = %g -> phi at curr %g -> phi at lb %g \n", i, lb, ub, curr, phival, evalPhiAtRay(lb, a, b, c, d, e));
1854#endif
1855
1856 if( phival <= 0.0 )
1857 {
1858 lb = curr;
1859 if( SCIPisFeasZero(scip, phival) || SCIPisFeasEQ(scip, ub, lb) )
1860 break;
1861 }
1862 else
1863 ub = curr;
1864 }
1865
1866 *sol = lb;
1867}
1868
1869/** finds smallest positive root phi by finding the smallest positive root of
1870 * (A - D^2) t^2 + (B - 2 D*E) t + (C - E^2) = 0
1871 *
1872 * However, we are conservative and want a solution such that phi is negative, but close to 0.
1873 * Thus, we correct the result with a binary search.
1874 */
1875static
1877 SCIP* scip, /**< SCIP data structure */
1878 SCIP_Real* coefs /**< value of A */
1879 )
1880{
1881 SCIP_Real sol;
1882 SCIP_INTERVAL bounds;
1883 SCIP_INTERVAL result;
1884 SCIP_Real a = coefs[0];
1885 SCIP_Real b = coefs[1];
1886 SCIP_Real c = coefs[2];
1887 SCIP_Real d = coefs[3];
1888 SCIP_Real e = coefs[4];
1889
1890 /* there is an intersection point if and only if sqrt(A) > D: here we are beliving in math, this might cause
1891 * numerical issues
1892 */
1893 if( sqrt(a) <= d )
1894 {
1895 sol = SCIPinfinity(scip);
1896 return sol;
1897 }
1898
1899 SCIPintervalSetBounds(&bounds, 0.0, SCIPinfinity(scip));
1900
1901 /* SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar finds all x such that a x^2 + b x >= c and x in bounds.
1902 * it is known that if tsol is the root we are looking for, then gamma(zlp + t * ray) <= 0 between 0 and tsol, thus
1903 * tsol is the smallest t such that (A - D^2) t^2 + (B - 2 D*E) t + (C - E^2) >= 0
1904 */
1906 e, -(c - e * e), bounds);
1907
1908 /* it can still be empty because of our infinity, I guess... */
1910
1911#ifdef INTERCUT_MOREDEBUG
1912 {
1913 SCIP_Real binsol;
1914 binsol = SCIPinfinity(scip);
1915 doBinarySearch(scip, a, b, c, d, e, &binsol);
1916 printf("got root %g: with binsearch get %g\n", sol, binsol);
1917 }
1918#endif
1919
1920 /* check that solution is acceptable, ideally it should be <= 0, however when it is positive, we trigger a binary
1921 * search to make it negative. This binary search might return a solution point that is not at accurately 0 as the
1922 * one obtained from the function above. Thus, it might fail to satisfy the condition of case 4b in some cases, e.g.,
1923 * ex8_3_1, bchoco05, etc
1924 */
1925 if( evalPhiAtRay(sol, a, b, c, d, e) <= 1e-10 )
1926 {
1927#ifdef INTERCUT_MOREDEBUG
1928 printf("interval solution returned %g -> phival = %g, believe it\n", sol, evalPhiAtRay(sol, a, b, c, d, e));
1929 printf("don't do bin search\n");
1930#endif
1931 return sol;
1932 }
1933 else
1934 {
1935 /* perform a binary search to make it negative: this might correct a wrong infinity (e.g. crudeoil_lee1_05) */
1936#ifdef INTERCUT_MOREDEBUG
1937 printf("do bin search because phival is %g\n", evalPhiAtRay(sol, a, b, c, d, e));
1938#endif
1939 doBinarySearch(scip, a, b, c, d, e, &sol);
1940 }
1941
1942 return sol;
1943}
1944
1945/** The maximal S-free set is \f$\gamma(z) \leq 0\f$; we find the intersection point of the ray `ray` starting from zlp with the
1946 * boundary of the S-free set.
1947 * That is, we find \f$t \geq 0\f$ such that \f$\gamma(zlp + t \cdot \text{ray}) = 0\f$.
1948 *
1949 * In cases 1,2, and 3, gamma is of the form
1950 * \f[ \gamma(zlp + t \cdot \text{ray}) = \sqrt{A t^2 + B t + C} - (D t + E) \f]
1951 *
1952 * In the case 4 gamma is of the form
1953 * \f[ \gamma(zlp + t \cdot \text{ray}) =
1954 * \begin{cases}
1955 * \sqrt{A t^2 + B t + C} - (D t + E), & \text{if some condition holds}, \\
1956 * \sqrt{A' t^2 + B' t + C'} - (D' t + E'), & \text{otherwise.}
1957 * \end{cases}
1958 * \f]
1959 *
1960 * It can be shown (given the special properties of \f$\gamma\f$) that the smallest positive root of each function of the form
1961 * \f$\sqrt{a t^2 + b t + c} - (d t + e)\f$
1962 * is the same as the smallest positive root of the quadratic equation:
1963 * \f{align}{
1964 * & \sqrt{a t^2 + b t + c} - (d t + e)) (\sqrt{a t^2 + b t + c} + (d t + e)) = 0 \\ \Leftrightarrow
1965 * & (a - d^2) t^2 + (b - 2 d\,e) t + (c - e^2) = 0
1966 * \f}
1967 *
1968 * So, in cases 1, 2, and 3, this function just returns the solution of the above equation.
1969 * In case 4, it first solves the equation assuming we are in the first piece.
1970 * If there is no solution, then the second piece can't have a solution (first piece &ge; second piece for all t)
1971 * Then we check if the solution satisfies the condition.
1972 * If it doesn't then we solve the equation for the second piece.
1973 * If it has a solution, then it _has_ to be the solution.
1974 */
1975static
1977 SCIP* scip, /**< SCIP data structure */
1978 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
1979 SCIP_Bool iscase4, /**< whether we are in case 4 or not */
1980 SCIP_Real* coefs1234a, /**< values of A, B, C, D, and E of cases 1, 2, 3, or 4a */
1981 SCIP_Real* coefs4b, /**< values of A, B, C, D, and E of case 4b */
1982 SCIP_Real* coefscondition /**< values needed to evaluate condition of case 4 */
1983 )
1984{
1985 SCIP_Real sol1234a;
1986 SCIP_Real sol4b;
1987
1988 assert(coefs1234a != NULL);
1989
1990#ifdef DEBUG_INTERSECTIONCUT
1991 SCIPinfoMessage(scip, NULL, "Computing intersection point for case 4? %d\n", iscase4);
1992#endif
1993 if( ! iscase4 )
1994 return computeRoot(scip, coefs1234a);
1995
1996 assert(coefs4b != NULL);
1997 assert(coefscondition != NULL);
1998
1999 /* compute solution of first piece */
2000#ifdef DEBUG_INTERSECTIONCUT
2001 SCIPinfoMessage(scip, NULL, "Compute root in 4a\n");
2002#endif
2003 sol1234a = computeRoot(scip, coefs1234a);
2004
2005 /* if there is no solution --> second piece doesn't have solution */
2006 if( SCIPisInfinity(scip, sol1234a) )
2007 {
2008 /* this assert fails on multiplants_mtg5 the problem is that sqrt(A) <= D in 4a but not in 4b,
2009 * now, this is impossible since the phi4a >= phi4b, so actually sqrt(A) is 10e-15 away from
2010 * D in 4b
2011 */
2012 /* assert(SCIPisInfinity(scip, computeRoot(scip, coefs4b))); */
2013 return sol1234a;
2014 }
2015
2016 /* if solution of 4a is in 4a, then return */
2017 if( isCase4a(sol1234a, coefs1234a, coefscondition) )
2018 return sol1234a;
2019
2020#ifdef DEBUG_INTERSECTIONCUT
2021 SCIPinfoMessage(scip, NULL, "Root not in 4a -> Compute root in 4b\n");
2022#endif
2023
2024 /* not on 4a --> then the intersection point is whatever 4b says: as phi4a >= phi4b, the solution of phi4b should
2025 * always be larger (but shouldn't be equal at this point given that isCase4a failed, and the condition function
2026 * evaluates to 0 when phi4a == phi4b) than the solution of phi4a; However, because of numerics (or limits in the
2027 * binary search) we can find a slightly smaller solution; thus, we just keep the larger one
2028 */
2029 sol4b = computeRoot(scip, coefs4b);
2030
2031 /* this assert fails in many instances, e.g. water, because sol4b < sol1234a */
2032 /* assert(SCIPisInfinity(scip, sol4b) || !isCase4a(sol4b, coefs1234a, coefscondition)); */
2033 /* count number of times we could have improved the coefficient by 10% */
2034 if( sol4b < sol1234a && evalPhiAtRay(1.1 * sol1234a, coefs4b[0], coefs4b[1], coefs4b[2], coefs4b[3], coefs4b[4]) <=
2035 0.0 )
2036 nlhdlrdata->ncouldimprovedcoef++;
2037
2038 return MAX(sol1234a, sol4b);
2039}
2040
2041/** checks if numerics of the coefficients are not too bad */
2042static
2044 SCIP* scip, /**< SCIP data structure */
2045 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2046 SCIP_Real* coefs1234a, /**< coefficients for case 1-3 and 4a */
2047 SCIP_Real* coefs4b, /**< coefficients for case 4b */
2048 SCIP_Bool iscase4 /**< whether we are in case 4 */
2049 )
2050{
2051 SCIP_Real max;
2052 SCIP_Real min;
2053 int j;
2054
2055 /* check at phi at 0 is negative (note; this could be checked before restricting to the ray) also, if this
2056 * succeeds for one ray, it should suceed for every ray
2057 */
2058 if( sqrt(coefs1234a[2]) - coefs1234a[4] >= 0.0 )
2059 {
2060 INTERLOG(printf("Bad numerics: phi(0) >= 0\n"); )
2061 nlhdlrdata->nphinonneg++;
2062 return FALSE;
2063 }
2064
2065 /* maybe we want to avoid a large dynamism between A, B and C */
2066 if( nlhdlrdata->ignorebadrayrestriction )
2067 {
2068 max = 0.0;
2070 for( j = 0; j < 3; ++j )
2071 {
2072 SCIP_Real absval;
2073
2074 absval = REALABS(coefs1234a[j]);
2075 if( max < absval )
2076 max = absval;
2077 if( absval != 0.0 && absval < min )
2078 min = absval;
2079 }
2080
2081 if( SCIPisHugeValue(scip, max / min) )
2082 {
2083 INTERLOG(printf("Bad numerics 1 2 3 or 4a: max(A,B,C)/min(A,B,C) is too large (%g)\n", max / min); )
2084 nlhdlrdata->nbadrayrestriction++;
2085 return FALSE;
2086 }
2087
2088 if( iscase4 )
2089 {
2090 max = 0.0;
2092 assert(coefs4b != NULL);
2093 for( j = 0; j < 3; ++j )
2094 {
2095 SCIP_Real absval;
2096
2097 absval = ABS(coefs4b[j]);
2098 if( max < absval )
2099 max = absval;
2100 if( absval != 0.0 && absval < min )
2101 min = absval;
2102 }
2103
2104 if( SCIPisHugeValue(scip, max / min) )
2105 {
2106 INTERLOG(printf("Bad numeric 4b: max(A,B,C)/min(A,B,C) is too large (%g)\n", max / min); )
2107 nlhdlrdata->nbadrayrestriction++;
2108 return FALSE;
2109 }
2110 }
2111 }
2112
2113 return TRUE;
2114}
2115
2116
2117/** computes the coefficients a, b, c defining the quadratic function defining set S restricted to the line
2118 * theta * apex.
2119 *
2120 * The solution to the monoidal strengthening problem is then given by the smallest root of the function
2121 * a * theta^2 + b * theta + c
2122 */
2123static
2125 SCIP* scip, /**< SCIP data structure */
2126 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2127 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2128 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2129 SCIP_Real* vapex, /**< array containing \f$v_i^T apex\f$ */
2130 SCIP_Real* vray, /**< array containing \f$v_i^T ray\f$ */
2131 SCIP_Real kappa, /**< value of kappa */
2132 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2133 SCIP_Real* a, /**< pointer to store quadratic coefficient */
2134 SCIP_Real* b, /**< pointer to store linear coefficient */
2135 SCIP_Real* c /**< pointer to store constant */
2136 )
2137{
2138 SCIP_EXPR* qexpr;
2139 int nquadexprs;
2140 SCIP_Real* eigenvectors;
2141 SCIP_Real* eigenvalues;
2142 int i;
2143
2144 qexpr = nlhdlrexprdata->qexpr;
2145 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
2146
2147 *a = 0.0;
2148 *b = 0.0;
2149 *c = 0.0;
2150 for( i = 0; i < nquadexprs; ++i )
2151 {
2152 SCIP_Real dot;
2153
2154 if( SCIPisZero(scip, sidefactor * eigenvalues[i]) )
2155 continue;
2156
2157 dot = vray[i] + vapex[i] + vb[i] / (2.0 * sidefactor * eigenvalues[i]);
2158
2159 *a += sidefactor * eigenvalues[i] * SQR(vzlp[i] - vapex[i]);
2160 *b += sidefactor * eigenvalues[i] * (vzlp[i] - vapex[i]) * dot;
2161 *c += sidefactor * eigenvalues[i] * SQR(dot);
2162 }
2163
2164 *b *= 2.0;
2165 *c += kappa;
2166
2167 return SCIP_OKAY;
2168}
2169
2170/** check if ray was in strip by checking if the point in the monoid corresponding to the cutcoef we just found
2171 * is "on the wrong side" of the hyperplane -(a - lambda^Ta lambda)^T x
2172 */
2173static
2175 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2176 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2177 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2178 SCIP_Real* vapex, /**< array containing \f$v_i^T apex\f$ */
2179 SCIP_Real* vray, /**< array containing \f$v_i^T ray\f$ */
2180 SCIP_Real kappa, /**< value of kappa */
2181 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2182 SCIP_Real cutcoef /**< optimal solution of the monoidal quadratic */
2183 )
2184{
2185 SCIP_EXPR* qexpr;
2186 int nquadexprs;
2187 SCIP_Real* eigenvectors;
2188 SCIP_Real* eigenvalues;
2189 SCIP_Real num;
2190 SCIP_Real denom;
2191 int i;
2192
2193 qexpr = nlhdlrexprdata->qexpr;
2194 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
2195
2196 num = 0.0;
2197 denom = 0.0;
2198 for( i = 0; i < nquadexprs; ++i )
2199 {
2200 SCIP_Real dot;
2201
2202 if( sidefactor * eigenvalues[i] <= 0.0 )
2203 continue;
2204
2205 dot = vzlp[i] + vb[i] / (2.0 * sidefactor * eigenvalues[i]);
2206
2207 num += sidefactor * eigenvalues[i] * dot * (cutcoef * (vzlp[i] - vapex[i]) + vray[i] + vapex[i]);
2208 denom += sidefactor * eigenvalues[i] * SQR(dot);
2209 }
2210
2211 num /= kappa;
2212 num += 1.0;
2213 denom /= kappa;
2214 denom += 1.0;
2215
2216 assert(denom > 0);
2217
2218 return num / denom < 1;
2219}
2220
2221/** computes the smallest root of the quadratic function a*x^2 + b*x + c with a > 0
2222 * and b^2 - 4ac >= 0. We use binary search between -inf and minimum at -b/2a.
2223 */
2224static
2226 SCIP* scip, /**< SCIP data structure */
2227 SCIP_Real a, /**< quadratic coefficient */
2228 SCIP_Real b, /**< linear coefficient */
2229 SCIP_Real c /**< constant */
2230 )
2231{
2232 SCIP_Real sol;
2233 SCIP_INTERVAL bounds;
2234 SCIP_INTERVAL result;
2235
2236 assert(SQR(b) - 4 * a * c >= 0.0);
2237
2238 if( SCIPisZero(scip, a) )
2239 {
2240 assert(b != 0.0);
2241 sol = - c / b;
2242 }
2243 else
2244 {
2245 SCIPintervalSetBounds(&bounds, - b / (2.0 * a), SCIPinfinity(scip));
2246
2247 /* find all positive x such that a x^2 + b x >= -c and x in bounds.*/
2250
2251 /* if we didn't find any positive solutions, negate quadratic and find negative solutions */
2252 if( SCIPisInfinity(scip, sol) )
2253 {
2254 SCIPintervalSetBounds(&bounds, b / (2.0 * a), SCIPinfinity(scip));
2255
2256 /* find all positive x such that a x^2 - b x >= -c and x in bounds.*/
2259 }
2260 }
2261
2262 /* check if that solution is close enough or if we need to improve it more with binary search */
2263 if( a * SQR(sol) + sol * b + c > 1e-10 )
2264 {
2265 SCIP_Real val;
2266 SCIP_Real lb;
2267 SCIP_Real ub;
2268 SCIP_Real lastposval;
2269 SCIP_Real lastpossol;
2270 int niter;
2271
2272 lb = - b / (2.0 * a);
2273 ub = sol;
2274 lastposval = SCIPinfinity(scip);
2275 lastpossol = SCIPinfinity(scip);
2276 val = SCIPinfinity(scip);
2277 niter = 0;
2278 while( niter < BINSEARCH_MAXITERS && ABS(val) > 1e-10 )
2279 {
2280 sol = (ub + lb) / 2.0;
2281 val = a * SQR(sol) + b * sol + c;
2282
2283 if( val < 0.0 )
2284 lb = sol;
2285 else
2286 ub = sol;
2287
2288 /* if we are close enough, return with (feasible) solution */
2289 if( val > 0.0 && val < 1e-6 )
2290 break;
2291
2292 if( val > 0.0 && lastposval > val )
2293 {
2294 lastposval = val;
2295 lastpossol = sol;
2296 }
2297
2298 ++niter;
2299 }
2300 if( val < 0.0 && ! SCIPisZero(scip, val) )
2301 {
2302 sol = lastpossol;
2303 val = lastposval;
2304 }
2305
2306 assert( val > 0.0 || SCIPisZero(scip, val) );
2307 }
2308
2309 return sol;
2310}
2311
2312/** computes the apex of the S-free set (if it exists) */
2313static
2315 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2316 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2317 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2318 SCIP_Real kappa, /**< value of kappa */
2319 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2320 SCIP_Real* apex, /**< array to store apex */
2321 SCIP_Bool* success /**< TRUE if computation of apex was successful */
2322 )
2323{
2324 SCIP_EXPR* qexpr;
2325 int nquadexprs;
2326 SCIP_Real* eigenvectors;
2327 SCIP_Real* eigenvalues;
2328 int i;
2329
2330 qexpr = nlhdlrexprdata->qexpr;
2331 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
2332
2333 *success = TRUE;
2334
2335 for( i = 0; i < nquadexprs; ++i )
2336 {
2337 SCIP_Real entry;
2338 SCIP_Real denom;
2339 SCIP_Real num;
2340 int j;
2341
2342 entry = 0.0;
2343 num = 0.0;
2344 denom = 0.0;
2345 for( j = 0; j < nquadexprs; ++j )
2346 {
2347 if( sidefactor * eigenvalues[j] == 0.0 )
2348 continue;
2349
2350 entry -= eigenvectors[j * nquadexprs + i] * vb[j] / (2.0 * sidefactor * eigenvalues[j]);
2351
2352 if( sidefactor * eigenvalues[j] > 0.0 )
2353 {
2354 SCIP_Real dot;
2355
2356 dot = vzlp[j] + vb[j] / (2.0 * sidefactor * eigenvalues[j]);
2357
2358 num += eigenvectors[j * nquadexprs + i] * dot;
2359 denom += sidefactor * eigenvalues[j] * SQR(dot);
2360 }
2361 }
2362
2363 /* if denom = 0, the S-free set is just the strip, so we don't have an apex -> monoidal not possible */
2364 if( denom == 0.0 )
2365 {
2366 *success = FALSE;
2367 return;
2368 }
2369 assert(denom > 0.0);
2370
2371 num *= -kappa;
2372 entry += num / denom;
2373
2374 apex[i] = entry;
2375 }
2376}
2377
2378/** for a given ray, computes the cut coefficient using monoidal strengthening (if possible) */
2379static
2381 SCIP* scip, /**< SCIP data structure */
2382 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2383 int lppos, /**< lp pos of current ray */
2384 SCIP_Real* raycoefs, /**< coefficients of ray */
2385 int* rayidx, /**< index of consvar the ray coef is associated to */
2386 int raynnonz, /**< length of raycoefs and rayidx */
2387 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2388 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2389 SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
2390 SCIP_Real kappa, /**< value of kappa */
2391 SCIP_Real* apex, /**< array containing the apex of the S-free set in the original space */
2392 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2393 SCIP_Real* cutcoef, /**< pointer to store cut coef */
2394 SCIP_Bool* success /**< TRUE if monoidal strengthening could be applied */
2395 )
2396{
2397 SCIP_COL** cols;
2398 SCIP_ROW** rows;
2399
2400 *success = FALSE;
2401
2402 /* check if we are in the correct case (case 2) */
2403 assert(wcoefs == NULL && kappa > 0.0);
2404
2405 cols = SCIPgetLPCols(scip);
2406 rows = SCIPgetLPRows(scip);
2407
2408 /* if var corresponding to current ray is integer, we can do monoidal */
2409 if( ( lppos >= 0 && SCIPvarIsIntegral(SCIPcolGetVar(cols[lppos])) ) ||
2410 ( lppos < 0 && SCIProwIsIntegral(rows[- lppos - 1]) ) )
2411 {
2412 SCIP_Real* vapex;
2413 SCIP_Real* vray;
2414 SCIP_Real a;
2415 SCIP_Real b;
2416 SCIP_Real c;
2417 int nquadexprs;
2418
2419 SCIPexprGetQuadraticData(nlhdlrexprdata->qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
2420
2421 /* compute v_i^T apex in vapex[i] and v_i^T ray in vray[i] */
2422 SCIP_CALL( SCIPallocBufferArray(scip, &vapex, nquadexprs) );
2423 SCIP_CALL( SCIPallocBufferArray(scip, &vray, nquadexprs) );
2424 computeVApexAndVRay(nlhdlrexprdata, apex, raycoefs, rayidx, raynnonz, vapex, vray);
2425
2426 /* compute coefficients of the quadratic monoidal problem function */
2427 SCIP_CALL( computeMonoidalQuadCoefs(scip, nlhdlrexprdata, vb, vzlp, vapex, vray, kappa,
2428 sidefactor, &a, &b, &c) );
2429
2430 /* check if ray is in strip */
2431 if( SQR(b) - (4 * a * c) >= 0.0 )
2432 {
2433 /* find smallest root of quadratic function a * x^2 + b * x + c -> this is the cut coef */
2434 *cutcoef = findMonoidalQuadRoot(scip, a, b, c);
2435
2436 /* if the cutcoef is negative, we have to set it to 0 */
2437 *cutcoef = MAX(*cutcoef, 0.0);
2438
2439 /* check if ray is in strip. If not, monoidal is possible and cutcoef is the strengthened cut coef */
2440 if( ! isRayInStrip(nlhdlrexprdata, vb, vzlp, vapex, vray, kappa, sidefactor, *cutcoef) )
2441 {
2442 *success = TRUE;
2443 }
2444 }
2445
2446 SCIPfreeBufferArray(scip, &vray);
2447 SCIPfreeBufferArray(scip, &vapex);
2448 }
2449
2450 return SCIP_OKAY;
2451}
2452
2453/** sparsify intersection cut by replacing non-basic variables with their bounds if their coefficient allows it */
2454static
2456 SCIP* scip, /**< SCIP data structure */
2457 SCIP_ROWPREP* rowprep /**< rowprep for the generated cut */
2458 )
2459{
2460 int i;
2461 int nvars;
2462
2463 /* get number of variables in rowprep */
2464 nvars = SCIProwprepGetNVars(rowprep);
2465
2466 /* go though all the variables in rowprep */
2467 for( i = 0; i < nvars; ++i )
2468 {
2469 SCIP_VAR* var;
2470 SCIP_Real coef;
2471 SCIP_Real lb;
2472 SCIP_Real ub;
2473 SCIP_Real solval;
2474
2475 /* get variable and its coefficient */
2476 var = SCIProwprepGetVars(rowprep)[i];
2477 coef = SCIProwprepGetCoefs(rowprep)[i];
2478
2479 /* get bounds of variable */
2480 lb = SCIPvarGetLbLocal(var);
2481 ub = SCIPvarGetUbLocal(var);
2482
2483 /* get LP solution value of variable */
2484 solval = SCIPgetSolVal(scip, NULL, var);
2485
2486 /* if the variable is at its lower or upper bound and the coefficient has the correct sign, we can
2487 * set the cutcoef to 0
2488 */
2489 if( SCIPisZero(scip, ub - solval) && coef > 0.0 )
2490 {
2491 SCIProwprepAddSide(rowprep, -coef * ub);
2492 SCIProwprepSetCoef(rowprep, i, 0.0);
2493 }
2494 else if( SCIPisZero(scip, solval - lb) && coef < 0.0 )
2495 {
2496 SCIProwprepAddSide(rowprep, -coef * lb);
2497 SCIProwprepSetCoef(rowprep, i, 0.0);
2498 }
2499 }
2500
2501 return;
2502}
2503
2504/** computes intersection cut cuts off sol (because solution sol violates the quadratic constraint cons)
2505 * and stores it in rowprep. Here, we don't use any strengthening.
2506 */
2507static
2509 SCIP* scip, /**< SCIP data structure */
2510 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2511 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2512 RAYS* rays, /**< rays */
2513 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2514 SCIP_Bool iscase4, /**< whether we are in case 4 */
2515 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2516 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2517 SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
2518 SCIP_Real wzlp, /**< value of w at zlp */
2519 SCIP_Real kappa, /**< value of kappa */
2520 SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
2521 SCIP_Real* interpoints, /**< array to store intersection points for all rays or NULL if nothing
2522 * needs to be stored */
2523 SCIP_SOL* sol, /**< solution we want to separate */
2524 SCIP_Bool* success /**< if a cut candidate could be computed */
2525 )
2526{
2527 SCIP_COL** cols;
2528 SCIP_ROW** rows;
2529 SCIP_Real* apex;
2530 SCIP_Real avecutcoefsum;
2531 SCIP_Real avemonoidalimprovsum;
2532 int monoidalcounter;
2533 int counter;
2534 int i;
2535 SCIP_Bool usemonoidal;
2536 SCIP_Bool monoidalwasused;
2537 SCIP_Bool case2;
2538
2539 cols = SCIPgetLPCols(scip);
2540 rows = SCIPgetLPRows(scip);
2541
2542 case2 = wcoefs == NULL && kappa > 0.0;
2543 monoidalwasused = FALSE;
2544
2545 counter = 0;
2546 monoidalcounter = 0;
2547 avecutcoefsum = 0.0;
2548 avemonoidalimprovsum = 0.0;
2549
2550 /* if we use monoidal and we are in the right case for it, compute the apex of the S-free set */
2551 if( case2 )
2552 {
2553 int nquadexprs;
2554
2555 SCIPexprGetQuadraticData(nlhdlrexprdata->qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
2556
2557 /* allocate memory for apex */
2558 SCIP_CALL( SCIPallocBufferArray(scip, &apex, nquadexprs) );
2559
2560 computeApex(nlhdlrexprdata, vb, vzlp, kappa, sidefactor, apex, success);
2561
2562 /* if computation of apex was not successful, don't apply monoidal strengthening */
2563 if( ! *success )
2564 case2 = FALSE;
2565 }
2566 else
2567 {
2568 apex = NULL;
2569 }
2570
2571 usemonoidal = nlhdlrdata->usemonoidal && case2;
2572
2573 /* for every ray: compute cut coefficient and add var associated to ray into cut */
2574 for( i = 0; i < rays->nrays; ++i )
2575 {
2576 SCIP_Real interpoint;
2577 SCIP_Real cutcoef;
2578 int lppos;
2579 SCIP_Real coefs1234a[5];
2580 SCIP_Real coefs4b[5];
2581 SCIP_Real coefscondition[3];
2582 SCIP_Bool monoidalsuccess;
2583
2584 monoidalsuccess = FALSE;
2585 cutcoef = SCIPinfinity(scip);
2586
2587 /* if we (can) use monoidal strengthening, compute the cut coefficient with that */
2588 if( usemonoidal )
2589 {
2590 SCIP_CALL( computeMonoidalStrengthCoef(scip, nlhdlrexprdata, rays->lpposray[i], &rays->rays[rays->raysbegin[i]],
2591 &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] - rays->raysbegin[i], vb, vzlp, wcoefs, kappa,
2592 apex, sidefactor, &cutcoef, &monoidalsuccess) );
2593 }
2594
2595 /* track whether monoidal was successful at least once if it is used */
2596 if( usemonoidal && ! monoidalwasused && monoidalsuccess )
2597 monoidalwasused = TRUE;
2598
2599 /* if we don't use monoidal or if monoidal couldn't be applied, use gauge to compute coef */
2600 if( ! usemonoidal || ! monoidalsuccess || nlhdlrdata->trackmore )
2601 {
2602 /* restrict phi to ray */
2603 SCIP_CALL( computeRestrictionToRay(scip, nlhdlrexprdata, sidefactor, iscase4,
2604 &rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] -
2605 rays->raysbegin[i], vb, vzlp, wcoefs, wzlp, kappa, coefs1234a, coefs4b, coefscondition, success) );
2606
2607 if( ! *success )
2608 goto TERMINATE;
2609
2610 /* if restriction to ray is numerically nasty -> abort cut separation */
2611 *success = areCoefsNumericsGood(scip, nlhdlrdata, coefs1234a, coefs4b, iscase4);
2612
2613 if( ! *success )
2614 goto TERMINATE;
2615
2616 /* compute intersection point */
2617 interpoint = computeIntersectionPoint(scip, nlhdlrdata, iscase4, coefs1234a, coefs4b, coefscondition);
2618
2619#ifdef DEBUG_INTERSECTIONCUT
2620 SCIPinfoMessage(scip, NULL, "interpoint for ray %d is %g\n", i, interpoint);
2621#endif
2622
2623 /* store intersection point */
2624 if( interpoints != NULL )
2625 interpoints[i] = interpoint;
2626
2627 /* if we are only computing the "normal" cut coefficient to track statistics (and we have been successful
2628 * with monoidal strengthening), don't overwrite cutcoef variable, but just track statistics */
2629 if( nlhdlrdata->trackmore && monoidalsuccess )
2630 {
2631 SCIP_Real normalcutcoef;
2632
2633 normalcutcoef = SCIPisInfinity(scip, interpoint) ? 0.0 : 1.0 / interpoint;
2634
2635 if( cutcoef >= 0 )
2636 avemonoidalimprovsum += cutcoef / normalcutcoef;
2637 ++monoidalcounter;
2638 }
2639 else
2640 {
2641 /* compute cut coef */
2642 cutcoef = SCIPisInfinity(scip, interpoint) ? 0.0 : 1.0 / interpoint;
2643 }
2644
2645 if( cutcoef == 0.0 && case2 && nlhdlrdata->useminrep )
2646 {
2647 /* restrict phi to the line defined by ray + apex + t*(f - apex) */
2648 SCIP_CALL( computeRestrictionToLine(scip, nlhdlrexprdata, sidefactor,
2649 &rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] -
2650 rays->raysbegin[i], vb, vzlp, kappa, apex, coefs1234a, success) );
2651
2652 if( ! *success )
2653 goto TERMINATE;
2654
2655 /* if restriction to ray is numerically nasty -> abort cut separation */
2656 *success = areCoefsNumericsGood(scip, nlhdlrdata, coefs1234a, NULL, FALSE);
2657
2658 if( ! *success )
2659 goto TERMINATE;
2660
2661 coefs1234a[1] *= -1.0;
2662 coefs1234a[3] *= -1.0;
2663
2664 /* compute intersection point */
2665 cutcoef = - computeRoot(scip, coefs1234a);
2666
2667 assert(cutcoef <= 0.0);
2668 }
2669 }
2670
2671 /* keep track of average cut coefficient */
2672 ++counter;
2673 avecutcoefsum += cutcoef;
2674 assert( ! SCIPisInfinity(scip, cutcoef) );
2675
2676 /* add var to cut: if variable is nonbasic at upper we have to flip sign of cutcoef */
2677 lppos = rays->lpposray[i];
2678 if( lppos < 0 )
2679 {
2680 lppos = -lppos - 1;
2681
2682 assert(SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_LOWER || SCIProwGetBasisStatus(rows[lppos]) ==
2684
2685 /* flip cutcoef when necessary. Note: rows have flipped base status! */
2686 cutcoef = SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_UPPER ? cutcoef : -cutcoef;
2687
2688 SCIP_CALL( addRowToCut(scip, rowprep, cutcoef, rows[lppos], success) );
2689
2690 if( ! *success )
2691 {
2692 INTERLOG(printf("Bad numeric: now not nonbasic enough\n");)
2693 nlhdlrdata->nbadnonbasic++;
2694 goto TERMINATE;
2695 }
2696 }
2697 else
2698 {
2699 if( ! nlhdlrdata->useboundsasrays )
2700 {
2701 assert(SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER || SCIPcolGetBasisStatus(cols[lppos]) ==
2703
2704 /* flip cutcoef when necessary */
2705 cutcoef = SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER ? -cutcoef : cutcoef;
2706
2707 SCIP_CALL( addColToCut(scip, rowprep, sol, cutcoef, cols[lppos]) );
2708 }
2709 else
2710 {
2711 /* flip cutcoef when necessary */
2712 cutcoef = rays->rays[i] == -1 ? -cutcoef : cutcoef;
2713
2714 SCIP_CALL( addColToCut(scip, rowprep, sol, cutcoef, cols[lppos]) );
2715 }
2716 }
2717 }
2718
2719 /* track statistics */
2720 if( counter > 0 )
2721 nlhdlrdata->currentavecutcoef = avecutcoefsum / counter;
2722 if( monoidalwasused )
2723 nlhdlrdata->nmonoidal += 1;
2724 if( monoidalcounter > 0 )
2725 nlhdlrdata->currentavemonoidalimprovement = avemonoidalimprovsum / monoidalcounter;
2726
2727TERMINATE:
2729
2730 return SCIP_OKAY;
2731}
2732
2733/** combine ray 1 and 2 to obtain new ray coef1 * ray1 - coef2 * ray2 in sparse format */
2734static
2736 SCIP_Real* raycoefs1, /**< coefficients of ray 1 */
2737 int* rayidx1, /**< index of consvar of the ray 1 coef is associated to */
2738 int raynnonz1, /**< length of raycoefs1 and rayidx1 */
2739 SCIP_Real* raycoefs2, /**< coefficients of ray 2 */
2740 int* rayidx2, /**< index of consvar of the ray 2 coef is associated to */
2741 int raynnonz2, /**< length of raycoefs2 and rayidx2 */
2742 SCIP_Real* newraycoefs, /**< coefficients of combined ray */
2743 int* newrayidx, /**< index of consvar of the combined ray coef is associated to */
2744 int* newraynnonz, /**< pointer to length of newraycoefs and newrayidx */
2745 SCIP_Real coef1, /**< coef of ray 1 */
2746 SCIP_Real coef2 /**< coef of ray 2 */
2747 )
2748{
2749 int idx1;
2750 int idx2;
2751
2752 idx1 = 0;
2753 idx2 = 0;
2754 *newraynnonz = 0;
2755
2756 while( idx1 < raynnonz1 || idx2 < raynnonz2 )
2757 {
2758 /* if the pointers look at different variables (or one already arrieved at the end), only one pointer can move
2759 * on
2760 */
2761 if( idx1 >= raynnonz1 || (idx2 < raynnonz2 && rayidx1[idx1] > rayidx2[idx2]) )
2762 {
2763 /*printf("case 1 \n"); */
2764 newraycoefs[*newraynnonz] = - coef2 * raycoefs2[idx2];
2765 newrayidx[*newraynnonz] = rayidx2[idx2];
2766 ++(*newraynnonz);
2767 ++idx2;
2768 }
2769 else if( idx2 >= raynnonz2 || rayidx1[idx1] < rayidx2[idx2] )
2770 {
2771 /*printf("case 2 \n"); */
2772 newraycoefs[*newraynnonz] = coef1 * raycoefs1[idx1];
2773 newrayidx[*newraynnonz] = rayidx1[idx1];
2774 ++(*newraynnonz);
2775 ++idx1;
2776 }
2777 /* if both pointers look at the same variable, just compute the difference and move both pointers */
2778 else if( rayidx1[idx1] == rayidx2[idx2] )
2779 {
2780 /*printf("case 3 \n"); */
2781 newraycoefs[*newraynnonz] = coef1 * raycoefs1[idx1] - coef2 * raycoefs2[idx2];
2782 newrayidx[*newraynnonz] = rayidx1[idx1];
2783 ++(*newraynnonz);
2784 ++idx1;
2785 ++idx2;
2786 }
2787 }
2788}
2789
2790/** checks if two rays are linearly dependent */
2791static
2793 SCIP* scip, /**< SCIP data structure */
2794 SCIP_Real* raycoefs1, /**< coefficients of ray 1 */
2795 int* rayidx1, /**< index of consvar of the ray 1 coef is associated to */
2796 int raynnonz1, /**< length of raycoefs1 and rayidx1 */
2797 SCIP_Real* raycoefs2, /**< coefficients of ray 2 */
2798 int* rayidx2, /**< index of consvar of the ray 2 coef is associated to */
2799 int raynnonz2, /**< length of raycoefs2 and rayidx2 */
2800 SCIP_Real* coef /**< pointer to store coef (s.t. r1 = coef * r2) in case rays are
2801 * dependent */
2802 )
2803{
2804 int i;
2805
2806 /* cannot be dependent if they have different number of non-zero entries */
2807 if( raynnonz1 != raynnonz2 )
2808 return FALSE;
2809
2810 *coef = 0.0;
2811
2812 for( i = 0; i < raynnonz1; ++i )
2813 {
2814 /* cannot be dependent if different variables have non-zero entries */
2815 if( rayidx1[i] != rayidx2[i] ||
2816 (SCIPisZero(scip, raycoefs1[i]) && !SCIPisZero(scip, raycoefs2[i])) ||
2817 (!SCIPisZero(scip, raycoefs1[i]) && SCIPisZero(scip, raycoefs2[i])) )
2818 {
2819 return FALSE;
2820 }
2821
2822 if( *coef != 0.0 )
2823 {
2824 /* cannot be dependent if the coefs aren't equal for all entries */
2825 if( ! SCIPisEQ(scip, *coef, raycoefs1[i] / raycoefs2[i]) )
2826 {
2827 return FALSE;
2828 }
2829 }
2830 else
2831 *coef = raycoefs1[i] / raycoefs2[i];
2832 }
2833
2834 return TRUE;
2835}
2836
2837/** checks if the ray alpha * ray_i + (1 - alpha) * ray_j is in the recession cone of the S-free set. To do so,
2838 * we check if phi restricted to the ray has a positive root.
2839 */
2840static
2842 SCIP* scip, /**< SCIP data structure */
2843 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2844 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2845 RAYS* rays, /**< rays */
2846 int j, /**< index of current ray in recession cone */
2847 int i, /**< index of current ray not in recession cone */
2848 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2849 SCIP_Bool iscase4, /**< whether we are in case 4 */
2850 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2851 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2852 SCIP_Real* wcoefs, /**< coefficients of w for the quad vars or NULL if w is 0 */
2853 SCIP_Real wzlp, /**< value of w at zlp */
2854 SCIP_Real kappa, /**< value of kappa */
2855 SCIP_Real alpha, /**< coef for combining the two rays */
2856 SCIP_Bool* inreccone, /**< pointer to store whether the ray is in the recession cone or not */
2857 SCIP_Bool* success /**< Did numerical troubles occur? */
2858 )
2859{
2860 SCIP_Real coefs1234a[5];
2861 SCIP_Real coefs4b[5];
2862 SCIP_Real coefscondition[3];
2863 SCIP_Real interpoint;
2864 SCIP_Real* newraycoefs;
2865 int* newrayidx;
2866 int newraynnonz;
2867
2868 *inreccone = FALSE;
2869
2870 /* allocate memory for new ray */
2871 newraynnonz = (rays->raysbegin[i + 1] - rays->raysbegin[i]) + (rays->raysbegin[j + 1] - rays->raysbegin[j]);
2872 SCIP_CALL( SCIPallocBufferArray(scip, &newraycoefs, newraynnonz) );
2873 SCIP_CALL( SCIPallocBufferArray(scip, &newrayidx, newraynnonz) );
2874
2875 /* build the ray alpha * ray_i + (1 - alpha) * ray_j */
2876 combineRays(&rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] -
2877 rays->raysbegin[i], &rays->rays[rays->raysbegin[j]], &rays->raysidx[rays->raysbegin[j]],
2878 rays->raysbegin[j + 1] - rays->raysbegin[j], newraycoefs, newrayidx, &newraynnonz, alpha,
2879 -1 + alpha);
2880
2881 /* restrict phi to the "new" ray */
2882 SCIP_CALL( computeRestrictionToRay(scip, nlhdlrexprdata, sidefactor, iscase4, newraycoefs, newrayidx,
2883 newraynnonz, vb, vzlp, wcoefs, wzlp, kappa, coefs1234a, coefs4b, coefscondition, success) );
2884
2885 if( ! *success )
2886 goto CLEANUP;
2887
2888 /* check if restriction to "new" ray is numerically nasty. If so, treat the corresponding rho as if phi is
2889 * positive
2890 */
2891
2892 /* compute intersection point */
2893 interpoint = computeIntersectionPoint(scip, nlhdlrdata, iscase4, coefs1234a, coefs4b, coefscondition);
2894
2895 /* no root exists */
2896 if( SCIPisInfinity(scip, interpoint) )
2897 *inreccone = TRUE;
2898
2899CLEANUP:
2900 SCIPfreeBufferArray(scip, &newrayidx);
2901 SCIPfreeBufferArray(scip, &newraycoefs);
2902
2903 return SCIP_OKAY;
2904}
2905
2906/** finds the smallest negative steplength for the current ray r_idx such that the combination
2907 * of r_idx with all rays not in the recession cone is in the recession cone
2908 */
2909static
2911 SCIP* scip, /**< SCIP data structure */
2912 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2913 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2914 RAYS* rays, /**< rays */
2915 int idx, /**< index of current ray we want to find rho for */
2916 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2917 SCIP_Bool iscase4, /**< whether we are in case 4 */
2918 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2919 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2920 SCIP_Real* wcoefs, /**< coefficients of w for the quad vars or NULL if w is 0 */
2921 SCIP_Real wzlp, /**< value of w at zlp */
2922 SCIP_Real kappa, /**< value of kappa */
2923 SCIP_Real* interpoints, /**< array to store intersection points for all rays or NULL if nothing
2924 * needs to be stored */
2925 SCIP_Real* rho, /**< pointer to store the optimal rho */
2926 SCIP_Bool* success /**< could we successfully find the right rho? */
2927 )
2928{
2929 int i;
2930
2931 /* go through all rays not in the recession cone and compute the largest negative steplength possible. The
2932 * smallest of them is then the steplength rho we use for the current ray */
2933 *rho = 0.0;
2934 for( i = 0; i < rays->nrays; ++i )
2935 {
2936 SCIP_Real currentrho;
2937 SCIP_Real coef;
2938
2939 if( SCIPisInfinity(scip, interpoints[i]) )
2940 continue;
2941
2942 /* if we cannot strengthen enough, we don't strengthen at all */
2943 if( SCIPisInfinity(scip, -*rho) )
2944 {
2945 *rho = -SCIPinfinity(scip);
2946 return SCIP_OKAY;
2947 }
2948
2949 /* if the rays are linearly independent, we don't need to search for rho */
2950 if( raysAreDependent(scip, &rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]],
2951 rays->raysbegin[i + 1] - rays->raysbegin[i], &rays->rays[rays->raysbegin[idx]],
2952 &rays->raysidx[rays->raysbegin[idx]], rays->raysbegin[idx + 1] - rays->raysbegin[idx], &coef) )
2953 {
2954 currentrho = coef * interpoints[i];
2955 }
2956 else
2957 {
2958 /* since the two rays are linearly independent, we need to find the biggest alpha such that
2959 * alpha * ray_i + (1 - alpha) * ray_idx in the recession cone is. For every ray i, we compute
2960 * such a alpha but take the smallest one of them. We use "maxalpha" to keep track of this.
2961 * Since we know that we can only use alpha < maxalpha, we don't need to do the whole binary search
2962 * for every ray i. We only need to search the intervall [0, maxalpha]. Thereby, we start by checking
2963 * if alpha = maxalpha is already feasable */
2964
2965 SCIP_Bool inreccone;
2966 SCIP_Real alpha;
2967 SCIP_Real lb;
2968 SCIP_Real ub;
2969 int j;
2970
2971 lb = 0.0;
2972 ub = 1.0;
2973 for( j = 0; j < BINSEARCH_MAXITERS; ++j )
2974 {
2975 alpha = (lb + ub) / 2.0;
2976
2977 if( SCIPisZero(scip, alpha) )
2978 {
2979 alpha = 0.0;
2980 break;
2981 }
2982
2983 SCIP_CALL( rayInRecessionCone(scip, nlhdlrdata, nlhdlrexprdata, rays, idx, i, sidefactor, iscase4, vb,
2984 vzlp, wcoefs, wzlp, kappa, alpha, &inreccone, success) );
2985
2986 if( ! *success )
2987 return SCIP_OKAY;
2988
2989 /* no root exists */
2990 if( inreccone )
2991 {
2992 lb = alpha;
2993 if( SCIPisEQ(scip, ub, lb) )
2994 break;
2995 }
2996 else
2997 ub = alpha;
2998 }
2999
3000 /* now we found the best convex combination which we use to derive the corresponding coef. If alpha = 0, we
3001 * cannot move the ray in the recession cone, i.e. strengthening is not possible */
3002 if( SCIPisZero(scip, alpha) )
3003 {
3004 *rho = -SCIPinfinity(scip);
3005 return SCIP_OKAY;
3006 }
3007 else
3008 currentrho = (alpha - 1) * interpoints[i] / alpha; /*lint !e795*/
3009 }
3010
3011 if( currentrho < *rho )
3012 *rho = currentrho;
3013
3014 if( *rho < -10e+06 )
3015 *rho = -SCIPinfinity(scip);
3016
3017 /* if rho is too small, don't add it */
3018 if( SCIPisZero(scip, *rho) )
3019 *success = FALSE;
3020 }
3021
3022 return SCIP_OKAY;
3023}
3024
3025/** computes intersection cut using negative edge extension to strengthen rays that do not intersect
3026 * (i.e., rays in the recession cone)
3027 */
3028static
3030 SCIP* scip, /**< SCIP data structure */
3031 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
3032 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
3033 RAYS* rays, /**< rays */
3034 SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
3035 SCIP_Bool iscase4, /**< whether we are in case 4 */
3036 SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
3037 SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
3038 SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
3039 SCIP_Real wzlp, /**< value of w at zlp */
3040 SCIP_Real kappa, /**< value of kappa */
3041 SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
3042 SCIP_SOL* sol, /**< solution to separate */
3043 SCIP_Bool* success, /**< if a cut candidate could be computed */
3044 SCIP_Bool* strengthsuccess /**< if strengthening was successfully applied */
3045 )
3046{
3047 SCIP_COL** cols;
3048 SCIP_ROW** rows;
3049 SCIP_Real* interpoints;
3050 SCIP_Real avecutcoef;
3051 int counter;
3052 int i;
3053
3054 *success = TRUE;
3055 *strengthsuccess = FALSE;
3056
3057 cols = SCIPgetLPCols(scip);
3058 rows = SCIPgetLPRows(scip);
3059
3060 /* allocate memory for intersection points */
3061 SCIP_CALL( SCIPallocBufferArray(scip, &interpoints, rays->nrays) );
3062
3063 /* compute all intersection points and store them in interpoints; build not-stregthened intersection cut */
3064 SCIP_CALL( computeIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
3065 rowprep, interpoints, sol, success) );
3066
3067 if( ! *success )
3068 goto CLEANUP;
3069
3070 /* keep track of the number of attempted strengthenings and average cutcoef */
3071 counter = 0;
3072 avecutcoef = 0.0;
3073
3074 /* go through all intersection points that are equal to infinity -> these correspond to the rays which are in the
3075 * recession cone of C, i.e. the rays for which we (possibly) can compute a negative steplength */
3076 for( i = 0; i < rays->nrays; ++i )
3077 {
3078 SCIP_Real rho;
3079 SCIP_Real cutcoef;
3080 int lppos;
3081
3082 if( !SCIPisInfinity(scip, interpoints[i]) )
3083 continue;
3084
3085 /* if we reached the limit of strengthenings, we stop */
3086 if( counter >= nlhdlrdata->nstrengthlimit )
3087 break;
3088
3089 /* compute the smallest rho */
3090 SCIP_CALL( findRho(scip, nlhdlrdata, nlhdlrexprdata, rays, i, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
3091 interpoints, &rho, success));
3092
3093 /* compute cut coef */
3094 if( ! *success || SCIPisInfinity(scip, -rho) )
3095 cutcoef = 0.0;
3096 else
3097 cutcoef = 1.0 / rho;
3098
3099 /* track average cut coef */
3100 counter += 1;
3101 avecutcoef += cutcoef;
3102
3103 if( ! SCIPisZero(scip, cutcoef) )
3104 *strengthsuccess = TRUE;
3105
3106 /* add var to cut: if variable is nonbasic at upper we have to flip sign of cutcoef */
3107 lppos = rays->lpposray[i];
3108 if( lppos < 0 )
3109 {
3110 lppos = -lppos - 1;
3111
3112 assert(SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_LOWER || SCIProwGetBasisStatus(rows[lppos]) ==
3114
3115 SCIP_CALL( addRowToCut(scip, rowprep, SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_UPPER ? cutcoef :
3116 -cutcoef, rows[lppos], success) ); /* rows have flipper base status! */
3117
3118 if( ! *success )
3119 {
3120 INTERLOG(printf("Bad numeric: row not nonbasic enough\n");)
3121 nlhdlrdata->nbadnonbasic++;
3122 return SCIP_OKAY;
3123 }
3124 }
3125 else
3126 {
3127 assert(SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER || SCIPcolGetBasisStatus(cols[lppos]) ==
3129 SCIP_CALL( addColToCut(scip, rowprep, sol, SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER ? -cutcoef :
3130 cutcoef, cols[lppos]) );
3131 }
3132 }
3133
3134 if( counter > 0 )
3135 nlhdlrdata->cutcoefsum += avecutcoef / counter;
3136
3137CLEANUP:
3138 SCIPfreeBufferArray(scip, &interpoints);
3139
3140 return SCIP_OKAY;
3141}
3142
3143/** sets variable in solution "vertex" to its nearest bound */
3144static
3146 SCIP* scip, /**< SCIP data structure */
3147 SCIP_SOL* sol, /**< solution to separate */
3148 SCIP_SOL* vertex, /**< new solution to separate */
3149 SCIP_VAR* var, /**< var we want to find nearest bound to */
3150 SCIP_Real* factor, /**< is vertex for current var at lower or upper? */
3151 SCIP_Bool* success /**< TRUE if no variable is bounded */
3152 )
3153{
3154 SCIP_Real solval;
3156
3157 solval = SCIPgetSolVal(scip, sol, var);
3158 *success = TRUE;
3159
3160 /* find nearest bound */
3162 {
3163 *success = FALSE;
3164 return SCIP_OKAY;
3165 }
3166 else if( solval - SCIPvarGetLbLocal(var) < SCIPvarGetUbLocal(var) - solval )
3167 {
3168 bound = SCIPvarGetLbLocal(var);
3169 *factor = 1.0;
3170 }
3171 else
3172 {
3173 bound = SCIPvarGetUbLocal(var);
3174 *factor = -1.0;
3175 }
3176
3177 /* set val to bound in solution */
3178 SCIP_CALL( SCIPsetSolVal(scip, vertex, var, bound) );
3179 return SCIP_OKAY;
3180}
3181
3182/** This function finds vertex (w.r.t. bounds of variables appearing in the quadratic) that is closest to the current
3183 * solution we want to separate.
3184 *
3185 * Furthermore, we store the rays corresponding to the unit vectors, i.e.,
3186 * - if \f$x_i\f$ is at its lower bound in vertex --> \f$r_i = e_i\f$
3187 * - if \f$x_i\f$ is at its upper bound in vertex --> \f$r_i = -e_i\f$
3188 */
3189static
3191 SCIP* scip, /**< SCIP data structure */
3192 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
3193 SCIP_SOL* sol, /**< solution to separate */
3194 SCIP_SOL* vertex, /**< new 'vertex' (w.r.t. bounds) solution to separate */
3195 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
3196 RAYS** raysptr, /**< pointer to new bound rays */
3197 SCIP_Bool* success /**< TRUE if no variable is unbounded */
3198 )
3199{
3200 SCIP_EXPR* qexpr;
3201 SCIP_EXPR** linexprs;
3202 RAYS* rays;
3203 int nquadexprs;
3204 int nlinexprs;
3205 int raylength;
3206 int i;
3207
3208 *success = TRUE;
3209
3210 qexpr = nlhdlrexprdata->qexpr;
3211 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
3212
3213 raylength = (auxvar == NULL) ? nquadexprs + nlinexprs : nquadexprs + nlinexprs + 1;
3214
3215 /* create rays */
3216 SCIP_CALL( createBoundRays(scip, raysptr, raylength) );
3217 rays = *raysptr;
3218
3219 rays->rayssize = raylength;
3220 rays->nrays = raylength;
3221
3222 /* go through quadratic variables */
3223 for( i = 0; i < nquadexprs; ++i )
3224 {
3225 SCIP_EXPR* expr;
3226 SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
3227
3228 rays->raysbegin[i] = i;
3229 rays->raysidx[i] = i;
3231
3233 &rays->rays[i], success) );
3234
3235 if( ! *success )
3236 return SCIP_OKAY;
3237 }
3238
3239 /* go through linear variables */
3240 for( i = 0; i < nlinexprs; ++i )
3241 {
3242 rays->raysbegin[i + nquadexprs] = i + nquadexprs;
3243 rays->raysidx[i + nquadexprs] = i + nquadexprs;
3244 rays->lpposray[i + nquadexprs] = SCIPcolGetLPPos(SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i])));
3245
3247 &rays->rays[i + nquadexprs], success) );
3248
3249 if( ! *success )
3250 return SCIP_OKAY;
3251 }
3252
3253 /* consider auxvar if it exists */
3254 if( auxvar != NULL )
3255 {
3256 rays->raysbegin[nquadexprs + nlinexprs] = nquadexprs + nlinexprs;
3257 rays->raysidx[nquadexprs + nlinexprs] = nquadexprs + nlinexprs;
3258 rays->lpposray[nquadexprs + nlinexprs] = SCIPcolGetLPPos(SCIPvarGetCol(auxvar));
3259
3260 SCIP_CALL( setVarToNearestBound(scip, sol, vertex, auxvar, &rays->rays[nquadexprs + nlinexprs], success) );
3261
3262 if( ! *success )
3263 return SCIP_OKAY;
3264 }
3265
3266 rays->raysbegin[raylength] = raylength;
3267
3268 return SCIP_OKAY;
3269}
3270
3271/** checks if the quadratic constraint is violated by sol */
3272static
3274 SCIP* scip, /**< SCIP data structure */
3275 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
3276 SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
3277 SCIP_SOL* sol, /**< solution to check feasibility for */
3278 SCIP_Real sidefactor /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
3279 )
3280{
3281 SCIP_EXPR* qexpr;
3282 SCIP_EXPR** linexprs;
3283 SCIP_Real* lincoefs;
3284 SCIP_Real constant;
3285 SCIP_Real val;
3286 int nquadexprs;
3287 int nlinexprs;
3288 int nbilinexprs;
3289 int i;
3290
3291 qexpr = nlhdlrexprdata->qexpr;
3292 SCIPexprGetQuadraticData(qexpr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs,
3293 &nbilinexprs, NULL, NULL);
3294
3295 val = 0.0;
3296
3297 /* go through quadratic terms */
3298 for( i = 0; i < nquadexprs; i++ )
3299 {
3300 SCIP_EXPR* expr;
3301 SCIP_Real quadlincoef;
3302 SCIP_Real sqrcoef;
3303 SCIP_Real solval;
3304
3305 SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, &quadlincoef, &sqrcoef, NULL, NULL, NULL);
3306
3307 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr));
3308
3309 /* add square term */
3310 val += sqrcoef * SQR(solval);
3311
3312 /* add linear term */
3313 val += quadlincoef * solval;
3314 }
3315
3316 /* go through bilinear terms */
3317 for( i = 0; i < nbilinexprs; i++ )
3318 {
3319 SCIP_EXPR* expr1;
3320 SCIP_EXPR* expr2;
3321 SCIP_Real bilincoef;
3322
3323 SCIPexprGetQuadraticBilinTerm(qexpr, i, &expr1, &expr2, &bilincoef, NULL, NULL);
3324
3325 val += bilincoef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1))
3327 }
3328
3329 /* go through linear terms */
3330 for( i = 0; i < nlinexprs; i++ )
3331 {
3332 val += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
3333 }
3334
3335 /* add auxvar if exists and get constant */
3336 if( auxvar != NULL )
3337 {
3338 val -= SCIPgetSolVal(scip, sol, auxvar);
3339
3340 constant = (sidefactor == 1.0) ? constant - SCIPgetRhsNonlinear(nlhdlrexprdata->cons) :
3341 SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - constant;
3342 }
3343 else
3344 constant = (sidefactor * constant);
3345
3346 val = (sidefactor * val);
3347
3348 /* now constraint is q(z) <= const */
3349 if( val <= constant )
3350 return FALSE;
3351 else
3352 return TRUE;
3353}
3354
3355/** generates intersection cut that cuts off sol (which violates the quadratic constraint cons) */
3356static
3358 SCIP* scip, /**< SCIP data structure */
3359 SCIP_EXPR* expr, /**< expr */
3360 SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
3361 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
3362 SCIP_CONS* cons, /**< violated constraint that contains expr */
3363 SCIP_SOL* sol, /**< solution to separate */
3364 SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
3365 SCIP_Bool overestimate, /**< TRUE if viol cons is q(z) &ge; lhs; FALSE if q(z) &le; rhs */
3366 SCIP_Bool* success /**< whether separation was successfull or not */
3367 )
3368{
3369 SCIP_EXPR* qexpr;
3370 RAYS* rays;
3371 SCIP_VAR* auxvar;
3372 SCIP_Real sidefactor;
3373 SCIP_Real* vb; /* eigenvectors * b */
3374 SCIP_Real* vzlp; /* eigenvectors * lpsol */
3375 SCIP_Real* wcoefs; /* coefficients affecting quadterms in w */
3376 SCIP_Real wzlp; /* w(lpsol) */
3377 SCIP_Real kappa;
3378 SCIP_Bool iscase4;
3379 SCIP_SOL* vertex;
3380 SCIP_SOL* soltoseparate;
3381 int nquadexprs;
3382 int nlinexprs;
3383 int i;
3384
3385 /* count number of calls */
3386 (nlhdlrdata->ncalls++);
3387
3388 qexpr = nlhdlrexprdata->qexpr;
3389 SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
3390
3391#ifdef DEBUG_INTERSECTIONCUT
3392 SCIPinfoMessage(scip, NULL, "Generating intersection cut for quadratic expr %p aka", (void*)expr);
3393 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3394 SCIPinfoMessage(scip, NULL, "\n");
3395#endif
3396
3397 *success = TRUE;
3398 iscase4 = TRUE;
3399
3400 /* in nonbasic space cut is >= 1 */
3401 assert(SCIProwprepGetSide(rowprep) == 0.0);
3402 SCIProwprepAddSide(rowprep, 1.0);
3404 assert(SCIProwprepGetSide(rowprep) == 1.0);
3405
3406 auxvar = (nlhdlrexprdata->cons != cons) ? SCIPgetExprAuxVarNonlinear(expr) : NULL;
3407 sidefactor = overestimate ? -1.0 : 1.0;
3408
3409 rays = NULL;
3410
3411 /* check if we use tableau or bounds as rays */
3412 if( ! nlhdlrdata->useboundsasrays )
3413 {
3414 SCIP_CALL( createAndStoreSparseRays(scip, nlhdlrexprdata, auxvar, &rays, success) );
3415
3416 if( ! *success )
3417 {
3418 INTERLOG(printf("Failed to get rays: there is a var with base status ZERO!\n"); )
3419 return SCIP_OKAY;
3420 }
3421
3422 soltoseparate = sol;
3423 }
3424 else
3425 {
3426 SCIP_Bool violated;
3427
3428 if( auxvar != NULL )
3429 {
3430 *success = FALSE;
3431 return SCIP_OKAY;
3432 }
3433
3434 /* create new solution */
3435 SCIP_CALL( SCIPcreateSol(scip, &vertex, NULL) );
3436
3437 /* find nearest vertex of the box to separate and compute rays */
3438 SCIP_CALL( findVertexAndGetRays(scip, nlhdlrexprdata, sol, vertex, auxvar, &rays, success) );
3439
3440 if( ! *success )
3441 {
3442 INTERLOG(printf("Failed to use bounds as rays: variable is unbounded!\n"); )
3443 freeRays(scip, &rays);
3444 SCIP_CALL( SCIPfreeSol(scip, &vertex) );
3445 return SCIP_OKAY;
3446 }
3447
3448 /* check if vertex is violated */
3449 violated = isQuadConsViolated(scip, nlhdlrexprdata, auxvar, vertex, sidefactor);
3450
3451 if( ! violated )
3452 {
3453 INTERLOG(printf("Failed to use bounds as rays: nearest vertex is not violated!\n"); )
3454 freeRays(scip, &rays);
3455 SCIP_CALL( SCIPfreeSol(scip, &vertex) );
3456 *success = FALSE;
3457 return SCIP_OKAY;
3458 }
3459
3460 soltoseparate = vertex;
3461 }
3462
3463 SCIP_CALL( SCIPallocBufferArray(scip, &vb, nquadexprs) );
3464 SCIP_CALL( SCIPallocBufferArray(scip, &vzlp, nquadexprs) );
3465 SCIP_CALL( SCIPallocBufferArray(scip, &wcoefs, nquadexprs) );
3466
3467 SCIP_CALL( intercutsComputeCommonQuantities(scip, nlhdlrexprdata, auxvar, sidefactor, soltoseparate,
3468 vb, vzlp, wcoefs, &wzlp, &kappa) );
3469
3470 /* check if we are in case 4 */
3471 if( nlinexprs == 0 && auxvar == NULL )
3472 {
3473 for( i = 0; i < nquadexprs; ++i )
3474 if( wcoefs[i] != 0.0 )
3475 break;
3476
3477 if( i == nquadexprs )
3478 {
3479 /* from now on wcoefs is going to be NULL --> case 1, 2 or 3 */
3480 SCIPfreeBufferArray(scip, &wcoefs);
3481 iscase4 = FALSE;
3482 }
3483 }
3484
3485 /* compute (strengthened) intersection cut */
3486 if( nlhdlrdata->usestrengthening )
3487 {
3488 SCIP_Bool strengthsuccess;
3489
3490 SCIP_CALL( computeStrengthenedIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs,
3491 wzlp, kappa, rowprep, soltoseparate, success, &strengthsuccess) );
3492
3493 if( *success && strengthsuccess )
3494 nlhdlrdata->nstrengthenings++;
3495 }
3496 else
3497 {
3498 SCIP_CALL( computeIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
3499 rowprep, NULL, soltoseparate, success) );
3500 }
3501
3502 SCIPfreeBufferArrayNull(scip, &wcoefs);
3503 SCIPfreeBufferArray(scip, &vzlp);
3505 freeRays(scip, &rays);
3506
3507 if( nlhdlrdata->useboundsasrays )
3508 {
3509 SCIP_CALL( SCIPfreeSol(scip, &vertex) );
3510 }
3511
3512 return SCIP_OKAY;
3513}
3514
3515/** returns whether a quadratic form is "propagable"
3516 *
3517 * It is propagable, if a variable (aka child expr) appears at least twice, which is the case if at least two of the following hold:
3518 * - it appears as a linear term (coef*expr)
3519 * - it appears as a square term (coef*expr^2)
3520 * - it appears in a bilinear term
3521 * - it appears in another bilinear term
3522 */
3523static
3525 SCIP_EXPR* qexpr /**< quadratic representation data */
3526 )
3527{
3528 int nquadexprs;
3529 int i;
3530
3531 SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
3532
3533 for( i = 0; i < nquadexprs; ++i )
3534 {
3535 SCIP_Real lincoef;
3536 SCIP_Real sqrcoef;
3537 int nadjbilin;
3538
3539 SCIPexprGetQuadraticQuadTerm(qexpr, i, NULL, &lincoef, &sqrcoef, &nadjbilin, NULL, NULL);
3540
3541 if( (lincoef != 0.0) + (sqrcoef != 0.0) + nadjbilin >= 2 ) /*lint !e514*/ /* actually MIN(2, nadjbilin), but we check >= 2 */
3542 return TRUE;
3543 }
3544
3545 return FALSE;
3546}
3547
3548/** returns whether a quadratic term is "propagable"
3549 *
3550 * A term is propagable, if its variable (aka child expr) appears at least twice, which is the case if at least two of the following hold:
3551 * - it appears as a linear term (coef*expr)
3552 * - it appears as a square term (coef*expr^2)
3553 * - it appears in a bilinear term
3554 * - it appears in another bilinear term
3555 */
3556static
3558 SCIP_EXPR* qexpr, /**< quadratic representation data */
3559 int idx /**< index of quadratic term to consider */
3560 )
3561{
3562 SCIP_Real lincoef;
3563 SCIP_Real sqrcoef;
3564 int nadjbilin;
3565
3566 SCIPexprGetQuadraticQuadTerm(qexpr, idx, NULL, &lincoef, &sqrcoef, &nadjbilin, NULL, NULL);
3567
3568 return (lincoef != 0.0) + (sqrcoef != 0.0) + nadjbilin >= 2; /*lint !e514*/ /* actually MIN(2, nadjbilin), but we check >= 2 */
3569}
3570
3571/** solves a quadratic equation \f$ a\, \text{expr}^2 + b\, \text{expr} \in \text{rhs} \f$ (with \f$b\f$ an interval)
3572 * and reduces bounds on `expr` or deduces infeasibility if possible
3573 */
3574static
3576 SCIP* scip, /**< SCIP data structure */
3577 SCIP_EXPR* expr, /**< expression for which to solve */
3578 SCIP_Real sqrcoef, /**< square coefficient */
3579 SCIP_INTERVAL b, /**< interval acting as linear coefficient */
3580 SCIP_INTERVAL rhs, /**< interval acting as rhs */
3581 SCIP_Bool* infeasible, /**< buffer to store if propagation produced infeasibility */
3582 int* nreductions /**< buffer to store the number of interval reductions */
3583 )
3584{
3586 SCIP_INTERVAL exprbounds;
3587 SCIP_INTERVAL newrange;
3588
3589 assert(scip != NULL);
3590 assert(expr != NULL);
3591 assert(infeasible != NULL);
3592 assert(nreductions != NULL);
3593
3594#ifdef DEBUG_PROP
3595 SCIPinfoMessage(scip, NULL, "Propagating <expr> by solving a <expr>^2 + b <expr> in rhs, where <expr> is: ");
3596 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3597 SCIPinfoMessage(scip, NULL, "\n");
3598 SCIPinfoMessage(scip, NULL, "expr in [%g, %g], a = %g, b = [%g, %g] and rhs = [%g, %g]\n",
3600 SCIPintervalGetSup(SCIPgetExprBoundsNonlinear(scip, expr)), sqrcoef, b.inf, b.sup,
3601 rhs.inf, rhs.sup);
3602#endif
3603
3604 exprbounds = SCIPgetExprBoundsNonlinear(scip, expr);
3606 {
3607 *infeasible = TRUE;
3608 return SCIP_OKAY;
3609 }
3610
3611 /* compute solution of a*x^2 + b*x in rhs */
3612 SCIPintervalSet(&a, sqrcoef);
3614
3615#ifdef DEBUG_PROP
3616 SCIPinfoMessage(scip, NULL, "Solution [%g, %g]\n", newrange.inf, newrange.sup);
3617#endif
3618
3619 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, newrange, infeasible, nreductions) );
3620
3621 return SCIP_OKAY;
3622}
3623
3624/** solves a linear equation \f$ b\, \text{expr} \in \text{rhs} \f$ (with \f$b\f$ a scalar) and reduces bounds on `expr` or deduces infeasibility if possible */
3625static
3627 SCIP* scip, /**< SCIP data structure */
3628 SCIP_EXPR* expr, /**< expression for which to solve */
3629 SCIP_Real b, /**< linear coefficient */
3630 SCIP_INTERVAL rhs, /**< interval acting as rhs */
3631 SCIP_Bool* infeasible, /**< buffer to store if propagation produced infeasibility */
3632 int* nreductions /**< buffer to store the number of interval reductions */
3633 )
3634{
3635 SCIP_INTERVAL newrange;
3636
3637 assert(scip != NULL);
3638 assert(expr != NULL);
3639 assert(infeasible != NULL);
3640 assert(nreductions != NULL);
3641
3642#ifdef DEBUG_PROP
3643 SCIPinfoMessage(scip, NULL, "Propagating <expr> by solving %g <expr> in [%g, %g], where <expr> is: ", b, rhs.inf, rhs.sup);
3644 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3645 SCIPinfoMessage(scip, NULL, "\n");
3646#endif
3647
3648 /* compute solution of b*x in rhs */
3650
3651#ifdef DEBUG_PROP
3652 SCIPinfoMessage(scip, NULL, "Solution [%g, %g]\n", newrange.inf, newrange.sup);
3653#endif
3654
3655 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, newrange, infeasible, nreductions) );
3656
3657 return SCIP_OKAY;
3658}
3659
3660/** returns max of a/x - c*x for x in {x1, x2} with x1, x2 > 0 */
3661static
3663 SCIP_Real a, /**< coefficient a */
3664 SCIP_Real c, /**< coefficient c */
3665 SCIP_Real x1, /**< coefficient x1 > 0 */
3666 SCIP_Real x2 /**< coefficient x2 > 0 */
3667 )
3668{
3669 SCIP_Real cneg;
3670 SCIP_Real cand1;
3671 SCIP_Real cand2;
3672 SCIP_ROUNDMODE roundmode;
3673
3674 assert(x1 > 0.0);
3675 assert(x2 > 0.0);
3676
3677 cneg = SCIPintervalNegateReal(c);
3678
3679 roundmode = SCIPintervalGetRoundingMode();
3681 cand1 = a/x1 + cneg*x1;
3682 cand2 = a/x2 + cneg*x2;
3683 SCIPintervalSetRoundingMode(roundmode);
3684
3685 return MAX(cand1, cand2);
3686}
3687
3688/** returns max of a/x - c*x for x in dom; it assumes that dom is contained in (0, +inf) */
3689static
3691 SCIP_Real a, /**< coefficient a */
3692 SCIP_Real c, /**< coefficient c */
3693 SCIP_INTERVAL dom /**< domain of x */
3694 )
3695{
3696 SCIP_ROUNDMODE roundmode;
3697 SCIP_INTERVAL argmax;
3698 SCIP_Real negunresmax;
3699 SCIP_Real boundarymax;
3700 assert(dom.inf > 0);
3701
3702 /* if a >= 0, then the function is convex which means the maximum is at one of the boundaries
3703 *
3704 * if c = 0, then the function is monotone which means the maximum is also at one of the boundaries
3705 *
3706 * if a < 0, then the function is concave. The function then has a maximum if and only if there is a point with derivative 0,
3707 * that is, iff -a/x^2 - c = 0 has a solution; i.e. if -a/c >= 0, i.e. (using a<0 and c != 0), c > 0.
3708 * Otherwise (that is, c<0), the maximum is at one of the boundaries.
3709 */
3710 if( a >= 0.0 || c <= 0.0 )
3711 return computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
3712
3713 /* now, the (unrestricted) maximum is at sqrt(-a/c).
3714 * if the argmax is not in the interior of dom then the solution is at a boundary, too
3715 * we check this by computing an interval that contains sqrt(-a/c) first
3716 */
3717 SCIPintervalSet(&argmax, -a);
3718 SCIPintervalDivScalar(SCIP_INTERVAL_INFINITY, &argmax, argmax, c);
3720
3721 /* if the interval containing sqrt(-a/c) does not intersect with the interior of dom, then
3722 * the (restricted) maximum is at a boundary (we could even say at which boundary, but that doesn't save much)
3723 */
3724 if( argmax.sup <= dom.inf || argmax.inf >= dom.sup )
3725 return computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
3726
3727 /* the maximum at sqrt(-a/c) is -2*sqrt(-a*c), so we compute an upper bound for that by computing a lower bound for 2*sqrt(-a*c) */
3728 roundmode = SCIPintervalGetRoundingMode();
3730 negunresmax = 2.0*SCIPnextafter(sqrt(SCIPintervalNegateReal(a)*c), 0.0);
3731 SCIPintervalSetRoundingMode(roundmode);
3732
3733 /* if the interval containing sqrt(-a/c) is contained in dom, then we can return -negunresmax */
3734 if( argmax.inf >= dom.inf && argmax.sup <= dom.sup )
3735 return -negunresmax;
3736
3737 /* now what is left is the case where we cannot say for sure whether sqrt(-a/c) is contained in dom or not
3738 * so we are conservative and return the max of both cases, i.e.,
3739 * the max of the upper bounds on -2*sqrt(-a*c), a/dom.inf-c*dom.inf, a/dom.sup-c*dom.sup.
3740 */
3741 boundarymax = computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
3742 return MAX(boundarymax, -negunresmax);
3743}
3744
3745/** computes the range of rhs/x - coef * x for x in exprdom; this is used for the propagation of bilinear terms
3746 *
3747 * If 0 is in the exprdom, we set range to \f$\mathbb{R}\f$ (even though this is not quite correct, it is correct for the
3748 * intended use of the function).
3749 * TODO: maybe check before calling it whether 0 is in the domain and then just avoid calling it
3750 *
3751 * If rhs is [A,B] and x > 0, then we want the min of A/x - coef*x and max of B/x - coef*x for x in [exprdom].
3752 * If rhs is [A,B] and x < 0, then we want the min of B/x - coef*x and max of A/x - coef*x for x in [exprdom].
3753 * However, this is the same as min of -B/x + coef*x and max of -A/x + coef*x for x in -[exprdom].
3754 * Thus, we can always reduce to x > 0 by multiplying [exprdom], rhs, and coef by -1.
3755 */
3756static
3758 SCIP_INTERVAL exprdom, /**< expression for which to solve */
3759 SCIP_Real coef, /**< expression for which to solve */
3760 SCIP_INTERVAL rhs, /**< rhs used for computation */
3761 SCIP_INTERVAL* range /**< storage for the resulting range */
3762 )
3763{
3764 SCIP_Real max;
3765 SCIP_Real min;
3766
3767 if( exprdom.inf <= 0.0 && 0.0 <= exprdom.sup )
3768 {
3770 return;
3771 }
3772
3773 /* reduce to positive case */
3774 if( exprdom.sup < 0 )
3775 {
3776 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &exprdom, exprdom, -1.0);
3778 coef *= -1.0;
3779 }
3780 assert(exprdom.inf > 0.0);
3781
3782 /* compute maximum and minimum */
3783 max = computeMaxForBilinearProp(rhs.sup, coef, exprdom);
3784 min = -computeMaxForBilinearProp(-rhs.inf, -coef, exprdom);
3785
3786 /* set interval */
3787 SCIPintervalSetBounds(range, min, max);
3788}
3789
3790/** reverse propagates coef_i expr_i + constant in rhs */
3791static
3793 SCIP* scip, /**< SCIP data structure */
3794 SCIP_EXPR** linexprs, /**< linear expressions */
3795 int nlinexprs, /**< number of linear expressions */
3796 SCIP_Real* lincoefs, /**< coefficients of linear expressions */
3797 SCIP_Real constant, /**< constant */
3798 SCIP_INTERVAL rhs, /**< rhs */
3799 SCIP_Bool* infeasible, /**< buffer to store whether an exps' bounds were propagated to an empty interval */
3800 int* nreductions /**< buffer to store the number of interval reductions of all exprs */
3801 )
3802{
3803 SCIP_INTERVAL* oldboundslin;
3804 SCIP_INTERVAL* newboundslin;
3805 int i;
3806
3807 if( nlinexprs == 0 )
3808 return SCIP_OKAY;
3809
3810 SCIP_CALL( SCIPallocBufferArray(scip, &oldboundslin, nlinexprs) );
3811 SCIP_CALL( SCIPallocBufferArray(scip, &newboundslin, nlinexprs) );
3812
3813 for( i = 0; i < nlinexprs; ++i )
3814 oldboundslin[i] = SCIPexprGetActivity(linexprs[i]); /* TODO use SCIPgetExprBoundsNonlinear(scip, linexprs[i]) ? */
3815
3817 oldboundslin, lincoefs, constant, rhs, newboundslin, infeasible);
3818
3819 if( *nreductions > 0 && !*infeasible )
3820 {
3821 /* SCIP is more conservative with what constitutes a reduction than interval arithmetic so we follow SCIP */
3822 *nreductions = 0;
3823 for( i = 0; i < nlinexprs && ! (*infeasible); ++i )
3824 {
3825 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, linexprs[i], newboundslin[i], infeasible, nreductions) );
3826 }
3827 }
3828
3829 SCIPfreeBufferArray(scip, &newboundslin);
3830 SCIPfreeBufferArray(scip, &oldboundslin);
3831
3832 return SCIP_OKAY;
3833}
3834
3835
3836/*
3837 * Callback methods of nonlinear handler
3838 */
3839
3840/** callback to free expression specific data */
3841static
3842SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeexprdataQuadratic)
3843{ /*lint --e{715}*/
3844 assert(nlhdlrexprdata != NULL);
3845 assert(*nlhdlrexprdata != NULL);
3846
3847 if( (*nlhdlrexprdata)->quadactivities != NULL )
3848 {
3849 int nquadexprs;
3850 SCIPexprGetQuadraticData((*nlhdlrexprdata)->qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
3851 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->quadactivities, nquadexprs);
3852 }
3853
3854 SCIPfreeBlockMemory(scip, nlhdlrexprdata);
3855
3856 return SCIP_OKAY;
3857}
3858
3859/** callback to detect structure in expression tree
3860 *
3861 * A term is quadratic if
3862 * - it is a product expression of two expressions, or
3863 * - it is power expression of an expression with exponent 2.0.
3864 *
3865 * We define a _propagable_ quadratic expression as a quadratic expression whose termwise propagation does not yield the
3866 * best propagation. In other words, is a quadratic expression that suffers from the dependency problem.
3867 *
3868 * Specifically, a propagable quadratic expression is a sum expression such that there is at least one expr that appears
3869 * at least twice (because of simplification, this means it appears in a quadratic terms and somewhere else).
3870 * For example: \f$x^2 + y^2\f$ is not a propagable quadratic expression; \f$x^2 + x\f$ is a propagable quadratic expression;
3871 * \f$x^2 + x y\f$ is also a propagable quadratic expression
3872 *
3873 * Furthermore, we distinguish between propagable and non-propagable terms. A term is propagable if any of the expressions
3874 * involved in it appear somewhere else. For example, \f$xy + z^2 + z\f$ is a propagable quadratic, the term \f$xy\f$ is
3875 * non-propagable, and \f$z^2\f$ is propagable. For propagation, non-propagable terms are handled as if they were linear
3876 * terms, that is, we do not use the activity of \f$x\f$ and \f$y\f$ to compute the activity of \f$xy\f$ but rather we use directly
3877 * the activity of \f$xy\f$. Similarly, we do not backward propagate to \f$x\f$ and \f$y\f$ (the product expr handler will do this),
3878 * but we backward propagate to \f$x*y\f$. More technically, we register \f$xy\f$ for its activity usage, rather than\f$x\f$ and \f$y\f$.
3879 *
3880 * For propagation, we store the quadratic in our data structure in the following way: We count how often a variable
3881 * appears. Then, a bilinear product expr_i * expr_j is stored as expr_i * expr_j if # expr_i appears > # expr_j
3882 * appears. When # expr_i appears = # expr_j appears, it then it will be stored as expr_i * expr_j if and only if
3883 * expr_i < expr_j, where '<' is the expression order (see \ref EXPR_ORDER "Ordering Rules" in \ref scip_expr.h).
3884 * Heuristically, this should be useful for propagation. The intuition is that by factoring out the variable that
3885 * appears most often we should be able to take care of the dependency problem better.
3886 *
3887 * Simple convex quadratics like \f$x^2 + y^2\f$ are ignored since the default nlhdlr will take care of them.
3888 *
3889 * @note The expression needs to be simplified (in particular, it is assumed to be sorted).
3890 * @note Common subexpressions are also assumed to have been identified, the hashing will fail otherwise!
3891 *
3892 * Sorted implies that:
3893 * - expr < expr^2: bases are the same, but exponent 1 < 2
3894 * - expr < expr * other_expr: u*v < w holds if and only if v < w (OR8), but here w = u < v, since expr comes before
3895 * other_expr in the product
3896 * - expr < other_expr * expr: u*v < w holds if and only if v < w (OR8), but here v = w
3897 *
3898 * Thus, if we see somebody twice, it is a propagable quadratic.
3899 *
3900 * It also implies that
3901 * - expr^2 < expr * other_expr
3902 * - other_expr * expr < expr^2
3903 *
3904 * It also implies that x^-2 < x^-1, but since, so far, we do not interpret x^-2 as (x^-1)^2, it is not a problem.
3905 */
3906static
3907SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuadratic)
3908{ /*lint --e{715,774}*/
3909 SCIP_NLHDLREXPRDATA* nlexprdata;
3910 SCIP_NLHDLRDATA* nlhdlrdata;
3911 SCIP_Real* eigenvalues;
3912 SCIP_Bool isquadratic;
3913 SCIP_Bool propagable;
3914
3915 assert(scip != NULL);
3916 assert(nlhdlr != NULL);
3917 assert(expr != NULL);
3918 assert(enforcing != NULL);
3919 assert(participating != NULL);
3920 assert(nlhdlrexprdata != NULL);
3921
3922 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
3923 assert(nlhdlrdata != NULL);
3924
3925 /* don't check if all enforcement methods are already ensured */
3926 if( (*enforcing & SCIP_NLHDLR_METHOD_ALL) == SCIP_NLHDLR_METHOD_ALL )
3927 return SCIP_OKAY;
3928
3929 /* if it is not a sum of at least two terms, it is not interesting */
3930 /* TODO: constraints of the form l<= x*y <= r ? */
3931 if( ! SCIPisExprSum(scip, expr) || SCIPexprGetNChildren(expr) < 2 )
3932 return SCIP_OKAY;
3933
3934 /* If we are in a subSCIP we don't want to separate intersection cuts */
3935 if( SCIPgetSubscipDepth(scip) > 0 )
3936 nlhdlrdata->useintersectioncuts = FALSE;
3937
3938#ifdef SCIP_DEBUG
3939 SCIPinfoMessage(scip, NULL, "Nlhdlr quadratic detecting expr %p aka ", (void*)expr);
3940 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3941 SCIPinfoMessage(scip, NULL, "\n");
3942 SCIPinfoMessage(scip, NULL, "Have to enforce %d\n", *enforcing);
3943#endif
3944
3945 /* check whether expression is quadratic (a sum with at least one square or bilinear term) */
3946 SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, &isquadratic) );
3947
3948 /* not quadratic -> nothing for us */
3949 if( !isquadratic )
3950 {
3951 SCIPdebugMsg(scip, "expr %p is not quadratic -> abort detect\n", (void*)expr);
3952 return SCIP_OKAY;
3953 }
3954
3955 propagable = isPropagable(expr);
3956
3957 /* if we are not propagable and are in presolving, return */
3958 if( !propagable && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
3959 {
3960 SCIPdebugMsg(scip, "expr %p is not propagable and in presolving -> abort detect\n", (void*)expr);
3961 return SCIP_OKAY;
3962 }
3963
3964 /* if we do not use intersection cuts and are not propagable, then we do not want to handle it at all;
3965 * if not propagable, then we need to check the curvature to decide if we want to generate intersection cuts
3966 */
3967 if( !propagable && !nlhdlrdata->useintersectioncuts )
3968 {
3969 SCIPdebugMsg(scip, "expr %p is not propagable -> abort detect\n", (void*)expr);
3970 return SCIP_OKAY;
3971 }
3972
3973 /* store quadratic in nlhdlrexprdata */
3974 SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
3975 nlexprdata = *nlhdlrexprdata;
3976 nlexprdata->qexpr = expr;
3977 nlexprdata->cons = cons;
3978
3979#ifdef DEBUG_DETECT
3980 SCIPinfoMessage(scip, NULL, "Nlhdlr quadratic detected:\n");
3981 SCIP_CALL( SCIPprintExprQuadratic(scip, conshdlr, qexpr) );
3982#endif
3983
3984 /* every propagable quadratic expression will be handled since we can propagate */
3985 if( propagable )
3986 {
3987 SCIP_EXPR** linexprs;
3988 int nlinexprs;
3989 int nquadexprs;
3990 int nbilin;
3991 int i;
3992
3993 *participating |= SCIP_NLHDLR_METHOD_ACTIVITY;
3994 *enforcing |= SCIP_NLHDLR_METHOD_ACTIVITY;
3995
3996 SCIPexprGetQuadraticData(expr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, &nbilin, NULL, NULL);
3997 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &nlexprdata->quadactivities, nquadexprs) );
3998
3999 /* notify children of quadratic that we will need their activity for propagation */
4000 for( i = 0; i < nlinexprs; ++i )
4002
4003 for( i = 0; i < nquadexprs; ++i )
4004 {
4005 SCIP_EXPR* argexpr;
4006 if( isPropagableTerm(expr, i) )
4007 {
4008 SCIPexprGetQuadraticQuadTerm(expr, i, &argexpr, NULL, NULL, &nbilin, NULL, NULL);
4010
4011#ifdef DEBUG_DETECT
4012 SCIPinfoMessage(scip, NULL, "quadterm %d propagable, using %p, unbounded=%d\n", i, (void*)argexpr, nbilin >
4014#endif
4015 }
4016 else
4017 {
4018 /* non-propagable quadratic is either a single square term or a single bilinear term
4019 * we should make use nlhdlrs in pow or product for this term, so we register usage of the square or product
4020 * expr instead of argexpr
4021 */
4022 SCIP_EXPR* sqrexpr;
4023 int* adjbilin;
4024
4025 SCIPexprGetQuadraticQuadTerm(expr, i, &argexpr, NULL, NULL, &nbilin, &adjbilin, &sqrexpr);
4026
4027 if( sqrexpr != NULL )
4028 {
4030 assert(nbilin == 0);
4031
4032#ifdef DEBUG_DETECT
4033 SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable square, using %p\n", i, (void*)sqrexpr);
4034#endif
4035 }
4036 else
4037 {
4038 /* we have expr1 * other_expr or other_expr * expr1; know that expr1 is non propagable, but to decide if
4039 * we want the bounds of expr1 or of the product expr1 * other_expr (or other_expr * expr1), we have to
4040 * decide whether other_expr is also non propagable; due to the way we sort bilinear terms (by
4041 * frequency), we can deduce that other_expr doesn't appear anywhere else (i.e. is non propagable) if the
4042 * product is of the form expr1 * other_expr; however, if we see other_expr * expr1 we need to find
4043 * other_expr and check whether it is propagable
4044 */
4045 SCIP_EXPR* expr1;
4046 SCIP_EXPR* prodexpr;
4047
4048 assert(nbilin == 1);
4049 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, NULL, NULL, &prodexpr);
4050
4051 if( expr1 == argexpr )
4052 {
4054
4055#ifdef DEBUG_DETECT
4056 SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable product, using %p\n", i, (void*)prodexpr);
4057#endif
4058 }
4059 else
4060 {
4061 int j;
4062 /* check if other_expr is propagable in which case we need the bounds of expr1; otherwise we just need
4063 * the bounds of the product and this will be (or was) registered when the loop takes us to the
4064 * quadexpr other_expr.
4065 * TODO this should be done faster, maybe store pos1 in bilinexprterm or store quadexprterm's in bilinexprterm
4066 */
4067 for( j = 0; j < nquadexprs; ++j )
4068 {
4069 SCIP_EXPR* exprj;
4070 SCIPexprGetQuadraticQuadTerm(expr, j, &exprj, NULL, NULL, NULL, NULL, NULL);
4071 if( expr1 == exprj )
4072 {
4073 if( isPropagableTerm(expr, j) )
4074 {
4076#ifdef DEBUG_DETECT
4077 SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable alien product, using %p\n", i, (void*)argexpr);
4078#endif
4079 }
4080 break;
4081 }
4082 }
4083 }
4084 }
4085 }
4086 }
4087 }
4088
4089 /* check if we are going to separate or not */
4090 nlexprdata->curvature = SCIP_EXPRCURV_UNKNOWN;
4091
4092 /* for now, we do not care about separation if it is not required */
4094 {
4095 /* if nobody can do anything, remove data */
4096 if( *participating == SCIP_NLHDLR_METHOD_NONE ) /*lint !e845*/
4097 {
4098 SCIP_CALL( nlhdlrFreeexprdataQuadratic(scip, nlhdlr, expr, nlhdlrexprdata) );
4099 }
4100 else
4101 {
4102 SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate\n", (void*)expr);
4103 }
4104 return SCIP_OKAY;
4105 }
4106
4107 assert(SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE); /* separation should only be required in (init)solving stage */
4108
4109 /* check if we can do something more: check curvature of quadratic function stored in nlexprdata
4110 * this is currently only used to decide whether we want to separate, so it can be skipped if in presolve
4111 */
4112 SCIPdebugMsg(scip, "checking curvature of expr %p\n", (void*)expr);
4113 SCIP_CALL( SCIPcomputeExprQuadraticCurvature(scip, expr, &nlexprdata->curvature, NULL, nlhdlrdata->useintersectioncuts) );
4114
4115 /* get eigenvalues to be able to check whether they were computed */
4116 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, NULL, NULL, &eigenvalues, NULL);
4117
4118 /* if we use intersection cuts then we can handle any non-convex quadratic */
4119 if( nlhdlrdata->useintersectioncuts && eigenvalues != NULL && (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) ==
4120 FALSE && nlexprdata->curvature != SCIP_EXPRCURV_CONVEX )
4121 {
4122 *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
4123 }
4124
4125 if( nlhdlrdata->useintersectioncuts && eigenvalues != NULL && (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == FALSE &&
4126 nlexprdata->curvature != SCIP_EXPRCURV_CONCAVE )
4127 {
4128 *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
4129 }
4130
4131 /* if nobody can do anything, remove data */
4132 if( *participating == SCIP_NLHDLR_METHOD_NONE ) /*lint !e845*/
4133 {
4134 SCIP_CALL( nlhdlrFreeexprdataQuadratic(scip, nlhdlr, expr, nlhdlrexprdata) );
4135 return SCIP_OKAY;
4136 }
4137
4138 /* we only need auxiliary variables if we are going to separate */
4139 if( *participating & SCIP_NLHDLR_METHOD_SEPABOTH )
4140 {
4141 SCIP_EXPR** linexprs;
4142 int nquadexprs;
4143 int nlinexprs;
4144 int i;
4145
4146 SCIPexprGetQuadraticData(expr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
4147
4148 for( i = 0; i < nlinexprs; ++i ) /* expressions appearing linearly */
4149 {
4151 }
4152 for( i = 0; i < nquadexprs; ++i ) /* expressions appearing quadratically */
4153 {
4154 SCIP_EXPR* quadexpr;
4155 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexpr, NULL, NULL, NULL, NULL, NULL);
4157 }
4158
4159 SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate and separate\n", (void*)expr);
4160
4161 nlexprdata->separating = TRUE;
4162 }
4163 else
4164 {
4165 SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate only\n", (void*)expr);
4166 }
4167
4169 {
4170 SCIPexprSetCurvature(expr, nlexprdata->curvature);
4171 SCIPdebugMsg(scip, "expr is %s in the original variables\n", nlexprdata->curvature == SCIP_EXPRCURV_CONCAVE ? "concave" : "convex");
4172 nlexprdata->origvars = TRUE;
4173 }
4174
4175 return SCIP_OKAY;
4176}
4177
4178/** nonlinear handler auxiliary evaluation callback */
4179static
4180SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuadratic)
4181{ /*lint --e{715}*/
4182 int i;
4183 int nlinexprs;
4184 int nquadexprs;
4185 int nbilinexprs;
4186 SCIP_Real constant;
4187 SCIP_Real* lincoefs;
4188 SCIP_EXPR** linexprs;
4189
4190 assert(scip != NULL);
4191 assert(expr != NULL);
4192 assert(auxvalue != NULL);
4193 assert(nlhdlrexprdata->separating);
4194 assert(nlhdlrexprdata->qexpr == expr);
4195
4196 /* if the quadratic is in the original variable we can just evaluate the expression */
4197 if( nlhdlrexprdata->origvars )
4198 {
4199 *auxvalue = SCIPexprGetEvalValue(expr);
4200 return SCIP_OKAY;
4201 }
4202
4203 /* TODO there was a
4204 *auxvalue = SCIPevalExprQuadratic(scip, nlhdlrexprdata->qexpr, sol);
4205 here; any reason why not using this anymore?
4206 */
4207
4208 SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
4209
4210 *auxvalue = constant;
4211
4212 for( i = 0; i < nlinexprs; ++i ) /* linear exprs */
4213 *auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
4214
4215 for( i = 0; i < nquadexprs; ++i ) /* quadratic terms */
4216 {
4217 SCIP_Real solval;
4218 SCIP_Real lincoef;
4219 SCIP_Real sqrcoef;
4220 SCIP_EXPR* qexpr;
4221
4222 SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, NULL, NULL, NULL);
4223
4224 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(qexpr));
4225 *auxvalue += (lincoef + sqrcoef * solval) * solval;
4226 }
4227
4228 for( i = 0; i < nbilinexprs; ++i ) /* bilinear terms */
4229 {
4230 SCIP_EXPR* expr1;
4231 SCIP_EXPR* expr2;
4232 SCIP_Real coef;
4233
4234 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
4235
4236 *auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol,
4238 }
4239
4240 return SCIP_OKAY;
4241}
4242
4243/** nonlinear handler enforcement callback */
4244static
4245SCIP_DECL_NLHDLRENFO(nlhdlrEnfoQuadratic)
4246{ /*lint --e{715}*/
4247 SCIP_NLHDLRDATA* nlhdlrdata;
4248 SCIP_ROWPREP* rowprep;
4249 SCIP_Bool success = FALSE;
4250 SCIP_NODE* node;
4251 int depth;
4252 SCIP_Longint nodenumber;
4253 SCIP_Real* eigenvalues;
4254 SCIP_Real violation;
4255
4256 assert(nlhdlrexprdata != NULL);
4257 assert(nlhdlrexprdata->qexpr == expr);
4258
4259 INTERLOG(printf("Starting interesection cuts!\n");)
4260
4261 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
4262 assert(nlhdlrdata != NULL);
4263
4264 assert(result != NULL);
4265 *result = SCIP_DIDNOTRUN;
4266
4267 if( branchcandonly )
4268 return SCIP_OKAY;
4269
4270 /* estimate should take care of convex quadratics */
4271 if( ( overestimate && nlhdlrexprdata->curvature == SCIP_EXPRCURV_CONCAVE) ||
4272 (!overestimate && nlhdlrexprdata->curvature == SCIP_EXPRCURV_CONVEX) )
4273 {
4274 INTERLOG(printf("Convex or concave, no need of interesection cuts!\n");)
4275 return SCIP_OKAY;
4276 }
4277
4278 /* nothing to do if we can't use intersection cuts */
4279 if( ! nlhdlrdata->useintersectioncuts )
4280 {
4281 INTERLOG(printf("We don't use intersection cuts!\n");)
4282 return SCIP_OKAY;
4283 }
4284
4285 /* right now can use interesction cuts only if a basic LP solution is at hand; TODO: in principle we can do something
4286 * even if it is not optimal
4287 */
4289 {
4290 INTERLOG(printf("LP solutoin not good!\n");)
4291 return SCIP_OKAY;
4292 }
4293
4294 /* only separate at selected nodes */
4295 node = SCIPgetCurrentNode(scip);
4296 depth = SCIPnodeGetDepth(node);
4297 if( (nlhdlrdata->atwhichnodes == -1 && depth != 0) || (nlhdlrdata->atwhichnodes != -1 && depth % nlhdlrdata->atwhichnodes != 0) )
4298 {
4299 INTERLOG(printf("Don't separate at this node\n");)
4300 return SCIP_OKAY;
4301 }
4302
4303 /* do not add more than ncutslimitroot cuts in root node and ncutslimit cuts in the non-root nodes */
4304 nodenumber = SCIPnodeGetNumber(node);
4305 if( nlhdlrdata->lastnodenumber != nodenumber )
4306 {
4307 nlhdlrdata->lastnodenumber = nodenumber;
4308 nlhdlrdata->lastncuts = nlhdlrdata->ncutsadded;
4309 }
4310 /*else if( (depth > 0 && nlhdlrdata->ncutsadded - nlhdlrdata->lastncuts >= nlhdlrdata->ncutslimit) || (depth == 0 &&
4311 nlhdlrdata->ncutsadded - nlhdlrdata->lastncuts >= nlhdlrdata->ncutslimitroot)) */
4312 /* allow the addition of a certain number of cuts per quadratic */
4313 if( (depth > 0 && nlhdlrexprdata->ncutsadded >= nlhdlrdata->ncutslimit) || (depth == 0 &&
4314 nlhdlrexprdata->ncutsadded >= nlhdlrdata->ncutslimitroot) )
4315 {
4316 INTERLOG(printf("Too many cuts added already\n");)
4317 return SCIP_OKAY;
4318 }
4319
4320 /* can't separate if we do not have an eigendecomposition */
4321 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, NULL, NULL, &eigenvalues, NULL);
4322 if( eigenvalues == NULL )
4323 {
4324 INTERLOG(printf("No known eigenvalues!\n");)
4325 return SCIP_OKAY;
4326 }
4327
4328 /* if constraint is not sufficiently violated -> do nothing */
4329 if( cons != nlhdlrexprdata->cons )
4330 {
4331 /* constraint is w.r.t auxvar */
4332 violation = auxvalue - SCIPgetSolVal(scip, NULL, SCIPgetExprAuxVarNonlinear(expr));
4333 violation = ABS( violation );
4334 }
4335 else
4336 /* quadratic is a constraint */
4337 violation = MAX( SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - auxvalue, auxvalue -
4338 SCIPgetRhsNonlinear(nlhdlrexprdata->cons)); /*lint !e666*/
4339
4340 if( violation < nlhdlrdata->minviolation )
4341 {
4342 INTERLOG(printf("Violation %g is just too small\n", violation); )
4343 return SCIP_OKAY;
4344 }
4345
4346 /* we can't build an intersection cut when the expr is the root of some constraint and also a subexpression of
4347 * another constraint because we initialize data differently */
4348 if( nlhdlrexprdata->cons != NULL && cons != nlhdlrexprdata->cons )
4349 {
4350 INTERLOG(printf("WARNING!! expr is root of one constraint and subexpr of another!\n"); )
4351 return SCIP_OKAY;
4352 }
4353
4354 /* if we are the root of a constraint and we are feasible w.r.t our auxiliary variables, that is, auxvalue is
4355 * actually feasible for the sides of the constraint, then do not separate
4356 */
4357 if( cons == nlhdlrexprdata->cons && ((overestimate && (SCIPgetLhsNonlinear(cons)) - auxvalue < SCIPfeastol(scip)) ||
4358 (! overestimate && (auxvalue - SCIPgetRhsNonlinear(cons) < SCIPfeastol(scip)))) )
4359 {
4360 INTERLOG(printf("We are actually feasible for the sides of the constraint\n"); )
4361 return SCIP_OKAY;
4362 }
4363
4364#ifdef DEBUG_INTERSECTIONCUT
4365 SCIPinfoMessage(scip, NULL, "Build intersection cut for \n");
4366 if( cons == nlhdlrexprdata->cons )
4367 {
4368 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
4369 SCIPinfoMessage(scip, NULL, "\n");
4370 }
4371 else
4372 {
4373 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
4375 }
4376 SCIPinfoMessage(scip, NULL, "We need to %sestimate\n", overestimate ? "over" : "under" );
4377 SCIPinfoMessage(scip, NULL, "LP sol: \n");
4379#endif
4380 *result = SCIP_DIDNOTFIND;
4381
4382 /* cut (in the nonbasic space) is of the form alpha^T x >= 1 */
4384 INTERLOG(printf("Generating inter cut\n"); )
4385
4386 SCIP_CALL( generateIntercut(scip, expr, nlhdlrdata, nlhdlrexprdata, cons, sol, rowprep, overestimate, &success) );
4387 INTERLOG(if( !success) printf("Generation failed\n"); )
4388
4389 /* we generated something, let us see if it survives the clean up */
4390 if( success )
4391 {
4392 assert(sol == NULL);
4393 nlhdlrdata->ncutsgenerated += 1;
4394 nlhdlrexprdata->ncutsadded += 1;
4395
4396 /* merge coefficients that belong to same variable */
4397 SCIPmergeRowprepTerms(scip, rowprep);
4398
4399 /* sparsify cut */
4400 if( nlhdlrdata->sparsifycuts )
4401 sparsifyIntercut(scip, rowprep);
4402
4403 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, nlhdlrdata->mincutviolation, &violation, &success) );
4404 INTERLOG(if( !success) printf("Clean up failed\n"); )
4405 }
4406
4407 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
4408 if( success )
4409 {
4410 SCIP_ROW* row;
4411 SCIP_Bool infeasible;
4412
4413 /* count number of bound cuts */
4414 if( nlhdlrdata->useboundsasrays )
4415 nlhdlrdata->nboundcuts += 1;
4416
4417 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%s_intersection_quadratic%p_lp%" SCIP_LONGINT_FORMAT,
4418 overestimate ? "over" : "under",
4419 (void*)expr,
4420 SCIPgetNLPs(scip));
4421
4422 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
4423
4424 /* printf("## New cut\n");
4425 printf(" -> found maxquad-free cut <%s>: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n\n",
4426 SCIProwGetName(row), SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row),
4427 SCIPgetCutEfficacy(scip, NULL, row),
4428 SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row),
4429 SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); */
4430
4431 /* intersection cuts can be numerically nasty; we do some extra numerical checks here */
4432 /*printf("SCIP DEPTH %d got a cut with violation %g, efficacy %g and r/e %g\n", SCIPgetSubscipDepth(scip),
4433 * violation, SCIPgetCutEfficacy(scip, NULL, row), SCIPgetRowMaxCoef(scip, row) / SCIPgetRowMinCoef(scip, row) /
4434 * SCIPgetCutEfficacy(scip, NULL, row));
4435 */
4436 assert(SCIPgetCutEfficacy(scip, NULL, row) > 0.0);
4437 if( ! nlhdlrdata->ignorehighre || SCIPgetRowMaxCoef(scip, row) / SCIPgetRowMinCoef(scip, row) / SCIPgetCutEfficacy(scip, NULL, row) < 1e9 )
4438 {
4439#ifdef SCIP_DEBUG
4440 SCIPdebugMsg(scip, "adding cut ");
4441 SCIP_CALL( SCIPprintRow(scip, row, NULL) );
4442#endif
4443
4444 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4445
4446 if( infeasible )
4447 {
4448 *result = SCIP_CUTOFF;
4449 }
4450 else
4451 {
4452 *result = SCIP_SEPARATED;
4453 nlhdlrdata->cutcoefsum += nlhdlrdata->currentavecutcoef;
4454 nlhdlrdata->monoidalimprovementsum += nlhdlrdata->currentavemonoidalimprovement;
4455 nlhdlrdata->ncutsadded += 1;
4456 nlhdlrdata->densitysum += (SCIP_Real) SCIProwprepGetNVars(rowprep) / (SCIP_Real) SCIPgetNVars(scip);
4457 nlhdlrdata->efficacysum += SCIPgetCutEfficacy(scip, NULL, row);
4458 }
4459 }
4460 else
4461 {
4462 nlhdlrdata->nhighre++;
4463 }
4464 SCIP_CALL( SCIPreleaseRow(scip, &row) );
4465 }
4466
4467 SCIPfreeRowprep(scip, &rowprep);
4468
4469 return SCIP_OKAY;
4470}
4471
4472/** nonlinear handler forward propagation callback
4473 *
4474 * This method should solve the problem
4475 * <pre>
4476 * max/min quad expression over box constraints
4477 * </pre>
4478 * However, this problem is difficult so we are satisfied with a proxy.
4479 * Interval arithmetic suffices when no variable appears twice, however this is seldom the case, so we try
4480 * to take care of the dependency problem to some extent:
4481 * Let \f$P_l = \{i : \text{expr}_l \text{expr}_i \,\text{is a bilinear expr}\}\f$.
4482 * 1. partition the quadratic expression as sum of quadratic functions \f$\sum_l q_l\f$
4483 * where \f$q_l = a_l \text{expr}_l^2 + c_l \text{expr}_l + \sum_{i \in P_l} b_{il} \text{expr}_i \text{expr}_l\f$
4484 * 2. build interval quadratic functions, i.e., \f$a x^2 + b x\f$ where \f$b\f$ is an interval, i.e.,
4485 * \f$a_l \text{expr}_l^2 + [\sum_{i \in P_l} b_{il} \text{expr}_i + c_l] \text{expr}_l\f$
4486 * 3. compute \f$\min/\max \{ a x^2 + b x : x \in [x] \}\f$ for each interval quadratic, i.e.,
4487 * \f$\min/\max a_l \text{expr}_l^2 + \text{expr}_l [\sum_{i \in P_l} b_{il} \text{expr}_i + c_l] : \text{expr}_l \in [\text{expr}_l]\f$
4488 *
4489 * Notes:
4490 * 1. The \f$l\f$-th quadratic expr (expressions that appear quadratically) is associated with \f$q_l\f$.
4491 * 2. `nlhdlrdata->quadactivities[l]` is the activity of \f$q_l\f$ as computed in the description above.
4492 * 3. The \f$q_l\f$ of a quadratic term might be empty, in which case `nlhdlrdata->quadactivities[l]` is [0,0].\n
4493 * For example, consider \f$x^2 + xy\f$. There are two quadratic expressions, \f$x\f$ and \f$y\f$.
4494 * The \f$q\f$ associated to \f$x\f$ is \f$x^2 + xy\f$, while the \f$q\f$ associated to \f$y\f$ is empty.
4495 * Thus, `nlhdlrdata->quadactivities[1]` is [0,0] in this case.
4496 * The logic is to avoid considering the term \f$xy\f$ twice.
4497 *
4498 * @note The order matters! If \f$\text{expr}_i\, \text{expr}_l\f$ is a term in the quadratic, then \f$i\f$ is *not* in \f$P_l\f$
4499 */
4500static
4501SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuadratic)
4502{ /*lint --e{715}*/
4503 SCIP_EXPR** linexprs;
4504 SCIP_Real* lincoefs;
4505 SCIP_Real constant;
4506 int nquadexprs;
4507 int nlinexprs;
4508
4509 assert(scip != NULL);
4510 assert(expr != NULL);
4511
4512 assert(nlhdlrexprdata != NULL);
4513 assert(nlhdlrexprdata->quadactivities != NULL);
4514 assert(nlhdlrexprdata->qexpr == expr);
4515
4516 SCIPdebugMsg(scip, "Interval evaluation of quadratic expr\n");
4517
4518 SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, NULL, NULL);
4519
4520 /*
4521 * compute activity of linear part, if some linear term has changed
4522 */
4523 {
4524 int i;
4525
4526 SCIPdebugMsg(scip, "Computing activity of linear part\n");
4527
4528 SCIPintervalSet(&nlhdlrexprdata->linactivity, constant);
4529 for( i = 0; i < nlinexprs; ++i )
4530 {
4531 SCIP_INTERVAL linterminterval;
4532
4533 linterminterval = SCIPexprGetActivity(linexprs[i]);
4534 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, linterminterval) )
4535 {
4536 SCIPdebugMsg(scip, "Activity of linear part is empty due to child %d\n", i);
4537 SCIPintervalSetEmpty(interval);
4538 return SCIP_OKAY;
4539 }
4540 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &linterminterval, linterminterval, lincoefs[i]);
4541 SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &nlhdlrexprdata->linactivity, nlhdlrexprdata->linactivity, linterminterval);
4542 }
4543
4544 SCIPdebugMsg(scip, "Activity of linear part is [%g, %g]\n", nlhdlrexprdata->linactivity.inf,
4545 nlhdlrexprdata->linactivity.sup);
4546 }
4547
4548 /*
4549 * compute activity of quadratic part
4550 */
4551 {
4552 int i;
4553
4554 SCIPdebugMsg(scip, "Computing activity of quadratic part\n");
4555
4556 nlhdlrexprdata->nneginfinityquadact = 0;
4557 nlhdlrexprdata->nposinfinityquadact = 0;
4558 nlhdlrexprdata->minquadfiniteact = 0.0;
4559 nlhdlrexprdata->maxquadfiniteact = 0.0;
4560 SCIPintervalSet(&nlhdlrexprdata->quadactivity, 0.0);
4561
4562 for( i = 0; i < nquadexprs; ++i )
4563 {
4564 SCIP_Real quadlb;
4565 SCIP_Real quadub;
4566 SCIP_EXPR* qexpr;
4567 SCIP_Real lincoef;
4568 SCIP_Real sqrcoef;
4569 int nadjbilin;
4570 int* adjbilin;
4571 SCIP_EXPR* sqrexpr;
4572
4573 SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, &sqrexpr);
4574
4575 if( !isPropagableTerm(expr, i) )
4576 {
4577 /* term is not propagable, i.e., the exprs involved in term only appear once; thus use the activity of the
4578 * quadratic term directly and not the activity of the exprs involed in the term. See also documentation of
4579 * DETECT
4580 */
4581 SCIP_INTERVAL tmp;
4582
4583 assert(lincoef == 0.0);
4584
4585 if( sqrcoef != 0.0 )
4586 {
4587 assert(sqrexpr != NULL);
4588 assert(nadjbilin == 0);
4589
4590 tmp = SCIPexprGetActivity(sqrexpr);
4592 {
4593 SCIPintervalSetEmpty(interval);
4594 return SCIP_OKAY;
4595 }
4596
4597 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &tmp, tmp, sqrcoef);
4598 quadlb = tmp.inf;
4599 quadub = tmp.sup;
4600
4601#ifdef DEBUG_PROP
4602 SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>, where <expr> is: ", sqrcoef);
4603 SCIP_CALL( SCIPprintExpr(scip, sqrexpr, NULL) );
4604#endif
4605 }
4606 else
4607 {
4608 SCIP_EXPR* expr1;
4609 SCIP_EXPR* prodexpr;
4610 SCIP_Real prodcoef;
4611
4612 assert(nadjbilin == 1);
4613 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, &prodcoef, NULL, &prodexpr);
4614
4615 if( expr1 == qexpr )
4616 {
4617 /* the quadratic expression expr1 appears only as expr1 * expr2, so its 'q' is expr1 * expr2 */
4618 tmp = SCIPexprGetActivity(prodexpr);
4620 {
4621 SCIPintervalSetEmpty(interval);
4622 return SCIP_OKAY;
4623 }
4624
4625 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &tmp, tmp, prodcoef);
4626 quadlb = tmp.inf;
4627 quadub = tmp.sup;
4628
4629#ifdef DEBUG_PROP
4630 SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>, where <expr> is: ", prodcoef);
4631 SCIP_CALL( SCIPprintExpr(scip, prodexpr, NULL) );
4632#endif
4633 }
4634 else
4635 {
4636 /* the quadratic expression expr1 appears as expr2 * expr1, thus its 'q' is empty, see also the Notes
4637 * in the documentation of the function
4638 */
4639 SCIPintervalSet(&nlhdlrexprdata->quadactivities[i], 0.0);
4640 continue;
4641 }
4642 }
4643 }
4644 else
4645 {
4646 int j;
4648
4649 SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, NULL);
4650
4652 {
4653 SCIPintervalSetEmpty(interval);
4654 return SCIP_OKAY;
4655 }
4656
4657 /* b = [c_l] */
4658 SCIPintervalSet(&b, lincoef);
4659#ifdef DEBUG_PROP
4660 SCIPinfoMessage(scip, NULL, "b := %g\n", lincoef);
4661#endif
4662 for( j = 0; j < nadjbilin; ++j )
4663 {
4664 SCIP_INTERVAL bterm;
4665 SCIP_EXPR* expr1;
4666 SCIP_EXPR* expr2;
4667 SCIP_Real bilincoef;
4668
4669 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &expr1, &expr2, &bilincoef, NULL, NULL);
4670
4671 if( expr1 != qexpr )
4672 continue;
4673
4674 bterm = SCIPexprGetActivity(expr2);
4676 {
4677 SCIPintervalSetEmpty(interval);
4678 return SCIP_OKAY;
4679 }
4680
4681 /* b += [b_jl * expr_j] for j \in P_l */
4682 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &bterm, bterm, bilincoef);
4684
4685#ifdef DEBUG_PROP
4686 SCIPinfoMessage(scip, NULL, "b += %g * [expr2], where <expr2> is: ", bilincoef);
4687 SCIP_CALL( SCIPprintExpr(scip, expr2, NULL) );
4688 SCIPinfoMessage(scip, NULL, " [%g,%g]\n", SCIPexprGetActivity(expr2).inf, SCIPexprGetActivity(expr2).sup);
4689#endif
4690 }
4691
4692 /* TODO: under which assumptions do we know that we just need to compute min or max? its probably the locks that give some information here */
4694 SCIPexprGetActivity(qexpr));
4695
4696 /* TODO: implement SCIPintervalQuadLowerBound */
4697 {
4698 SCIP_INTERVAL minusb;
4700
4701 quadlb = -SCIPintervalQuadUpperBound(SCIP_INTERVAL_INFINITY, -sqrcoef, minusb,
4702 SCIPexprGetActivity(qexpr));
4703 }
4704
4705#ifdef DEBUG_PROP
4706 SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>^2 + [%g,%g] <expr>, where <expr> is: ", sqrcoef, b.inf, b.sup);
4707 SCIP_CALL( SCIPprintExpr(scip, qexpr, NULL) );
4708#endif
4709 }
4710#ifdef DEBUG_PROP
4711 SCIPinfoMessage(scip, NULL, " -> [%g, %g]\n", quadlb, quadub);
4712#endif
4713
4714 SCIPintervalSetBounds(&nlhdlrexprdata->quadactivities[i], quadlb, quadub);
4715 SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &nlhdlrexprdata->quadactivity, nlhdlrexprdata->quadactivity, nlhdlrexprdata->quadactivities[i]);
4716
4717 /* get number of +/-infinity contributions and compute finite activity */
4718 if( quadlb <= -SCIP_INTERVAL_INFINITY )
4719 nlhdlrexprdata->nneginfinityquadact++;
4720 else
4721 {
4722 SCIP_ROUNDMODE roundmode;
4723
4724 roundmode = SCIPintervalGetRoundingMode();
4726
4727 nlhdlrexprdata->minquadfiniteact += quadlb;
4728
4729 SCIPintervalSetRoundingMode(roundmode);
4730 }
4731 if( quadub >= SCIP_INTERVAL_INFINITY )
4732 nlhdlrexprdata->nposinfinityquadact++;
4733 else
4734 {
4735 SCIP_ROUNDMODE roundmode;
4736
4737 roundmode = SCIPintervalGetRoundingMode();
4739
4740 nlhdlrexprdata->maxquadfiniteact += quadub;
4741
4742 SCIPintervalSetRoundingMode(roundmode);
4743 }
4744 }
4745
4746 SCIPdebugMsg(scip, "Activity of quadratic part is [%g, %g]\n", nlhdlrexprdata->quadactivity.inf, nlhdlrexprdata->quadactivity.sup);
4747 }
4748
4749 /* interval evaluation is linear activity + quadactivity */
4750 SCIPintervalAdd(SCIP_INTERVAL_INFINITY, interval, nlhdlrexprdata->linactivity, nlhdlrexprdata->quadactivity);
4751
4752 nlhdlrexprdata->activitiestag = SCIPgetCurBoundsTagNonlinear(SCIPfindConshdlr(scip, "nonlinear"));
4753
4754 return SCIP_OKAY;
4755}
4756
4757/** nonlinear handler reverse propagation callback
4758 *
4759 * @note the implemented technique is a proxy for solving the problem min/max{ x_i : quad expr in [quad expr] }
4760 * and as such can be improved.
4761 */
4762static
4763SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuadratic)
4764{ /*lint --e{715}*/
4765 SCIP_EXPR** linexprs;
4766 SCIP_EXPR** bilinexprs; /* TODO: should this be stored in the nlhdlr expr data? */
4767 SCIP_Real* bilincoefs;
4768 SCIP_Real* lincoefs;
4769 SCIP_Real constant;
4770 int nquadexprs;
4771 int nlinexprs;
4772
4773 SCIP_INTERVAL rhs;
4774 SCIP_INTERVAL quadactivity;
4775 int i;
4776
4777 SCIPdebugMsg(scip, "Reverse propagation of quadratic expr given bounds = [%g,%g]\n", bounds.inf, bounds.sup);
4778
4779 assert(scip != NULL);
4780 assert(expr != NULL);
4781 assert(infeasible != NULL);
4782 assert(nreductions != NULL);
4783 assert(nlhdlrexprdata != NULL);
4784 assert(nlhdlrexprdata->quadactivities != NULL);
4785 assert(nlhdlrexprdata->qexpr == expr);
4786
4787 *nreductions = 0;
4788
4789 /* not possible to conclude finite bounds if the interval of the expression is [-inf,inf] */
4791 {
4792 SCIPdebugMsg(scip, "expr's range is R -> cannot reverse propagate\n");
4793 return SCIP_OKAY;
4794 }
4795
4796 /* ensure that partial activities as stored in nlhdlrexprdata are uptodate
4797 * if the activity stored in expr is more recent than the partial activities stored in this nlhdlrexprdata,
4798 * then we should reevaluate the partial activities
4799 */
4800 if( SCIPexprGetActivityTag(expr) > nlhdlrexprdata->activitiestag )
4801 {
4802 SCIP_CALL( nlhdlrIntevalQuadratic(scip, nlhdlr, expr, nlhdlrexprdata, &quadactivity, NULL, NULL) );
4803 }
4804
4805 SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, NULL, NULL);
4806
4807 /* propagate linear part in rhs = expr's interval - quadratic activity; first, reconstruct the quadratic activity */
4808 SCIPintervalSetBounds(&quadactivity,
4809 nlhdlrexprdata->nneginfinityquadact > 0 ? -SCIP_INTERVAL_INFINITY : nlhdlrexprdata->minquadfiniteact,
4810 nlhdlrexprdata->nposinfinityquadact > 0 ? SCIP_INTERVAL_INFINITY : nlhdlrexprdata->maxquadfiniteact);
4811
4812 SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs, bounds, quadactivity);
4813
4814 SCIP_CALL( reversePropagateLinearExpr(scip, linexprs, nlinexprs, lincoefs, constant, rhs, infeasible, nreductions) );
4815
4816 /* stop if we find infeasibility */
4817 if( *infeasible )
4818 return SCIP_OKAY;
4819
4820 /* propagate quadratic part in expr's interval - linear activity, where linear activity was computed in INTEVAL.
4821 * The idea is basically to write interval quadratics for each expr and then solve for expr.
4822 *
4823 * One way of achieving this is:
4824 * - for each expression expr_i, write the quadratic expression as a_i expr^2_i + expr_i ( \sum_{j \in J_i} b_ij
4825 * expr_j + c_i ) + quadratic expression in expr_k for k \neq i
4826 * - compute the interval b = [\sum_{j \in J_i} b_ij expr_j + c_i], where J_i are all the indices j such that the
4827 * bilinear expression expr_i expr_j appears
4828 * - use some technique (like the one in nlhdlrIntevalQuadratic), to evaluate the activity of rest_i = [quadratic
4829 * expression in expr_k for k \neq i].
4830 * - solve a_i expr_i^2 + b expr_i \in rhs_i := [expr activity] - rest_i
4831 *
4832 * However, this might be expensive, especially computing rest_i. Hence, we implement a simpler version.
4833 * - we use the same partition as in nlhdlrIntevalQuadratic for the bilinear terms. This way, b = [\sum_{j \in P_i}
4834 * b_ij expr_j + c_i], where P_i is the set of indices j such that expr_i * expr_j appears in that order
4835 * - we evaluate the activity of rest_i as sum_{k \neq i} [\min q_k, \max q_k] where q_k = a_k expr_k^2 + [\sum_{j
4836 * \in P_k} b_jk expr_j + c_k] expr_k. The intervals [\min q_k, \max q_k] were already computed in
4837 * nlhdlrIntevalQuadratic, so we just reuse them.
4838 *
4839 * A downside of the above is that we might not deduce any bounds for variables that appear less often. For example,
4840 * consider x^2 + x * y + x * z + y * z + z. This quadratic gets partitioned as (x^2 + x*y + x*z) + (z*y + z). The
4841 * first parenthesis is interpreted as a function of x, while the second one as a function of z.
4842 * To also get bounds on y, after reverse propagating x in x^2 + x*y + x*z \in rhs, we rewrite this as y + z \in rhs/x -
4843 * x and propagate the y + z).
4844 * In general, after reverse propagating expr_i, we consider
4845 * \sum_{j \in J_i} b_ij expr_j in ([expr activity] - quadratic expression in expr_k for k \neq i - c_i) / expr_i - a_i expr_i,
4846 * compute an interval for the right hand side (see computeRangeForBilinearProp) and use that to propagate the
4847 * linear sum on the left hand side.
4848 *
4849 * Note: this last step generalizes a technique that appeared in the classic cons_quadratic.
4850 * The idea of that technique was to borrow a bilinear term expr_k expr_l when propagating expr_l and the quadratic
4851 * function for expr_k was simple enough.
4852 * Since in P_l we only consider the indices of expressions that appear multiplying expr_l as _second_ factor, we
4853 * would lose the bilinear terms expr_k * expr_l, which contributes to the dependency problem.
4854 * The problem is that the contribution of b_kl * expr_k * expr_l to rest_i is not just [b_kl * expr_k * expr_l], but
4855 * rather quadactivities[k] (= max/min of a_k expr_k^2 + expr_k * [c_k + sum_i \in P_k b_ki expr_i]).
4856 * Thus, we _cannot_ just substract [b_kl * expr_k * expr_l] from rest_i.
4857 * But, if expr_k only appears as expr_k * expr_l, then quadactivities[k] = [b_kl * expr_k * expr_l]. So this
4858 * case was handled in old cons_quadratic.
4859 *
4860 *
4861 * TODO: handle simple cases
4862 * TODO: identify early when there is nothing to be gain
4863 */
4864 SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs, bounds, nlhdlrexprdata->linactivity);
4865 SCIP_CALL( SCIPallocBufferArray(scip, &bilinexprs, nquadexprs) );
4866 SCIP_CALL( SCIPallocBufferArray(scip, &bilincoefs, nquadexprs) );
4867
4868 for( i = 0; i < nquadexprs; ++i )
4869 {
4870 SCIP_INTERVAL rhs_i;
4871 SCIP_INTERVAL rest_i;
4872 SCIP_EXPR* qexpr;
4873 SCIP_Real lincoef;
4874 SCIP_Real sqrcoef;
4875 int nadjbilin;
4876 int* adjbilin;
4877 SCIP_EXPR* sqrexpr;
4878
4879 SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, &sqrexpr);
4880
4881 /* rhs_i = rhs - rest_i.
4882 * to compute rest_i = [\sum_{k \neq i} q_k] we just have to substract
4883 * the activity of q_i from quadactivity; however, care must be taken about infinities;
4884 * if [q_i].sup = +infinity and there is = 1 contributing +infinity -> rest_i.sup = maxquadfiniteact
4885 * if [q_i].sup = +infinity and there is > 1 contributing +infinity -> rest_i.sup = +infinity
4886 * if [q_i].sup = finite and there is > 0 contributing +infinity -> rest_i.sup = +infinity
4887 * if [q_i].sup = finite and there is = 0 contributing +infinity -> rest_i.sup = maxquadfiniteact - [q_i].sup
4888 *
4889 * the same holds when replacing sup with inf, + with - and max(quadfiniteact) with min(...)
4890 */
4891 /* compute rest_i.sup */
4892 if( SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]) < SCIP_INTERVAL_INFINITY &&
4893 nlhdlrexprdata->nposinfinityquadact == 0 )
4894 {
4895 SCIP_ROUNDMODE roundmode;
4896
4897 roundmode = SCIPintervalGetRoundingMode();
4899 rest_i.sup = nlhdlrexprdata->maxquadfiniteact - SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]);
4900
4901 SCIPintervalSetRoundingMode(roundmode);
4902 }
4903 else if( SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]) >= SCIP_INTERVAL_INFINITY &&
4904 nlhdlrexprdata->nposinfinityquadact == 1 )
4905 rest_i.sup = nlhdlrexprdata->maxquadfiniteact;
4906 else
4907 rest_i.sup = SCIP_INTERVAL_INFINITY;
4908
4909 /* compute rest_i.inf */
4910 if( SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]) > -SCIP_INTERVAL_INFINITY &&
4911 nlhdlrexprdata->nneginfinityquadact == 0 )
4912 {
4913 SCIP_ROUNDMODE roundmode;
4914
4915 roundmode = SCIPintervalGetRoundingMode();
4917 rest_i.inf = nlhdlrexprdata->minquadfiniteact - SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]);
4918
4919 SCIPintervalSetRoundingMode(roundmode);
4920 }
4921 else if( SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]) <= -SCIP_INTERVAL_INFINITY &&
4922 nlhdlrexprdata->nneginfinityquadact == 1 )
4923 rest_i.inf = nlhdlrexprdata->minquadfiniteact;
4924 else
4925 rest_i.inf = -SCIP_INTERVAL_INFINITY;
4926
4927#ifdef SCIP_DISABLED_CODE /* I (SV) added the following in cons_quadratic to fix/workaround some bug. Maybe we'll need this here, too? */
4928 /* FIXME in theory, rest_i should not be empty here
4929 * what we tried to do here is to remove the contribution of the i'th bilinear term (=bilinterm) to [minquadactivity,maxquadactivity] from rhs
4930 * however, quadactivity is computed differently (as x*(a1*y1+...+an*yn)) than q_i (a*ak*yk) and since interval arithmetics do overestimation,
4931 * it can happen that q_i is actually slightly larger than quadactivity, which results in rest_i being (slightly) empty
4932 * a proper fix could be to compute the quadactivity also as x*a1*y1+...+x*an*yn if sqrcoef=0, but due to taking
4933 * also infinite bounds into account, this complicates the code even further
4934 * instead, I'll just work around this by turning an empty rest_i into a small non-empty one
4935 */
4937 {
4938 assert(SCIPisSumRelEQ(scip, rest_i.inf, rest_i.sup));
4939 SCIPswapReals(&rest_i.inf, &rest_i.sup);
4940 }
4941#endif
4943
4944 /* compute rhs_i */
4945 SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs_i, rhs, rest_i);
4946
4948 continue;
4949
4950 /* try to propagate */
4951 if( !isPropagableTerm(expr, i) )
4952 {
4953 assert(lincoef == 0.0);
4954
4955 if( sqrcoef != 0.0 )
4956 {
4957 assert(sqrexpr != NULL);
4958 assert(nadjbilin == 0);
4959
4960 /* solve sqrcoef sqrexpr in rhs_i */
4961 SCIP_CALL( propagateBoundsLinExpr(scip, sqrexpr, sqrcoef, rhs_i, infeasible, nreductions) );
4962 }
4963 else
4964 {
4965 /* qexpr only appears in a term of the form qexpr * other_expr (or other_expr * qexpr); we only care about
4966 * getting bounds for the product, thus we will compute these bounds when qexpr appears as qexpr *
4967 * other_expr; note that if it appears as other_expr * qexpr, then when we process other_expr bounds for the
4968 * product will be computed
4969 * TODO: we can actually avoid computing rhs_i in the case that qexpr is not propagable and it appears as
4970 * other_expr * qexpr
4971 */
4972 SCIP_EXPR* expr1;
4973 SCIP_EXPR* prodexpr;
4974 SCIP_Real prodcoef;
4975
4976 assert(nadjbilin == 1);
4977 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, &prodcoef, NULL, &prodexpr);
4978
4979 if( expr1 == qexpr )
4980 {
4981 /* solve prodcoef prodexpr in rhs_i */
4982 SCIP_CALL( propagateBoundsLinExpr(scip, prodexpr, prodcoef, rhs_i, infeasible, nreductions) );
4983 }
4984 }
4985 }
4986 else
4987 {
4989 SCIP_EXPR* expr1 = NULL;
4990 SCIP_EXPR* expr2 = NULL;
4991 SCIP_Real bilincoef = 0.0;
4992 int nbilin = 0;
4993 int pos2 = 0;
4994 int j;
4995
4996 /* set b to [c_l] */
4997 SCIPintervalSet(&b, lincoef);
4998
4999 /* add [\sum_{j \in P_l} b_lj expr_j + c_l] into b */
5000 for( j = 0; j < nadjbilin; ++j )
5001 {
5002 SCIP_INTERVAL bterm;
5003 SCIP_INTERVAL expr2bounds;
5004
5005 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &expr1, &expr2, &bilincoef, &pos2, NULL);
5006
5007 if( expr1 != qexpr )
5008 continue;
5009
5010 expr2bounds = SCIPgetExprBoundsNonlinear(scip, expr2);
5012 {
5013 *infeasible = TRUE;
5014 break;
5015 }
5016
5017 /* b += [b_lj * expr_j] for j \in P_l */
5018 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &bterm, expr2bounds, bilincoef);
5020
5021 /* remember b_lj and expr_j to propagate them too */
5022 bilinexprs[nbilin] = expr2;
5023 bilincoefs[nbilin] = bilincoef;
5024 nbilin++;
5025 }
5026
5027 if( !*infeasible )
5028 {
5029 /* solve a_i expr_i^2 + b expr_i in rhs_i */
5030 SCIP_CALL( propagateBoundsQuadExpr(scip, qexpr, sqrcoef, b, rhs_i, infeasible, nreductions) );
5031 }
5032
5033 if( nbilin > 0 && !*infeasible )
5034 {
5035 /* if 0 is not in [expr_i], then propagate bilincoefs^T bilinexpr in rhs_i/expr_i - a_i expr_i - c_i */
5036 SCIP_INTERVAL bilinrhs;
5037 SCIP_INTERVAL qexprbounds;
5038
5039 qexprbounds = SCIPgetExprBoundsNonlinear(scip, qexpr);
5041 {
5042 *infeasible = TRUE;
5043 }
5044 else
5045 {
5046 /* compute bilinrhs := [rhs_i/expr_i - a_i expr_i] */
5047 computeRangeForBilinearProp(qexprbounds, sqrcoef, rhs_i, &bilinrhs);
5048
5050 {
5051 int nreds;
5052
5053 /* propagate \sum_{j \in P_i} b_ij expr_j + c_i in bilinrhs */
5054 SCIP_CALL( reversePropagateLinearExpr(scip, bilinexprs, nbilin, bilincoefs, lincoef, bilinrhs,
5055 infeasible, &nreds) );
5056
5057 /* TODO FIXME: we are overestimating the number of reductions: an expr might be tightened many times! */
5058 *nreductions += nreds;
5059 }
5060 }
5061 }
5062 }
5063
5064 /* stop if we find infeasibility */
5065 if( *infeasible )
5066 break;
5067 }
5068
5069 SCIPfreeBufferArray(scip, &bilincoefs);
5070 SCIPfreeBufferArray(scip, &bilinexprs);
5071
5072 return SCIP_OKAY;
5073}
5074
5075/** callback to free data of handler */
5076static
5077SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataQuadratic)
5078{ /*lint --e{715}*/
5079 assert(nlhdlrdata != NULL);
5080
5081 SCIPfreeBlockMemory(scip, nlhdlrdata);
5082
5083 return SCIP_OKAY;
5084}
5085
5086/** nonlinear handler copy callback */
5087static
5088SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuadratic)
5089{ /*lint --e{715}*/
5090 assert(targetscip != NULL);
5091 assert(sourcenlhdlr != NULL);
5092 assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
5093
5095
5096 return SCIP_OKAY;
5097}
5098
5099/** includes quadratic nonlinear handler in nonlinear constraint handler */
5101 SCIP* scip /**< SCIP data structure */
5102 )
5103{
5104 SCIP_NLHDLRDATA* nlhdlrdata;
5105 SCIP_NLHDLR* nlhdlr;
5106
5107 assert(scip != NULL);
5108
5109 /* create nonlinear handler specific data */
5110 SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
5111 BMSclearMemory(nlhdlrdata);
5112
5114 NLHDLR_ENFOPRIORITY, nlhdlrDetectQuadratic, nlhdlrEvalauxQuadratic, nlhdlrdata) );
5115
5116 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrQuadratic);
5117 SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataQuadratic);
5118 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeexprdataQuadratic);
5119 SCIPnlhdlrSetSepa(nlhdlr, NULL, nlhdlrEnfoQuadratic, NULL, NULL);
5120 SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalQuadratic, nlhdlrReversepropQuadratic);
5121
5122 /* parameters */
5123 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useintersectioncuts",
5124 "whether to use intersection cuts for quadratic constraints to separate",
5125 &nlhdlrdata->useintersectioncuts, FALSE, DEFAULT_USEINTERCUTS, NULL, NULL) );
5126
5127 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/usestrengthening",
5128 "whether the strengthening should be used",
5129 &nlhdlrdata->usestrengthening, FALSE, DEFAULT_USESTRENGTH, NULL, NULL) );
5130
5131 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/usemonoidal",
5132 "whether monoidal strengthening should be used",
5133 &nlhdlrdata->usemonoidal, FALSE, DEFAULT_USEMONOIDAL, NULL, NULL) );
5134
5135 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useminrep",
5136 "whether the minimal representation of the S-free set should be used (instead of the gauge)",
5137 &nlhdlrdata->useminrep, FALSE, DEFAULT_USEMINREP, NULL, NULL) );
5138
5139 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useboundsasrays",
5140 "use bounds of variables in quadratic as rays for intersection cuts",
5141 &nlhdlrdata->useboundsasrays, FALSE, DEFAULT_USEBOUNDS, NULL, NULL) );
5142
5143 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/ncutslimit",
5144 "limit for number of cuts generated consecutively",
5145 &nlhdlrdata->ncutslimit, FALSE, DEFAULT_NCUTS, 0, INT_MAX, NULL, NULL) );
5146
5147 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/ncutslimitroot",
5148 "limit for number of cuts generated at root node",
5149 &nlhdlrdata->ncutslimitroot, FALSE, DEFAULT_NCUTSROOT, 0, INT_MAX, NULL, NULL) );
5150
5151 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxrank",
5152 "maximal rank a slackvar can have",
5153 &nlhdlrdata->maxrank, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
5154
5155 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mincutviolation",
5156 "minimal cut violation the generated cuts must fulfill to be added to the LP",
5157 &nlhdlrdata->mincutviolation, FALSE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
5158
5159 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/minviolation",
5160 "minimal violation the constraint must fulfill such that a cut is generated",
5161 &nlhdlrdata->minviolation, FALSE, INTERCUTS_MINVIOL, 0.0, SCIPinfinity(scip), NULL, NULL) );
5162
5163 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/atwhichnodes",
5164 "determines at which nodes cut is used (if it's -1, it's used only at the root node, if it's n >= 0, it's used at every multiple of n",
5165 &nlhdlrdata->atwhichnodes, FALSE, 1, -1, INT_MAX, NULL, NULL) );
5166
5167 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/nstrengthlimit",
5168 "limit for number of rays we do the strengthening for",
5169 &nlhdlrdata->nstrengthlimit, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
5170
5171 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/sparsifycuts",
5172 "should we try to sparisfy the intersection cut?",
5173 &nlhdlrdata->sparsifycuts, FALSE, FALSE, NULL, NULL) );
5174
5175 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/ignorebadrayrestriction",
5176 "should cut be generated even with bad numerics when restricting to ray?",
5177 &nlhdlrdata->ignorebadrayrestriction, FALSE, TRUE, NULL, NULL) );
5178
5179 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/ignorenhighre",
5180 "should cut be added even when range / efficacy is large?",
5181 &nlhdlrdata->ignorehighre, FALSE, TRUE, NULL, NULL) );
5182
5183 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/trackmore",
5184 "for monoidal strengthening, should we track more statistics (more expensive)?",
5185 &nlhdlrdata->trackmore, FALSE, FALSE, NULL, NULL) );
5186
5187 /* statistic table */
5190 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputQuadratic, tableCollectQuadratic,
5192 return SCIP_OKAY;
5193}
static long bound
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** b
Definition: circlepacking.c:65
constraint handler for nonlinear constraints specified by algebraic expressions
#define SCIPquadprecSqrtQ(r, a)
Definition: dbldblarith.h:71
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:58
#define SCIPquadprecProdQD(r, a, b)
Definition: dbldblarith.h:63
#define QUAD_SCALE(x, a)
Definition: dbldblarith.h:50
#define SCIPquadprecSumQD(r, a, b)
Definition: dbldblarith.h:62
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:51
#define QUAD(x)
Definition: dbldblarith.h:47
#define SCIPquadprecSquareD(r, a)
Definition: dbldblarith.h:59
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:67
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:49
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_INTERVAL_INFINITY
Definition: def.h:180
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define SQR(x)
Definition: def.h:199
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
power and signed power expression handlers
product expression handler
sum expression handler
variable expression handler
SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2588
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPincludeNlhdlrQuadratic(SCIP *scip)
SCIP_Real SCIPnextafter(SCIP_Real from, SCIP_Real to)
Definition: misc.c:9440
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10498
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:17487
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17425
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:17379
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:17414
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:94
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
SCIP_RETCODE SCIPinsertDatatreeInt(SCIP *scip, SCIP_DATATREE *datatree, const char *name, int value)
SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3872
SCIP_RETCODE SCIPprintExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2495
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4226
void SCIPexprSetCurvature(SCIP_EXPR *expr, SCIP_EXPRCURV curvature)
Definition: expr.c:4080
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1479
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4262
void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
Definition: expr.c:4141
SCIP_RETCODE SCIPcomputeExprQuadraticCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV *curv, SCIP_HASHMAP *assumevarfixed, SCIP_Bool storeeigeninfo)
Definition: scip_expr.c:2611
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1512
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3946
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:4044
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2402
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:4028
void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
Definition: expr.c:4186
void SCIPintervalSetRoundingModeUpwards(void)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
int SCIP_ROUNDMODE
Definition: intervalarith.h:65
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_Real lincoeff, SCIP_Real rhs, SCIP_INTERVAL xbnds)
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
int SCIPintervalPropagateWeightedSum(SCIP_Real infinity, int noperands, SCIP_INTERVAL *operands, SCIP_Real *weights, SCIP_Real constant, SCIP_INTERVAL rhs, SCIP_INTERVAL *resultants, SCIP_Bool *infeasible)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition: scip_lp.c:692
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip_lp.c:477
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:576
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:611
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:632
SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:791
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
SCIP_COL ** SCIPgetLPCols(SCIP *scip)
Definition: scip_lp.c:512
int SCIPgetNLPCols(SCIP *scip)
Definition: scip_lp.c:533
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:673
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:720
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:91
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
void SCIPnlhdlrSetCopyHdlr(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRCOPYHDLR((*copy)))
Definition: nlhdlr.c:77
void SCIPnlhdlrSetFreeExprData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEEXPRDATA((*freeexprdata)))
Definition: nlhdlr.c:99
void SCIPnlhdlrSetProp(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINTEVAL((*inteval)), SCIP_DECL_NLHDLRREVERSEPROP((*reverseprop)))
Definition: nlhdlr.c:124
SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:217
void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)))
Definition: nlhdlr.c:88
void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)), SCIP_DECL_NLHDLREXITSEPA((*exitsepa)))
Definition: nlhdlr.c:137
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:167
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:8483
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:8493
SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
Definition: lp.c:17785
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1886
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17686
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1868
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17632
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17696
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17621
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17895
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2176
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2068
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17652
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17642
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17734
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPprintTransSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2521
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:101
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:62
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisSumRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:23683
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:639
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:659
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
void SCIProwprepSetCoef(SCIP_ROWPREP *rowprep, int idx, SCIP_Real newcoef)
Definition: misc_rowprep.c:734
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:649
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:689
void SCIProwprepSetSidetype(SCIP_ROWPREP *rowprep, SCIP_SIDETYPE sidetype)
Definition: misc_rowprep.c:769
void SCIProwprepAddConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
Definition: misc_rowprep.c:760
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:913
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
Definition: misc_rowprep.c:563
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:629
void SCIProwprepAddSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
Definition: misc_rowprep.c:746
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
Definition: misc_rowprep.c:583
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
#define BMSclearMemory(ptr)
Definition: memory.h:129
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
Rational & max(Rational &r1, Rational &r2)
Rational & min(Rational &r1, Rational &r2)
static SCIP_Bool raysAreDependent(SCIP *scip, SCIP_Real *raycoefs1, int *rayidx1, int raynnonz1, SCIP_Real *raycoefs2, int *rayidx2, int raynnonz2, SCIP_Real *coef)
#define NLHDLR_DETECTPRIORITY
static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuadratic)
static SCIP_RETCODE computeRestrictionToLine(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real sidefactor, SCIP_Real *raycoefs, int *rayidx, int raynnonz, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real kappa, SCIP_Real *apex, SCIP_Real *coefs2, SCIP_Bool *success)
#define DEFAULT_USEBOUNDS
#define DEFAULT_USESTRENGTH
static SCIP_Real computeMaxBoundaryForBilinearProp(SCIP_Real a, SCIP_Real c, SCIP_Real x1, SCIP_Real x2)
static SCIP_RETCODE setVarToNearestBound(SCIP *scip, SCIP_SOL *sol, SCIP_SOL *vertex, SCIP_VAR *var, SCIP_Real *factor, SCIP_Bool *success)
static void computeVApexAndVRay(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real *apex, SCIP_Real *raycoefs, int *rayidx, int raynnonz, SCIP_Real *vapex, SCIP_Real *vray)
static void computeRangeForBilinearProp(SCIP_INTERVAL exprdom, SCIP_Real coef, SCIP_INTERVAL rhs, SCIP_INTERVAL *range)
static SCIP_RETCODE computeIntercut(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_ROWPREP *rowprep, SCIP_Real *interpoints, SCIP_SOL *sol, SCIP_Bool *success)
static SCIP_DECL_TABLECOLLECT(tableCollectQuadratic)
#define NLHDLR_ENFOPRIORITY
static SCIP_RETCODE computeRestrictionToRay(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *raycoefs, int *rayidx, int raynnonz, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Real *coefscondition, SCIP_Bool *success)
static SCIP_RETCODE findRho(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, int idx, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real *interpoints, SCIP_Real *rho, SCIP_Bool *success)
static SCIP_RETCODE createAndStoreSparseRays(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, RAYS **raysptr, SCIP_Bool *success)
static SCIP_DECL_NLHDLRENFO(nlhdlrEnfoQuadratic)
static SCIP_RETCODE insertRayEntry(SCIP *scip, RAYS *rays, SCIP_Real coef, int coefidx, int coefpos)
static void sparsifyIntercut(SCIP *scip, SCIP_ROWPREP *rowprep)
static SCIP_RETCODE computeMonoidalStrengthCoef(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, int lppos, SCIP_Real *raycoefs, int *rayidx, int raynnonz, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real kappa, SCIP_Real *apex, SCIP_Real sidefactor, SCIP_Real *cutcoef, SCIP_Bool *success)
static SCIP_Real findMonoidalQuadRoot(SCIP *scip, SCIP_Real a, SCIP_Real b, SCIP_Real c)
static SCIP_RETCODE propagateBoundsQuadExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_Real sqrcoef, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
static SCIP_RETCODE createBoundRays(SCIP *scip, RAYS **rays, int size)
#define INTERLOG(x)
#define TABLE_DESC_QUADRATIC
static void freeRays(SCIP *scip, RAYS **rays)
static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuadratic)
static SCIP_DECL_TABLEOUTPUT(tableOutputQuadratic)
static void combineRays(SCIP_Real *raycoefs1, int *rayidx1, int raynnonz1, SCIP_Real *raycoefs2, int *rayidx2, int raynnonz2, SCIP_Real *newraycoefs, int *newrayidx, int *newraynnonz, SCIP_Real coef1, SCIP_Real coef2)
static SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuadratic)
static SCIP_Real computeEigenvecDotRay(SCIP_Real *eigenvec, int nquadvars, SCIP_Real *raycoefs, int *rayidx, int raynnonz)
static SCIP_Bool isPropagableTerm(SCIP_EXPR *qexpr, int idx)
#define NLHDLR_DESC
#define DEFAULT_NCUTS
static SCIP_Real computeWRayLinear(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real sidefactor, SCIP_Real *raycoefs, int *rayidx, int raynnonz)
#define DEFAULT_NCUTSROOT
#define DEFAULT_USEMONOIDAL
static SCIP_RETCODE storeDenseTableauRow(SCIP *scip, SCIP_COL *col, int *basicvarpos2tableaurow, int nbasiccol, int raylength, SCIP_Real *binvrow, SCIP_Real *binvarow, SCIP_Real *tableaurows)
static SCIP_RETCODE addRowToCut(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real cutcoef, SCIP_ROW *row, SCIP_Bool *success)
static SCIP_Real computeIntersectionPoint(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_Bool iscase4, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Real *coefscondition)
static SCIP_Real isCase4a(SCIP_Real tsol, SCIP_Real *coefs4a, SCIP_Real *coefscondition)
#define DEFAULT_USEMINREP
static SCIP_Real computeMaxForBilinearProp(SCIP_Real a, SCIP_Real c, SCIP_INTERVAL dom)
#define DEFAULT_USEINTERCUTS
static void constructLPPos2ConsPosMap(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, int *map)
static SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuadratic)
static SCIP_Real computeRoot(SCIP *scip, SCIP_Real *coefs)
static SCIP_Bool isQuadConsViolated(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_SOL *sol, SCIP_Real sidefactor)
static SCIP_Bool areCoefsNumericsGood(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Bool iscase4)
static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuadratic)
#define NLHDLR_NAME
static SCIP_RETCODE intercutsComputeCommonQuantities(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_Real sidefactor, SCIP_SOL *sol, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real *wzlp, SCIP_Real *kappa)
static SCIP_Real evalPhiAtRay(SCIP_Real t, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e)
#define TABLE_POSITION_QUADRATIC
static SCIP_RETCODE insertRayEntries(SCIP *scip, RAYS *rays, SCIP_Real *densetableaucols, int *rayentry2conspos, int raylength, int nray, int conspos, SCIP_Real factor, int *nnonz, SCIP_Bool *success)
static SCIP_RETCODE computeStrengthenedIntercut(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *success, SCIP_Bool *strengthsuccess)
#define TABLE_NAME_QUADRATIC
static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataQuadratic)
#define INTERCUTS_MINVIOL
static void computeApex(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real kappa, SCIP_Real sidefactor, SCIP_Real *apex, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsLinExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_Real b, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
static SCIP_RETCODE createRays(SCIP *scip, RAYS **rays)
#define BINSEARCH_MAXITERS
static int countBasicVars(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_Bool *nozerostat)
static SCIP_RETCODE findVertexAndGetRays(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_SOL *vertex, SCIP_VAR *auxvar, RAYS **raysptr, SCIP_Bool *success)
static SCIP_RETCODE reversePropagateLinearExpr(SCIP *scip, SCIP_EXPR **linexprs, int nlinexprs, SCIP_Real *lincoefs, SCIP_Real constant, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
static SCIP_Bool isPropagable(SCIP_EXPR *qexpr)
static SCIP_Bool isRayInStrip(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *vapex, SCIP_Real *vray, SCIP_Real kappa, SCIP_Real sidefactor, SCIP_Real cutcoef)
static void doBinarySearch(SCIP *scip, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e, SCIP_Real *sol)
static SCIP_RETCODE storeDenseTableauRowsByColumns(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, int raylength, SCIP_VAR *auxvar, SCIP_Real *tableaurows, int *rayentry2conspos)
static SCIP_RETCODE computeMonoidalQuadCoefs(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *vapex, SCIP_Real *vray, SCIP_Real kappa, SCIP_Real sidefactor, SCIP_Real *a, SCIP_Real *b, SCIP_Real *c)
#define TABLE_EARLIEST_STAGE_QUADRATIC
static SCIP_RETCODE constructBasicVars2TableauRowMap(SCIP *scip, int *map)
static SCIP_RETCODE rayInRecessionCone(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, int j, int i, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real alpha, SCIP_Bool *inreccone, SCIP_Bool *success)
static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeexprdataQuadratic)
static SCIP_RETCODE generateIntercut(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_Bool *success)
static SCIP_RETCODE addColToCut(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real cutcoef, SCIP_COL *col)
nonlinear handler to handle quadratic expressions
preparation of a linear inequality to become a SCIP_ROW
public functions of nonlinear handlers of nonlinear constraints
int * raysidx
int rayssize
int * lpposray
SCIP_Real * rays
int * raysbegin
SCIP_Real sup
Definition: intervalarith.h:57
SCIP_Real inf
Definition: intervalarith.h:56
SCIP_EXPRCURV
Definition: type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition: type_expr.h:63
@ SCIP_EXPRCURV_UNKNOWN
Definition: type_expr.h:62
@ SCIP_EXPRCURV_CONCAVE
Definition: type_expr.h:64
@ SCIP_SIDETYPE_LEFT
Definition: type_lp.h:65
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_BASESTAT_BASIC
Definition: type_lpi.h:92
@ SCIP_BASESTAT_UPPER
Definition: type_lpi.h:93
@ SCIP_BASESTAT_LOWER
Definition: type_lpi.h:91
@ SCIP_BASESTAT_ZERO
Definition: type_lpi.h:94
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:52
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:452
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:53
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition: type_nlhdlr.h:54
#define SCIP_NLHDLR_METHOD_NONE
Definition: type_nlhdlr.h:50
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:453
#define SCIP_NLHDLR_METHOD_ALL
Definition: type_nlhdlr.h:55
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:51
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PRESOLVING
Definition: type_set.h:49
@ SCIP_STAGE_INITSOLVE
Definition: type_set.h:52