Scippy

SCIP

Solving Constraint Integer Programs

sepa_eccuts.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 sepa_eccuts.c
26 * @ingroup DEFPLUGINS_SEPA
27 * @brief edge concave cut separator
28 * @author Benjamin Mueller
29 */
30
31/**@todo only count number of fixed variables in the edge concave terms */
32/**@todo only add nonlinear row aggregations where at least ...% of the variables (bilinear terms?) are in edge concave
33 * terms */
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36#include <assert.h>
37#include <string.h>
38
39#include "scip/scipdefplugins.h"
40#include "scip/sepa_eccuts.h"
41#include "scip/cons_xor.h"
42#include "scip/nlp.h"
43#include "tclique/tclique.h"
44
45#define SEPA_NAME "eccuts"
46#define SEPA_DESC "separator for edge-concave functions"
47#define SEPA_PRIORITY -13000
48#define SEPA_FREQ -1
49#define SEPA_MAXBOUNDDIST 1.0
50#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
51#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
52
53#define CLIQUE_MAXFIRSTNODEWEIGHT 1000 /**< maximum weight of branching nodes in level 0; 0 if not used for cliques
54 * with at least one fractional node) */
55#define CLIQUE_MINWEIGHT 0 /**< lower bound for weight of generated cliques */
56#define CLIQUE_MAXNTREENODES 10000 /**< maximal number of nodes of b&b tree */
57#define CLIQUE_BACKTRACKFREQ 10000 /**< frequency to backtrack to first level of tree (0: no premature backtracking) */
58
59#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
60#define DEFAULT_MAXROUNDS 10 /**< maximal number of separation rounds per node (-1: unlimited) */
61#define DEFAULT_MAXROUNDSROOT 250 /**< maximal number of separation rounds in the root node (-1: unlimited) */
62#define DEFAULT_MAXDEPTH -1 /**< maximal depth at which the separator is applied */
63#define DEFAULT_MAXSEPACUTS 10 /**< maximal number of e.c. cuts separated per separation round */
64#define DEFAULT_MAXSEPACUTSROOT 50 /**< maximal number of e.c. cuts separated per separation round in root node */
65#define DEFAULT_CUTMAXRANGE 1e+7 /**< maximal coefficient range of a cut (maximal coefficient divided by minimal
66 * coefficient) in order to be added to LP relaxation */
67#define DEFAULT_MINVIOLATION 0.3 /**< minimal violation of an e.c. cut to be separated */
68#define DEFAULT_MINAGGRSIZE 3 /**< search for e.c. aggregation of at least this size (has to be >= 3) */
69#define DEFAULT_MAXAGGRSIZE 4 /**< search for e.c. aggregation of at most this size (has to be >= minaggrsize) */
70#define DEFAULT_MAXBILINTERMS 500 /**< maximum number of bilinear terms allowed to be in a quadratic constraint */
71#define DEFAULT_MAXSTALLROUNDS 5 /**< maximum number of unsuccessful rounds in the e.c. aggregation search */
72
73#define SUBSCIP_NODELIMIT 100LL /**< node limit to solve the sub-SCIP */
74
75#define ADJUSTFACETTOL 1e-6 /**< adjust resulting facets in checkRikun() up to a violation of this value */
76#define USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
77
78/** first values for \f$2^n\f$ */
79static const int poweroftwo[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
80
81/*
82 * Data structures
83 */
84
85/** data to store a single edge-concave aggregations; an edge-concave aggregation of a quadratic constraint is a subset
86 * of nonconvex bilinear terms
87 */
88struct EcAggr
89{
90 SCIP_VAR** vars; /**< variables */
91 int nvars; /**< number of variables */
92 int varsize; /**< size of vars array */
93
94 SCIP_Real* termcoefs; /**< coefficients of bilinear terms */
95 int* termvars1; /**< index of the first variable of each bilinear term */
96 int* termvars2; /**< index of the second variable of each bilinear term*/
97 int nterms; /**< number of bilinear terms in the aggregation */
98 int termsize; /**< size of term{coefs,vars1,vars2} arrays */
99};
100typedef struct EcAggr SCIP_ECAGGR;
101
102/** data to store all edge-concave aggregations and the remaining part of a nonlinear row of the form g(x) <= rhs */
104{
105 SCIP_NLROW* nlrow; /**< nonlinear row aggregation */
106 SCIP_Bool rhsaggr; /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
107 * g(x) >= lhs (FALSE) */
108
109 SCIP_ECAGGR** ecaggr; /**< array with all edge-concave aggregations */
110 int necaggr; /**< number of edge-concave aggregation */
111
112 SCIP_VAR** linvars; /**< linear variables */
113 SCIP_Real* lincoefs; /**< linear coefficients */
114 int nlinvars; /**< number of linear variables */
115 int linvarssize; /**< size of linvars array */
116
117 SCIP_VAR** quadvars; /**< quadratic variables */
118 int* quadvar2aggr; /**< stores in which edge-concave aggregation the i-th quadratic variable
119 * is contained (< 0: in no edge-concave aggregation) */
120 int nquadvars; /**< number of quadratic variables */
121 int quadvarssize; /**< size of quadvars array */
122
123 SCIP_VAR** remtermvars1; /**< first quadratic variable of remaining bilinear terms */
124 SCIP_VAR** remtermvars2; /**< second quadratic variable of remaining bilinear terms */
125 SCIP_Real* remtermcoefs; /**< coefficients for each remaining bilinear term */
126 int nremterms; /**< number of remaining bilinear terms */
127 int remtermsize; /**< size of remterm* arrays */
128
129 SCIP_Real rhs; /**< rhs of the nonlinear row */
130 SCIP_Real constant; /**< constant part of the nonlinear row */
131};
133
134/** separator data */
135struct SCIP_SepaData
136{
137 SCIP_NLROWAGGR** nlrowaggrs; /**< array containing all nonlinear row aggregations */
138 int nnlrowaggrs; /**< number of nonlinear row aggregations */
139 int nlrowaggrssize; /**< size of nlrowaggrs array */
140 SCIP_Bool searchedforaggr; /**< flag if we already searched for nlrow aggregation candidates */
141 int minaggrsize; /**< only search for e.c. aggregations of at least this size (has to be >= 3) */
142 int maxaggrsize; /**< only search for e.c. aggregations of at most this size (has to be >= minaggrsize) */
143 int maxecsize; /**< largest edge concave aggregation size */
144 int maxbilinterms; /**< maximum number of bilinear terms allowed to be in a quadratic constraint */
145 int maxstallrounds; /**< maximum number of unsuccessful rounds in the e.c. aggregation search */
146
147 SCIP_LPI* lpi; /**< LP interface to solve the LPs to compute the facets of the convex envelopes */
148 int lpisize; /**< maximum size of e.c. aggregations which can be handled by the LP interface */
149
150 SCIP_Real cutmaxrange; /**< maximal coef range of a cut (maximal coefficient divided by minimal
151 * coefficient) in order to be added to LP relaxation */
152 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
153 SCIP_Real minviolation; /**< minimal violation of an e.c. cut to be separated */
154
155 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
156 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
157 int maxdepth; /**< maximal depth at which the separator is applied */
158 int maxsepacuts; /**< maximal number of e.c. cuts separated per separation round */
159 int maxsepacutsroot; /**< maximal number of e.c. cuts separated per separation round in root node */
160
161#ifdef SCIP_STATISTIC
162 SCIP_Real aggrsearchtime; /**< total time spent for searching edge concave aggregations */
163 int nlhsnlrowaggrs; /**< number of found nonlinear row aggregations for SCIP_NLROWs of the form g(x) <= rhs */
164 int nrhsnlrowaggrs; /**< number of found nonlinear row aggregations for SCIP_NLROWs of the form g(x) >= lhs */
165#endif
166};
167
168
169/*
170 * Local methods
171 */
172
173/** creates an empty edge-concave aggregation (without bilinear terms) */
174static
176 SCIP* scip, /**< SCIP data structure */
177 SCIP_ECAGGR** ecaggr, /**< pointer to store the edge-concave aggregation */
178 int nquadvars, /**< number of quadratic variables */
179 int nquadterms /**< number of bilinear terms */
180 )
181{
182 assert(scip != NULL);
183 assert(ecaggr != NULL);
184 assert(nquadvars > 0);
185 assert(nquadterms >= nquadvars);
186
188
189 (*ecaggr)->nvars = 0;
190 (*ecaggr)->nterms = 0;
191 (*ecaggr)->varsize = nquadvars;
192 (*ecaggr)->termsize = nquadterms;
193
194 /* allocate enough memory for the quadratic variables and bilinear terms */
195 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->vars, nquadvars) );
196 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termcoefs, nquadterms) );
197 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termvars1, nquadterms) );
198 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termvars2, nquadterms) );
199
200 return SCIP_OKAY;
201}
202
203/** frees an edge-concave aggregation */
204static
206 SCIP* scip, /**< SCIP data structure */
207 SCIP_ECAGGR** ecaggr /**< pointer to store the edge-concave aggregation */
208 )
209{
210 assert(scip != NULL);
211 assert(ecaggr != NULL);
212
213 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termcoefs), (*ecaggr)->termsize);
214 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termvars1), (*ecaggr)->termsize);
215 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termvars2), (*ecaggr)->termsize);
216 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->vars), (*ecaggr)->varsize);
217
218 SCIPfreeBlockMemory(scip, ecaggr);
219 *ecaggr = NULL;
220
221 return SCIP_OKAY;
222}
223
224/** adds a quadratic variable to an edge-concave aggregation */
225static
227 SCIP_ECAGGR* ecaggr, /**< pointer to store the edge-concave aggregation */
228 SCIP_VAR* x /**< first variable */
229 )
230{
231 ecaggr->vars[ ecaggr->nvars++ ] = x;
232 return SCIP_OKAY;
233}
234
235/** adds a bilinear term to an edge-concave aggregation */
236static
238 SCIP* scip, /**< SCIP data structure */
239 SCIP_ECAGGR* ecaggr, /**< pointer to store the edge-concave aggregation */
240 SCIP_VAR* x, /**< first variable */
241 SCIP_VAR* y, /**< second variable */
242 SCIP_Real coef /**< bilinear coefficient */
243 )
244{
245 int idx1;
246 int idx2;
247 int i;
248
249 assert(x != NULL);
250 assert(y != NULL);
251 assert(ecaggr->nterms + 1 <= ((ecaggr->nvars + 1) * ecaggr->nvars) / 2);
252 assert(!SCIPisZero(scip, coef));
253
254 idx1 = -1;
255 idx2 = -1;
256
257 /* search for the quadratic variables in the e.c. aggregation */
258 for( i = 0; i < ecaggr->nvars && (idx1 == -1 || idx2 == -1); ++i )
259 {
260 if( ecaggr->vars[i] == x )
261 idx1 = i;
262 if( ecaggr->vars[i] == y )
263 idx2 = i;
264 }
265
266 assert(idx1 != -1 && idx2 != -1);
267
268 ecaggr->termcoefs[ ecaggr->nterms ] = coef;
269 ecaggr->termvars1[ ecaggr->nterms ] = idx1;
270 ecaggr->termvars2[ ecaggr->nterms ] = idx2;
271 ++(ecaggr->nterms);
272
273 return SCIP_OKAY;
274}
275
276#ifdef SCIP_DEBUG
277/** prints an edge-concave aggregation */
278static
279void ecaggrPrint(
280 SCIP* scip, /**< SCIP data structure */
281 SCIP_ECAGGR* ecaggr /**< pointer to store the edge-concave aggregation */
282 )
283{
284 int i;
285
286 assert(scip != NULL);
287 assert(ecaggr != NULL);
288
289 SCIPdebugMsg(scip, " nvars = %d nterms = %d\n", ecaggr->nvars, ecaggr->nterms);
290 SCIPdebugMsg(scip, " vars: ");
291 for( i = 0; i < ecaggr->nvars; ++i )
292 SCIPdebugMsgPrint(scip, "%s ", SCIPvarGetName(ecaggr->vars[i]));
293 SCIPdebugMsgPrint(scip, "\n");
294
295 SCIPdebugMsg(scip, " terms: ");
296 for( i = 0; i < ecaggr->nterms; ++i )
297 {
298 SCIP_VAR* x;
299 SCIP_VAR* y;
300
301 x = ecaggr->vars[ ecaggr->termvars1[i] ];
302 y = ecaggr->vars[ ecaggr->termvars2[i] ];
303 SCIPdebugMsgPrint(scip, "%e %s * %s ", ecaggr->termcoefs[i], SCIPvarGetName(x), SCIPvarGetName(y) );
304 }
305 SCIPdebugMsgPrint(scip, "\n");
306}
307#endif
308
309/** stores linear terms in a given nonlinear row aggregation */
310static
312 SCIP* scip, /**< SCIP data structure */
313 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
314 SCIP_VAR** linvars, /**< linear variables */
315 SCIP_Real* lincoefs, /**< linear coefficients */
316 int nlinvars /**< number of linear variables */
317 )
318{
319 assert(scip != NULL);
320 assert(nlrowaggr != NULL);
321 assert(linvars != NULL || nlinvars == 0);
322 assert(lincoefs != NULL || nlinvars == 0);
323 assert(nlinvars >= 0);
324
325 nlrowaggr->nlinvars = 0;
326 nlrowaggr->linvarssize = 0;
327 nlrowaggr->linvars = NULL;
328 nlrowaggr->lincoefs = NULL;
329
330 if( nlinvars == 0 )
331 return SCIP_OKAY;
332
333 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &nlrowaggr->linvars, linvars, nlinvars) );
334 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &nlrowaggr->lincoefs, lincoefs, nlinvars) );
335 nlrowaggr->nlinvars = nlinvars;
336 nlrowaggr->linvarssize = nlinvars;
337
338 /* if we have a nlrow of the form g(x) >= lhs, multiply every coefficient by -1 */
339 if( !nlrowaggr->rhsaggr )
340 {
341 int i;
342
343 for( i = 0; i < nlrowaggr->nlinvars; ++i )
344 nlrowaggr->lincoefs[i] *= -1.0;
345 }
346
347 return SCIP_OKAY;
348}
349
350/** adds linear term to a given nonlinear row aggregation */
351static
353 SCIP* scip, /**< SCIP data structure */
354 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
355 SCIP_VAR* linvar, /**< linear variable */
356 SCIP_Real lincoef /**< coefficient */
357 )
358{
359 assert(scip != NULL);
360 assert(nlrowaggr != NULL);
361 assert(linvar != NULL);
362
363 if( nlrowaggr->nlinvars == nlrowaggr->linvarssize )
364 {
365 int newsize = SCIPcalcMemGrowSize(scip, nlrowaggr->linvarssize+1);
366 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlrowaggr->linvars, nlrowaggr->linvarssize, newsize) );
367 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlrowaggr->lincoefs, nlrowaggr->linvarssize, newsize) );
368 nlrowaggr->linvarssize = newsize;
369 }
370 assert(nlrowaggr->linvarssize > nlrowaggr->nlinvars);
371
372 /* if we have a nlrow of the form g(x) >= lhs, multiply coefficient by -1 */
373 if( !nlrowaggr->rhsaggr )
374 lincoef = -lincoef;
375
376 nlrowaggr->linvars[nlrowaggr->nlinvars] = linvar;
377 nlrowaggr->lincoefs[nlrowaggr->nlinvars] = lincoef;
378 ++nlrowaggr->nlinvars;
379
380 return SCIP_OKAY;
381}
382
383/** adds quadratic variable to a given nonlinear row aggregation */
384static
386 SCIP* scip, /**< SCIP data structure */
387 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
388 SCIP_VAR* quadvar /**< quadratic variable */
389 )
390{
391 assert(scip != NULL);
392 assert(nlrowaggr != NULL);
393 assert(quadvar != NULL);
394
395 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &nlrowaggr->quadvars, &nlrowaggr->quadvarssize, nlrowaggr->nquadvars+1) );
396 assert(nlrowaggr->quadvarssize > nlrowaggr->nquadvars);
397 nlrowaggr->quadvars[nlrowaggr->nquadvars] = quadvar;
398 ++nlrowaggr->nquadvars;
399
400 return SCIP_OKAY;
401}
402
403/** adds a remaining bilinear term to a given nonlinear row aggregation */
404static
406 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
407 SCIP_VAR* x, /**< first variable */
408 SCIP_VAR* y, /**< second variable */
409 SCIP_Real coef /**< bilinear coefficient */
410 )
411{
412 assert(nlrowaggr != NULL);
413 assert(x != NULL);
414 assert(y != NULL);
415 assert(coef != 0.0);
416 assert(nlrowaggr->remtermcoefs != NULL);
417 assert(nlrowaggr->remtermvars1 != NULL);
418 assert(nlrowaggr->remtermvars2 != NULL);
419
420 nlrowaggr->remtermcoefs[ nlrowaggr->nremterms ] = coef;
421 nlrowaggr->remtermvars1[ nlrowaggr->nremterms ] = x;
422 nlrowaggr->remtermvars2[ nlrowaggr->nremterms ] = y;
423 ++(nlrowaggr->nremterms);
424
425 return SCIP_OKAY;
426}
427
428/** creates a nonlinear row aggregation */
429static
431 SCIP* scip, /**< SCIP data structure */
432 SCIP_NLROW* nlrow, /**< nonlinear row */
433 SCIP_NLROWAGGR** nlrowaggr, /**< pointer to store the nonlinear row aggregation */
434 int* quadvar2aggr, /**< mapping between quadratic variables and edge-concave aggregation
435 * stores a negative value if the quadratic variables does not belong
436 * to any aggregation */
437 int nfound, /**< number of edge-concave aggregations */
438 SCIP_Bool rhsaggr /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
439 * lhs <= g(x) (FALSE) */
440 )
441{
442 SCIP_EXPR* expr;
443 int* aggrnvars; /* count the number of variables in each e.c. aggregations */
444 int* aggrnterms; /* count the number of bilinear terms in each e.c. aggregations */
445 int nquadvars;
446 int nremterms;
447 int i;
448
449 assert(scip != NULL);
450 assert(nlrow != NULL);
451 assert(nlrowaggr != NULL);
452 assert(quadvar2aggr != NULL);
453 assert(nfound > 0);
454
455 expr = SCIPnlrowGetExpr(nlrow);
456 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, NULL, NULL, NULL);
457 nremterms = 0;
458
459 SCIP_CALL( SCIPallocClearBufferArray(scip, &aggrnvars, nfound) );
460 SCIP_CALL( SCIPallocClearBufferArray(scip, &aggrnterms, nfound) );
461
462 /* create an empty nonlinear row aggregation */
463 SCIP_CALL( SCIPallocBlockMemory(scip, nlrowaggr) );
464 (*nlrowaggr)->nlrow = nlrow;
465 (*nlrowaggr)->rhsaggr = rhsaggr;
466 (*nlrowaggr)->rhs = rhsaggr ? SCIPnlrowGetRhs(nlrow) : -SCIPnlrowGetLhs(nlrow);
467 (*nlrowaggr)->constant = rhsaggr ? SCIPnlrowGetConstant(nlrow) : -SCIPnlrowGetConstant(nlrow);
468
469 (*nlrowaggr)->quadvars = NULL;
470 (*nlrowaggr)->nquadvars = 0;
471 (*nlrowaggr)->quadvarssize = 0;
472 (*nlrowaggr)->quadvar2aggr = NULL;
473 (*nlrowaggr)->remtermcoefs = NULL;
474 (*nlrowaggr)->remtermvars1 = NULL;
475 (*nlrowaggr)->remtermvars2 = NULL;
476 (*nlrowaggr)->nremterms = 0;
477
478 /* copy quadvar2aggr array */
479 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlrowaggr)->quadvar2aggr, quadvar2aggr, nquadvars) );
480
481 /* store all linear terms */
483 SCIPnlrowGetNLinearVars(nlrow)) );
484
485 /* store all quadratic variables and additional linear terms */
486 /* count the number of variables in each e.c. aggregation */
487 /* count the number of square and bilinear terms in each e.c. aggregation */
488 for( i = 0; i < nquadvars; ++i )
489 {
490 SCIP_EXPR* qterm;
491 SCIP_Real lincoef;
492 SCIP_Real sqrcoef;
493 int idx1;
494 int nadjbilin;
495 int* adjbilin;
496 int j;
497
498 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, NULL);
499 assert(SCIPisExprVar(scip, qterm));
500
502
503 if( lincoef != 0.0 )
504 {
505 SCIP_CALL( nlrowaggrAddLinearTerm(scip, *nlrowaggr, SCIPgetVarExprVar(qterm), lincoef) );
506 }
507
508 if( quadvar2aggr[i] >= 0)
509 ++aggrnvars[ quadvar2aggr[i] ];
510
511 idx1 = quadvar2aggr[i];
512 if( rhsaggr )
513 sqrcoef = -sqrcoef;
514
515 /* variable has to belong to an e.c. aggregation; square term has to be concave */
516 if( idx1 >= 0 && SCIPisNegative(scip, sqrcoef) )
517 ++aggrnterms[idx1];
518 else
519 ++nremterms;
520
521 for( j = 0; j < nadjbilin; ++j )
522 {
523 SCIP_EXPR* qterm1;
524 int pos2;
525 int idx2;
526
527 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
528
529 /* only handle qterm1 == qterm here; the other case will be handled when its turn for qterm2 to be qterm */
530 if( qterm1 != qterm )
531 continue;
532
533 idx2 = quadvar2aggr[pos2];
534
535 /* variables have to belong to the same e.c. aggregation; bilinear term has to be concave */
536 if( idx1 >= 0 && idx2 >= 0 && idx1 == idx2 )
537 ++aggrnterms[idx1];
538 else
539 ++nremterms;
540 }
541 }
542 assert((*nlrowaggr)->nquadvars == nquadvars);
543
544 /* create all edge-concave aggregations (empty) and remaining terms */
545 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->ecaggr, nfound) );
546 if( nremterms > 0 )
547 {
548 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermcoefs, nremterms) );
549 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermvars1, nremterms) );
550 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermvars2, nremterms) );
551 (*nlrowaggr)->remtermsize = nremterms;
552 }
553 (*nlrowaggr)->necaggr = nfound;
554
555 for( i = 0; i < nfound; ++i )
556 {
557 SCIP_CALL( ecaggrCreateEmpty(scip, &(*nlrowaggr)->ecaggr[i], aggrnvars[i], aggrnterms[i]) );
558 }
559
560 /* add quadratic variables to the edge-concave aggregations */
561 for( i = 0; i < nquadvars; ++i )
562 {
563 int idx;
564
565 idx = quadvar2aggr[i];
566
567 if( idx >= 0)
568 {
569 SCIP_EXPR* qterm;
570
571 SCIPdebugMsg(scip, "add quadvar %d to aggr. %d\n", i, idx);
572
573 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, NULL, NULL, NULL);
574 assert(SCIPisExprVar(scip, qterm));
575
576 SCIP_CALL( ecaggrAddQuadvar((*nlrowaggr)->ecaggr[idx], SCIPgetVarExprVar(qterm)) );
577 }
578 }
579
580 /* add the bilinear/square terms to the edge-concave aggregations or in the remaining part */
581 for( i = 0; i < nquadvars; ++i )
582 {
583 SCIP_EXPR* qterm;
584 SCIP_VAR* x;
585 SCIP_Real coef;
586 int idx1;
587 int nadjbilin;
588 int* adjbilin;
589 int j;
590
591 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
592
593 x = SCIPgetVarExprVar(qterm);
594
595 idx1 = quadvar2aggr[i];
596 if( rhsaggr )
597 coef = -coef;
598
599 if( idx1 >= 0 && SCIPisNegative(scip, coef) )
600 {
601 SCIP_CALL( ecaggrAddBilinTerm(scip, (*nlrowaggr)->ecaggr[idx1], x, x, coef) );
602 SCIPdebugMsg(scip, "add term %e *%d^2 to aggr. %d\n", coef, i, idx1);
603 }
604 else
605 {
606 SCIP_CALL( nlrowaggrAddRemBilinTerm(*nlrowaggr, x, x, coef) );
607 SCIPdebugMsg(scip, "add term %e *%d^2 to the remaining part\n", coef, idx1);
608 }
609
610 for( j = 0; j < nadjbilin; ++j )
611 {
612 SCIP_EXPR* qterm1;
613 SCIP_EXPR* qterm2;
614 int pos2;
615 int idx2;
616 SCIP_VAR* y;
617
618 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
619
620 /* only handle qterm1 == qterm here; the other case will be handled when its turn for qterm2 to be qterm */
621 if( qterm1 != qterm )
622 continue;
623
624 y = SCIPgetVarExprVar(qterm2);
625
626 idx2 = quadvar2aggr[pos2];
627 if( rhsaggr )
628 coef = -coef;
629
630 if( idx1 >= 0 && idx2 >= 0 && idx1 == idx2 )
631 {
632 SCIP_CALL( ecaggrAddBilinTerm(scip, (*nlrowaggr)->ecaggr[idx1], x, y, coef) );
633 SCIPdebugMsg(scip, "add term %e *%d*%d to aggr. %d\n", coef, i, pos2, idx1);
634 }
635 else
636 {
637 SCIP_CALL( nlrowaggrAddRemBilinTerm(*nlrowaggr, x, y, coef) );
638 SCIPdebugMsg(scip, "add term %e *%d*%d to the remaining part\n", coef, i, pos2);
639 }
640 }
641 }
642
643 /* free allocated memory */
644 SCIPfreeBufferArray(scip, &aggrnterms);
645 SCIPfreeBufferArray(scip, &aggrnvars);
646
647 return SCIP_OKAY;
648}
649
650/** frees a nonlinear row aggregation */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_NLROWAGGR** nlrowaggr /**< pointer to free the nonlinear row aggregation */
655 )
656{
657 int i;
658
659 assert(scip != NULL);
660 assert(nlrowaggr != NULL);
661 assert(*nlrowaggr != NULL);
662 (*nlrowaggr)->nlrow = NULL;
663 assert((*nlrowaggr)->quadvars != NULL);
664 assert((*nlrowaggr)->nquadvars > 0);
665 assert((*nlrowaggr)->nremterms >= 0);
666
667 /* free remaining part */
668 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermcoefs, (*nlrowaggr)->remtermsize);
669 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermvars1, (*nlrowaggr)->remtermsize);
670 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermvars2, (*nlrowaggr)->remtermsize);
671
672 /* free quadratic variables */
673 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->quadvars, (*nlrowaggr)->quadvarssize);
674 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->quadvar2aggr, (*nlrowaggr)->nquadvars);
675
676 /* free linear part */
677 if( (*nlrowaggr)->nlinvars > 0 )
678 {
679 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->linvars, (*nlrowaggr)->linvarssize);
680 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->lincoefs, (*nlrowaggr)->linvarssize);
681 }
682
683 /* free edge-concave aggregations */
684 for( i = 0; i < (*nlrowaggr)->necaggr; ++i )
685 {
686 SCIP_CALL( ecaggrFree(scip, &(*nlrowaggr)->ecaggr[i]) );
687 }
688 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->ecaggr, (*nlrowaggr)->necaggr);
689
690 /* free nlrow aggregation */
691 SCIPfreeBlockMemory(scip, nlrowaggr);
692
693 return SCIP_OKAY;
694}
695
696#ifdef SCIP_DEBUG
697/** prints a nonlinear row aggregation */
698static
699void nlrowaggrPrint(
700 SCIP* scip, /**< SCIP data structure */
701 SCIP_NLROWAGGR* nlrowaggr /**< nonlinear row aggregation */
702 )
703{
704 int i;
705
706 SCIPdebugMsg(scip, " nlrowaggr rhs = %e\n", nlrowaggr->rhs);
707 SCIPdebugMsg(scip, " #remaining terms = %d\n", nlrowaggr->nremterms);
708
709 SCIPdebugMsg(scip, "remaining terms: ");
710 for( i = 0; i < nlrowaggr->nremterms; ++i )
711 SCIPdebugMsgPrint(scip, "%e %s * %s + ", nlrowaggr->remtermcoefs[i], SCIPvarGetName(nlrowaggr->remtermvars1[i]),
712 SCIPvarGetName(nlrowaggr->remtermvars2[i]) );
713 for( i = 0; i < nlrowaggr->nlinvars; ++i )
714 SCIPdebugMsgPrint(scip, "%e %s + ", nlrowaggr->lincoefs[i], SCIPvarGetName(nlrowaggr->linvars[i]) );
715 SCIPdebugMsgPrint(scip, "\n");
716
717 for( i = 0; i < nlrowaggr->necaggr; ++i )
718 {
719 SCIPdebugMsg(scip, "print e.c. aggr %d\n", i);
720 ecaggrPrint(scip, nlrowaggr->ecaggr[i]);
721 }
722 return;
723}
724#endif
725
726/** creates separator data */
727static
729 SCIP* scip, /**< SCIP data structure */
730 SCIP_SEPADATA** sepadata /**< pointer to store separator data */
731 )
732{
733 assert(scip != NULL);
734 assert(sepadata != NULL);
735
736 SCIP_CALL( SCIPallocBlockMemory(scip, sepadata) );
737 BMSclearMemory(*sepadata);
738
739 return SCIP_OKAY;
740}
741
742/** frees all nonlinear row aggregations */
743static
745 SCIP* scip, /**< SCIP data structure */
746 SCIP_SEPADATA* sepadata /**< pointer to store separator data */
747 )
748{
749 assert(scip != NULL);
750 assert(sepadata != NULL);
751
752 /* free nonlinear row aggregations */
753 if( sepadata->nlrowaggrs != NULL )
754 {
755 int i;
756
757 for( i = sepadata->nnlrowaggrs - 1; i >= 0; --i )
758 {
759 SCIP_CALL( nlrowaggrFree(scip, &sepadata->nlrowaggrs[i]) );
760 }
761
762 SCIPfreeBlockMemoryArray(scip, &sepadata->nlrowaggrs, sepadata->nlrowaggrssize);
763
764 sepadata->nlrowaggrs = NULL;
765 sepadata->nnlrowaggrs = 0;
766 sepadata->nlrowaggrssize = 0;
767 }
768
769 return SCIP_OKAY;
770}
771
772/** frees separator data */
773static
775 SCIP* scip, /**< SCIP data structure */
776 SCIP_SEPADATA** sepadata /**< pointer to store separator data */
777 )
778{
779 assert(scip != NULL);
780 assert(sepadata != NULL);
781 assert(*sepadata != NULL);
782
783 /* free nonlinear row aggregations */
784 SCIP_CALL( sepadataFreeNlrows(scip, *sepadata) );
785
786 /* free LP interface */
787 if( (*sepadata)->lpi != NULL )
788 {
789 SCIP_CALL( SCIPlpiFree(&((*sepadata)->lpi)) );
790 (*sepadata)->lpisize = 0;
791 }
792
793 SCIPfreeBlockMemory(scip, sepadata);
794
795 return SCIP_OKAY;
796}
797
798/** adds a nonlinear row aggregation to the separator data */
799static
801 SCIP* scip, /**< SCIP data structure */
802 SCIP_SEPADATA* sepadata, /**< separator data */
803 SCIP_NLROWAGGR* nlrowaggr /**< non-linear row aggregation */
804 )
805{
806 int i;
807
808 assert(scip != NULL);
809 assert(sepadata != NULL);
810 assert(nlrowaggr != NULL);
811
812 if( sepadata->nlrowaggrssize == 0 )
813 {
814 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &sepadata->nlrowaggrs, 2) ); /*lint !e506*/
815 sepadata->nlrowaggrssize = 2;
816 }
817 else if( sepadata->nlrowaggrssize < sepadata->nnlrowaggrs + 1 )
818 {
819 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->nlrowaggrs, sepadata->nlrowaggrssize, 2 * sepadata->nlrowaggrssize) ); /*lint !e506 !e647*/
820 sepadata->nlrowaggrssize *= 2;
821 assert(sepadata->nlrowaggrssize >= sepadata->nnlrowaggrs + 1);
822 }
823
824 sepadata->nlrowaggrs[ sepadata->nnlrowaggrs ] = nlrowaggr;
825 ++(sepadata->nnlrowaggrs);
826
827 /* update maximum e.c. aggregation size */
828 for( i = 0; i < nlrowaggr->necaggr; ++i )
829 sepadata->maxecsize = MAX(sepadata->maxecsize, nlrowaggr->ecaggr[i]->nvars);
830
831#ifdef SCIP_STATISTIC
832 /* update statistics */
833 if( nlrowaggr->rhsaggr )
834 ++(sepadata->nrhsnlrowaggrs);
835 else
836 ++(sepadata->nlhsnlrowaggrs);
837#endif
838
839 return SCIP_OKAY;
840}
841
842/** returns min{val-lb,ub-val} / (ub-lb) */
843static
845 SCIP* scip, /**< SCIP data structure */
846 SCIP_Real val, /**< solution value */
847 SCIP_Real lb, /**< lower bound */
848 SCIP_Real ub /**< upper bound */
849 )
850{
851 if( SCIPisFeasEQ(scip, lb, ub) )
852 return 0.0;
853
854 /* adjust */
855 val = MAX(val, lb);
856 val = MIN(val, ub);
857
858 return MIN(ub - val, val - lb) / (ub - lb);
859}
860
861/** creates an MIP to search for cycles with an odd number of positive edges in the graph representation of a nonlinear row
862 *
863 * The model uses directed binary arc flow variables.
864 * We introduce for all quadratic elements a forward and backward edge.
865 * If the term is quadratic (e.g., loop in the graph) we fix the corresponding variables to zero.
866 * This leads to an easy mapping between quadratic elements and the variables of the MIP.
867 */
868static
870 SCIP* scip, /**< SCIP data structure */
871 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
872 SCIP_SEPADATA* sepadata, /**< separator data */
873 SCIP_NLROW* nlrow, /**< nonlinear row */
874 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
875 * lhs <= g(x) (FALSE) */
876 SCIP_VAR** forwardarcs, /**< array to store all forward arc variables */
877 SCIP_VAR** backwardarcs, /**< array to store all backward arc variables */
878 SCIP_Real* nodeweights, /**< weights for each node of the graph */
879 int* nedges, /**< pointer to store the number of nonexcluded edges in the graph */
880 int* narcs /**< pointer to store the number of created arc variables (number of square and bilinear terms) */
881 )
882{
883 SCIP_VAR** oddcyclearcs;
884 SCIP_CONS** flowcons;
885 SCIP_CONS* cyclelengthcons;
886 SCIP_CONS* oddcyclecons;
887 char name[SCIP_MAXSTRLEN];
888 SCIP_EXPR* expr;
889 int noddcyclearcs;
890 int nnodes;
891 int nquadexprs;
892 int nbilinexprs;
893 int i;
894 int arcidx;
895
896 assert(subscip != NULL);
897 assert(forwardarcs != NULL);
898 assert(backwardarcs != NULL);
899 assert(nedges != NULL);
900 assert(sepadata->minaggrsize <= sepadata->maxaggrsize);
901
902 expr = SCIPnlrowGetExpr(nlrow);
903 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, &nbilinexprs, NULL, NULL);
904
905 nnodes = nquadexprs;
906 *nedges = 0;
907 *narcs = 0;
908
909 assert(nnodes > 0);
910
911 noddcyclearcs = 0;
912 SCIP_CALL( SCIPallocBufferArray(subscip, &oddcyclearcs, 2*nbilinexprs) );
913
914 /* create problem with default plug-ins */
915 SCIP_CALL( SCIPcreateProbBasic(subscip, "E.C. aggregation MIP") );
918
919 /* create forward and backward arc variables */
920 for( i = 0; i < nquadexprs; ++i )
921 {
922 SCIP_EXPR* qterm;
923 SCIP_Real coef;
924 int nadjbilin;
925 int* adjbilin;
926 int j;
927
928 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
929
930 if( !SCIPisZero(scip, coef) )
931 {
932 /* squares (loops) are fixed to zero */
933 SCIPdebugMsg(scip, "edge {%d,%d} = {%s,%s} coeff=%e edgeweight=0\n", i, i,
935 coef);
936
937 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, i);
938 SCIP_CALL( SCIPcreateVarBasic(subscip, &forwardarcs[*narcs], name, 0.0, 0.0, 0.01, SCIP_VARTYPE_BINARY) );
939 SCIP_CALL( SCIPaddVar(subscip, forwardarcs[*narcs]) );
940
941 SCIP_CALL( SCIPcreateVarBasic(subscip, &backwardarcs[*narcs], name, 0.0, 0.0, 0.01, SCIP_VARTYPE_BINARY) );
942 SCIP_CALL( SCIPaddVar(subscip, backwardarcs[*narcs]) );
943
944 ++*narcs;
945 }
946
947 for( j = 0 ; j < nadjbilin; ++j )
948 {
949 SCIP_EXPR* qterm1;
950 SCIP_EXPR* qterm2;
951 int pos2;
952 SCIP_Real edgeweight;
953 SCIP_CONS* noparallelcons;
954
955 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
956
957 /* handle qterm == qterm2 later */
958 if( qterm1 != qterm )
959 continue;
960
961 edgeweight = nodeweights[i] + nodeweights[pos2];
962 SCIPdebugMsg(scip, "edge {%d,%d} = {%s,%s} coeff=%e edgeweight=%e\n", i, pos2,
964 coef, edgeweight);
965
966 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, pos2);
967 SCIP_CALL( SCIPcreateVarBasic(subscip, &forwardarcs[*narcs], name, 0.0, 1.0, 0.01 + edgeweight, SCIP_VARTYPE_BINARY) );
968 SCIP_CALL( SCIPaddVar(subscip, forwardarcs[*narcs]) );
969
970 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, pos2);
971 SCIP_CALL( SCIPcreateVarBasic(subscip, &backwardarcs[*narcs], name, 0.0, 1.0, 0.01 + edgeweight, SCIP_VARTYPE_BINARY) );
972 SCIP_CALL( SCIPaddVar(subscip, backwardarcs[*narcs]) );
973
974 ++(*nedges);
975
976 /* store all arcs which are important for the odd cycle property (no loops) */
977 if( rhsaggr && SCIPisPositive(scip, coef) )
978 {
979 assert(noddcyclearcs < 2*nbilinexprs-1);
980 oddcyclearcs[noddcyclearcs++] = forwardarcs[i];
981 oddcyclearcs[noddcyclearcs++] = backwardarcs[i];
982 }
983
984 if( !rhsaggr && SCIPisNegative(scip, coef) )
985 {
986 assert(noddcyclearcs < 2*nbilinexprs-1);
987 oddcyclearcs[noddcyclearcs++] = forwardarcs[i];
988 oddcyclearcs[noddcyclearcs++] = backwardarcs[i];
989 }
990
991 /* add constraints to ensure no parallel edges */
992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_noparalleledges");
993 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &noparallelcons, name, 0, NULL, NULL, 0.0, 1.0) );
994 SCIP_CALL( SCIPaddCoefLinear(subscip, noparallelcons, forwardarcs[*narcs], 1.0) );
995 SCIP_CALL( SCIPaddCoefLinear(subscip, noparallelcons, backwardarcs[*narcs], 1.0) );
996 SCIP_CALL( SCIPaddCons(subscip, noparallelcons) );
997 SCIP_CALL( SCIPreleaseCons(subscip, &noparallelcons) );
998
999 ++*narcs;
1000 }
1001 }
1002 assert(*narcs > 0);
1003
1004 /* odd cycle property constraint */
1005 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_oddcycle");
1006 SCIP_CALL( SCIPcreateConsBasicXor(subscip, &oddcyclecons, name, TRUE, noddcyclearcs, oddcyclearcs) );
1007 SCIP_CALL( SCIPaddCons(subscip, oddcyclecons) );
1008 SCIP_CALL( SCIPreleaseCons(subscip, &oddcyclecons) );
1009 SCIPfreeBufferArray(subscip, &oddcyclearcs);
1010
1011 /* cycle length constraint */
1012 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_cyclelength");
1013 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &cyclelengthcons, name, 0, NULL, NULL,
1014 (SCIP_Real) sepadata->minaggrsize, (SCIP_Real) sepadata->maxaggrsize) );
1015
1016 for( i = 0; i < *narcs; ++i )
1017 {
1018 SCIP_CALL( SCIPaddCoefLinear(subscip, cyclelengthcons, forwardarcs[i], 1.0) );
1019 SCIP_CALL( SCIPaddCoefLinear(subscip, cyclelengthcons, backwardarcs[i], 1.0) );
1020 }
1021
1022 SCIP_CALL( SCIPaddCons(subscip, cyclelengthcons) );
1023 SCIP_CALL( SCIPreleaseCons(subscip, &cyclelengthcons) );
1024
1025 /* create flow conservation constraints */
1026 SCIP_CALL( SCIPallocBufferArray(subscip, &flowcons, nnodes) );
1027
1028 for( i = 0; i < nnodes; ++i )
1029 {
1030 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_flowconservation#%d", i);
1031 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &flowcons[i], name, 0, NULL, NULL, 0.0, 0.0) );
1032 }
1033
1034 arcidx = 0;
1035 for( i = 0; i < nquadexprs; ++i )
1036 {
1037 SCIP_EXPR* qterm;
1038 SCIP_Real coef;
1039 int nadjbilin;
1040 int* adjbilin;
1041 int j;
1042
1043 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
1044
1045 if( !SCIPisZero(scip, coef) )
1046 ++arcidx;
1047
1048 for( j = 0 ; j < nadjbilin; ++j )
1049 {
1050 SCIP_EXPR* qterm1;
1051 int pos2;
1052
1053 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
1054
1055 /* handle qterm == qterm2 later */
1056 if( qterm1 != qterm )
1057 continue;
1058
1059 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[i], forwardarcs[arcidx], 1.0) );
1060 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[i], backwardarcs[arcidx], -1.0) );
1061
1062 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[pos2], forwardarcs[arcidx], -1.0) );
1063 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[pos2], backwardarcs[arcidx], 1.0) );
1064
1065 ++arcidx;
1066 }
1067 }
1068 assert(arcidx == *narcs);
1069
1070 for( i = 0; i < nnodes; ++i )
1071 {
1072 SCIP_CALL( SCIPaddCons(subscip, flowcons[i]) );
1073 SCIP_CALL( SCIPreleaseCons(subscip, &flowcons[i]) );
1074 }
1075
1076 SCIPfreeBufferArray(subscip, &flowcons);
1077
1078 return SCIP_OKAY;
1079}
1080
1081/** fixed all arc variables (u,v) for which u or v is already in an edge-concave aggregation */
1082static
1084 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
1085 SCIP_NLROW* nlrow, /**< nonlinear row */
1086 SCIP_VAR** forwardarcs, /**< forward arc variables */
1087 SCIP_VAR** backwardarcs, /**< backward arc variables */
1088 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
1089 int* nedges /**< pointer to store the number of nonexcluded edges */
1090 )
1091{
1092 SCIP_EXPR* expr;
1093 int nquadexprs;
1094 int arcidx;
1095 int i;
1096
1097 assert(subscip != NULL);
1098 assert(nlrow != NULL);
1099 assert(forwardarcs != NULL);
1100 assert(backwardarcs != NULL);
1101 assert(quadvar2aggr != NULL);
1102 assert(nedges != NULL);
1103
1104 SCIP_CALL( SCIPfreeTransform(subscip) );
1105
1106 /* recompute the number of edges */
1107 *nedges = 0;
1108
1109 expr = SCIPnlrowGetExpr(nlrow);
1110 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
1111
1112 /* fix each arc to 0 if at least one of its nodes is contained in an e.c. aggregation */
1113 arcidx = 0;
1114 for( i = 0; i < nquadexprs; ++i )
1115 {
1116 SCIP_EXPR* qterm;
1117 SCIP_Real coef;
1118 int nadjbilin;
1119 int* adjbilin;
1120 int j;
1121
1122 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
1123
1124 if( !SCIPisZero(subscip, coef) )
1125 {
1126 if( quadvar2aggr[i] != -1 )
1127 {
1128 SCIP_CALL( SCIPchgVarUb(subscip, forwardarcs[arcidx], 0.0) );
1129 SCIP_CALL( SCIPchgVarUb(subscip, backwardarcs[arcidx], 0.0) );
1130 }
1131 ++arcidx;
1132 }
1133
1134 for( j = 0 ; j < nadjbilin; ++j )
1135 {
1136 SCIP_EXPR* qterm1;
1137 int pos2;
1138
1139 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
1140
1141 /* handle qterm == qterm2 later */
1142 if( qterm1 != qterm )
1143 continue;
1144
1145 if( quadvar2aggr[i] != -1 || quadvar2aggr[pos2] != -1 )
1146 {
1147 SCIP_CALL( SCIPchgVarUb(subscip, forwardarcs[arcidx], 0.0) );
1148 SCIP_CALL( SCIPchgVarUb(subscip, backwardarcs[arcidx], 0.0) );
1149 }
1150 else
1151 ++*nedges;
1152
1153 ++arcidx;
1154 }
1155 }
1156
1157 return SCIP_OKAY;
1158}
1159
1160/** stores the best edge-concave aggregation found by the MIP model */
1161static
1163 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
1164 SCIP_NLROW* nlrow, /**< nonlinear row */
1165 SCIP_VAR** forwardarcs, /**< forward arc variables */
1166 SCIP_VAR** backwardarcs, /**< backward arc variables */
1167 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
1168 int nfoundsofar /**< number of e.c. aggregation found so far */
1169 )
1170{
1171 SCIP_SOL* sol;
1172 SCIP_EXPR* expr;
1173 int nquadexprs;
1174 int arcidx;
1175 int i;
1176
1177 assert(subscip != NULL);
1178 assert(nlrow != NULL);
1179 assert(forwardarcs != NULL);
1180 assert(backwardarcs != NULL);
1181 assert(quadvar2aggr != NULL);
1182 assert(nfoundsofar >= 0);
1183 assert(SCIPgetStatus(subscip) != SCIP_STATUS_INFEASIBLE);
1184 assert(SCIPgetStatus(subscip) != SCIP_STATUS_UNBOUNDED);
1185 assert(SCIPgetStatus(subscip) != SCIP_STATUS_INFORUNBD);
1186 assert(SCIPgetNSols(subscip) > 0);
1187
1188 sol = SCIPgetBestSol(subscip);
1189 assert(sol != NULL);
1190
1191 expr = SCIPnlrowGetExpr(nlrow);
1192 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
1193
1194 /* fix each arc to 0 if at least one of its nodes is contained in an e.c. aggregation */
1195 arcidx = 0;
1196 for( i = 0; i < nquadexprs; ++i )
1197 {
1198 SCIP_EXPR* qterm;
1199 SCIP_Real coef;
1200 int nadjbilin;
1201 int* adjbilin;
1202 int j;
1203
1204 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
1205
1206 if( !SCIPisZero(subscip, coef) )
1207 {
1208 if( SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, forwardarcs[arcidx]), 0.5) ||
1209 SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, backwardarcs[arcidx]), 0.5) )
1210 {
1211 assert(quadvar2aggr[i] == -1 || quadvar2aggr[i] == nfoundsofar);
1212 quadvar2aggr[i] = nfoundsofar;
1213 }
1214
1215 ++arcidx;
1216 }
1217
1218 for( j = 0; j < nadjbilin; ++j )
1219 {
1220 SCIP_EXPR* qterm1;
1221 int pos2;
1222
1223 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
1224
1225 /* handle qterm == qterm2 later */
1226 if( qterm1 != qterm )
1227 continue;
1228
1229 if( SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, forwardarcs[arcidx]), 0.5) ||
1230 SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, backwardarcs[arcidx]), 0.5) )
1231 {
1232 assert(quadvar2aggr[i] == -1 || quadvar2aggr[i] == nfoundsofar);
1233 assert(quadvar2aggr[pos2] == -1 || quadvar2aggr[pos2] == nfoundsofar);
1234
1235 quadvar2aggr[i] = nfoundsofar;
1236 quadvar2aggr[pos2] = nfoundsofar;
1237 }
1238
1239 ++arcidx;
1240 }
1241 }
1242
1243 return SCIP_OKAY;
1244}
1245
1246/** searches for edge-concave aggregations with a MIP model based on binary flow variables */
1247static
1249 SCIP* subscip, /**< SCIP data structure */
1250 SCIP_Real timelimit, /**< time limit to solve the MIP */
1251 int nedges, /**< number of nonexcluded undirected edges */
1252 SCIP_Bool* aggrleft, /**< pointer to store if there might be a left aggregation */
1253 SCIP_Bool* found /**< pointer to store if we have found an aggregation */
1254 )
1255{
1256 assert(subscip != NULL);
1257 assert(aggrleft != NULL);
1258 assert(found != NULL);
1259 assert(nedges >= 0);
1260
1261 *aggrleft = TRUE;
1262 *found = FALSE;
1263
1264 if( SCIPisLE(subscip, timelimit, 0.0) )
1265 return SCIP_OKAY;
1266
1267 /* set working limits */
1268 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1269 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/totalnodes", SUBSCIP_NODELIMIT) );
1270
1271 /* set heuristics to aggressive */
1273
1274 /* disable output to console in optimized mode, enable in SCIP's debug mode */
1275#ifdef SCIP_DEBUG
1276 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
1277 SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 1) );
1278#else
1279 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1280#endif
1281
1282 SCIP_CALL( SCIPsolve(subscip) );
1283
1284 /* no more aggregation left if the MIP is infeasible */
1285 if( SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE )
1286 {
1287 *found = FALSE;
1288 *aggrleft = FALSE;
1289 return SCIP_OKAY;
1290 }
1291
1292 if( SCIPgetNSols(subscip) > 0 )
1293 {
1294 *found = TRUE;
1295 *aggrleft = TRUE;
1296
1297#ifdef SCIP_DEBUG
1298 if( SCIPgetNSols(subscip) > 0 )
1299 {
1300 SCIP_CALL( SCIPprintSol(subscip, SCIPgetBestSol(subscip), NULL , FALSE) );
1301 }
1302#endif
1303 }
1304
1305 return SCIP_OKAY;
1306}
1307
1308/** creates a tclique graph from a given nonlinear row
1309 *
1310 * SCIP's clique code can only handle integer node weights; all node weights are scaled by a factor of 100; since the
1311 * clique code ignores nodes with weight of zero, we add an offset of 100 to each weight
1312 */
1313static
1315 SCIP_NLROW* nlrow, /**< nonlinear row */
1316 TCLIQUE_GRAPH** graph, /**< TCLIQUE graph structure */
1317 SCIP_Real* nodeweights /**< weights for each quadratic variable (nodes in the graph) */
1318 )
1319{
1320 SCIP_EXPR* expr;
1321 int nquadexprs;
1322 int i;
1323
1324 assert(graph != NULL);
1325 assert(nlrow != NULL);
1326
1327 /* create the tclique graph */
1328 if( !tcliqueCreate(graph) )
1329 {
1330 SCIPerrorMessage("could not create clique graph\n");
1331 return SCIP_ERROR;
1332 }
1333
1334 expr = SCIPnlrowGetExpr(nlrow);
1335 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
1336
1337 /* add all nodes to the tclique graph */
1338 for( i = 0; i < nquadexprs; ++i )
1339 {
1340 int nodeweight;
1341
1342 /* note: clique code can only handle integer weights */
1343 nodeweight = 100 + (int)(100 * nodeweights[i]);
1344 /* SCIPdebugMsg(scip, "%d (%s): nodeweight %d \n", i, SCIPvarGetName(SCIPnlrowGetQuadVars(nlrow)[i]), nodeweight); */
1345
1346 if( !tcliqueAddNode(*graph, i, nodeweight) )
1347 {
1348 SCIPerrorMessage("could not add node to clique graph\n");
1349 return SCIP_ERROR;
1350 }
1351 }
1352
1353 /* add all edges */
1354 for( i = 0; i < nquadexprs; ++i )
1355 {
1356 SCIP_EXPR* qterm;
1357 int nadjbilin;
1358 int* adjbilin;
1359 int j;
1360
1361 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, &nadjbilin, &adjbilin, NULL);
1362
1363 for( j = 0; j < nadjbilin; ++j )
1364 {
1365 SCIP_EXPR* qterm1;
1366 SCIP_EXPR* qterm2;
1367 int pos2;
1368
1369 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, NULL, &pos2, NULL);
1370
1371 /* handle qterm == qterm2 later */
1372 if( qterm1 != qterm )
1373 continue;
1374
1375#ifdef SCIP_DEBUG_DETAILED
1376 SCIPdebugMessage(" add edge (%d, %d) = (%s,%s) to tclique graph\n",
1379#endif
1380
1381 if( !tcliqueAddEdge(*graph, i, pos2) )
1382 {
1383 SCIPerrorMessage("could not add edge to clique graph\n");
1384 return SCIP_ERROR;
1385 }
1386 }
1387 }
1388
1389 /* flush the clique graph */
1390 if( !tcliqueFlush(*graph) )
1391 {
1392 SCIPerrorMessage("could not flush the clique graph\n");
1393 return SCIP_ERROR;
1394 }
1395
1396 return SCIP_OKAY;
1397}
1398
1399/** searches for edge-concave aggregations by computing cliques in the graph representation of a given nonlinear row
1400 *
1401 * update graph, compute clique, store clique; after computing a clique we heuristically check if the clique contains
1402 * at least one good cycle
1403 */
1404static
1406 SCIP* scip, /**< SCIP data structure */
1407 TCLIQUE_GRAPH* graph, /**< TCLIQUE graph structure */
1408 SCIP_SEPADATA* sepadata, /**< separator data */
1409 SCIP_NLROW* nlrow, /**< nonlinear row */
1410 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
1411 int nfoundsofar, /**< number of e.c. aggregation found so far */
1412 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
1413 * lhs <= g(x) (FALSE) */
1414 SCIP_Bool* foundaggr, /**< pointer to store if we have found an aggregation */
1415 SCIP_Bool* foundclique /**< pointer to store if we have found a clique */
1416 )
1417{
1418 SCIP_HASHMAP* cliquemap;
1419 TCLIQUE_STATUS status;
1420 SCIP_EXPR* expr;
1421 int nquadexprs;
1422 int* maxcliquenodes;
1423 int* degrees;
1424 int nmaxcliquenodes;
1425 int maxcliqueweight;
1426 int noddcycleedges;
1427 int ntwodegrees;
1428 int aggrsize;
1429 int i;
1430
1431 assert(graph != NULL);
1432 assert(nfoundsofar >= 0);
1433 assert(foundaggr != NULL);
1434 assert(foundclique != NULL);
1435
1436 cliquemap = NULL;
1437 *foundaggr = FALSE;
1438 *foundclique = FALSE;
1439
1440 expr = SCIPnlrowGetExpr(nlrow);
1441 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
1442 assert(nquadexprs == tcliqueGetNNodes(graph));
1443
1444 /* exclude all nodes which are already in an edge-concave aggregation (no flush is needed) */
1445 for( i = 0; i < nquadexprs; ++i )
1446 {
1447 if( quadvar2aggr[i] != -1 )
1448 {
1449 SCIPdebugMsg(scip, "exclude node %d from clique graph\n", i);
1450 tcliqueChangeWeight(graph, i, 0);
1451 }
1452 }
1453
1454 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliquenodes, nquadexprs) );
1455
1456 /* solve clique problem */
1457 tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes, graph, NULL, NULL,
1458 maxcliquenodes, &nmaxcliquenodes, &maxcliqueweight, CLIQUE_MAXFIRSTNODEWEIGHT, CLIQUE_MINWEIGHT,
1460
1461 if( status != TCLIQUE_OPTIMAL || nmaxcliquenodes < sepadata->minaggrsize )
1462 goto TERMINATE;
1463
1464 *foundclique = TRUE;
1465 aggrsize = MIN(sepadata->maxaggrsize, nmaxcliquenodes);
1466 SCIP_CALL( SCIPhashmapCreate(&cliquemap, SCIPblkmem(scip), aggrsize) );
1467
1468 for( i = 0; i < aggrsize; ++i )
1469 {
1470 SCIP_CALL( SCIPhashmapInsertInt(cliquemap, (void*) (size_t) maxcliquenodes[i], 0) ); /*lint !e571*/
1471 }
1472
1473 /* count the degree of good cycle edges for each node in the clique */
1474 SCIP_CALL( SCIPallocBufferArray(scip, &degrees, aggrsize) );
1475 BMSclearMemoryArray(degrees, aggrsize);
1476 ntwodegrees = 0;
1477
1478 /* count the number of positive or negative edges (depending on <= rhs or >= lhs) */
1479 noddcycleedges = 0;
1480 for( i = 0; i < nquadexprs; ++i )
1481 {
1482 SCIP_Bool isoddcycleedge;
1483 SCIP_EXPR* qterm;
1484 SCIP_Real coef;
1485 int nadjbilin;
1486 int* adjbilin;
1487 int j;
1488
1489 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
1490
1491 isoddcycleedge = (rhsaggr && SCIPisPositive(scip, coef)) || (!rhsaggr && SCIPisNegative(scip, coef));
1492
1493 if( isoddcycleedge && SCIPhashmapExists(cliquemap, (void*) (size_t) i) )
1494 {
1495 ++noddcycleedges;
1496 ++degrees[i];
1497 }
1498
1499 for( j = 0; j < nadjbilin; ++j )
1500 {
1501 SCIP_EXPR* qterm1;
1502 SCIP_EXPR* qterm2;
1503 int pos2;
1504
1505 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
1506
1507 /* handle qterm == qterm2 later */
1508 if( qterm1 != qterm )
1509 continue;
1510
1511 isoddcycleedge = (rhsaggr && SCIPisPositive(scip, coef)) || (!rhsaggr && SCIPisNegative(scip, coef));
1512
1513 if( isoddcycleedge
1514 && SCIPhashmapExists(cliquemap, (void*) (size_t) i)
1515 && SCIPhashmapExists(cliquemap, (void*) (size_t) pos2) )
1516 {
1517 ++noddcycleedges;
1518 ++degrees[i];
1519 ++degrees[pos2];
1520 }
1521 }
1522 }
1523
1524 /* count the number of nodes with exactly two incident odd cycle edges */
1525 for( i = 0; i < aggrsize; ++i )
1526 if( degrees[i] == 2 )
1527 ++ntwodegrees;
1528
1529 /* check cases for which we are sure that there are no good cycles in the clique */
1530 if( noddcycleedges == 0 || (aggrsize == 3 && noddcycleedges == 2) || (aggrsize == 4 && ntwodegrees == 4) )
1531 *foundaggr = FALSE;
1532 else
1533 *foundaggr = TRUE;
1534
1535 /* add the found clique as an edge-concave aggregation or exclude the nodes from the remaining search */
1536 for( i = 0; i < aggrsize; ++i )
1537 {
1538 quadvar2aggr[ maxcliquenodes[i] ] = *foundaggr ? nfoundsofar : -2;
1539 SCIPdebugMsg(scip, "%s %d\n", *foundaggr ? "aggregate node: " : "exclude node: ", maxcliquenodes[i]);
1540 }
1541
1542 SCIPfreeBufferArray(scip, &degrees);
1543
1544TERMINATE:
1545 if( cliquemap != NULL )
1546 SCIPhashmapFree(&cliquemap);
1547 SCIPfreeBufferArray(scip, &maxcliquenodes);
1548
1549 return SCIP_OKAY;
1550}
1551
1552/** helper function for searchEcAggr() */
1553static
1555 SCIP* scip, /**< SCIP data structure */
1556 SCIP* subscip, /**< sub-SCIP data structure */
1557 SCIP_SEPADATA* sepadata, /**< separator data */
1558 SCIP_NLROW* nlrow, /**< nonlinear row */
1559 SCIP_SOL* sol, /**< current solution (might be NULL) */
1560 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or g(x) >= lhs (FALSE) */
1561 int* quadvar2aggr, /**< array to store for each quadratic variable in which edge-concave
1562 * aggregation it is stored (< 0: in no aggregation); size has to be at
1563 * least SCIPnlrowGetNQuadVars(nlrow) */
1564 int* nfound /**< pointer to store the number of found e.c. aggregations */
1565 )
1566{
1567 TCLIQUE_GRAPH* graph = NULL;
1568 SCIP_EXPR* expr;
1569 SCIP_VAR** forwardarcs;
1570 SCIP_VAR** backwardarcs;
1571 SCIP_Real* nodeweights;
1572 SCIP_Real timelimit;
1573 SCIP_RETCODE retcode;
1574 int nunsucces = 0;
1575 int nedges = 0;
1576 int narcs;
1577 int nquadvars;
1578 int nbilinexprs;
1579 int i;
1580
1581 assert(subscip != NULL);
1582 assert(quadvar2aggr != NULL);
1583 assert(nfound != NULL);
1584
1585 expr = SCIPnlrowGetExpr(nlrow);
1586 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, &nbilinexprs, NULL, NULL);
1587
1588 retcode = SCIP_OKAY;
1589 *nfound = 0;
1590
1591 /* arrays to store all arc variables of the MIP model; note that we introduce variables even for loops in the graph
1592 * to have an easy mapping from the edges of the graph to the quadratic elements
1593 * nquadvars + nbilinexprs is an upper bound on the actual number of square and bilinear terms
1594 */
1595 SCIP_CALL( SCIPallocBufferArray(scip, &nodeweights, nquadvars) );
1596 SCIP_CALL( SCIPallocBufferArray(scip, &forwardarcs, nquadvars + nbilinexprs) );
1597 SCIP_CALL( SCIPallocBufferArray(scip, &backwardarcs, nquadvars + nbilinexprs) );
1598
1599 /* initialize mapping from quadvars to e.c. aggregation index (-1: quadvar is in no aggregation); compute node
1600 * weights
1601 */
1602 for( i = 0; i < nquadvars; ++i )
1603 {
1604 SCIP_EXPR* qterm;
1605 SCIP_VAR* var;
1606
1607 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, NULL, NULL, NULL);
1608 assert(SCIPisExprVar(scip, qterm));
1609 var = SCIPgetVarExprVar(qterm);
1610
1611 quadvar2aggr[i] = -1;
1612 nodeweights[i] = phi(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
1613 SCIPdebugMsg(scip, "%s = %e (%e in [%e, %e])\n", SCIPvarGetName(var), nodeweights[i], SCIPgetSolVal(scip, sol, var),
1615 }
1616
1617 SCIP_CALL( createMIP(scip, subscip, sepadata, nlrow, rhsaggr, forwardarcs, backwardarcs, nodeweights, &nedges, &narcs) );
1618 assert(nedges >= 0);
1619 assert(narcs > 0);
1620 SCIPdebugMsg(scip, "nedges (without loops) = %d\n", nedges);
1621 SCIPdebugMsg(scip, "narcs (number of quadratic terms) = %d\n", narcs);
1622
1623 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1624
1625 /* main loop to search for edge-concave aggregations */
1626 while( !SCIPisStopped(scip) )
1627 {
1628 SCIP_Bool aggrleft;
1629 SCIP_Bool found;
1630
1631 SCIPdebugMsg(scip, "#remaining edges = %d\n", nedges);
1632
1633 /* not enough edges left */
1634 if( nedges < sepadata->minaggrsize )
1635 break;
1636
1637 /* check whether there is enough time left; update the remaining time */
1638 if( !SCIPisInfinity(scip, timelimit) )
1639 {
1640 timelimit -= SCIPgetSolvingTime(scip);
1641 if( timelimit <= 0.0 )
1642 {
1643 SCIPdebugMsg(scip, "skip aggregation search since no time left\n");
1644 goto TERMINATE;
1645 }
1646 }
1647
1648 /* 1.a - search for edge-concave aggregation with the help of the MIP model */
1649 SCIP_CALL( searchEcAggrWithMIP(subscip, timelimit, nedges, &aggrleft, &found) );
1650
1651 /* 1.b - there are no more edge-concave aggregations left */
1652 if( !aggrleft )
1653 {
1654 SCIPdebugMsg(scip, "no more aggregation left\n");
1655 break;
1656 }
1657
1658 if( found )
1659 {
1660 SCIP_CALL( storeAggrFromMIP(subscip, nlrow, forwardarcs, backwardarcs, quadvar2aggr, *nfound) );
1661 ++(*nfound);
1662 nunsucces = 0;
1663 }
1664 /* try to find an edge-concave aggregation by computing cliques */
1665 else
1666 {
1667 SCIP_Bool foundaggr;
1668 SCIP_Bool foundclique;
1669
1670 ++nunsucces;
1671
1672 /* create graph if necessary */
1673 if( graph == NULL )
1674 {
1675 SCIP_CALL_TERMINATE( retcode, createTcliqueGraph(nlrow, &graph, nodeweights), TERMINATE );
1676 }
1677
1678 /* 2.a - search and store a single edge-concave aggregation by computing a clique with a good cycle */
1679 SCIP_CALL_FINALLY( searchEcAggrWithCliques(scip, graph, sepadata, nlrow, quadvar2aggr, *nfound, rhsaggr,
1680 &foundaggr, &foundclique), tcliqueFree(&graph) );
1681
1682 if( foundaggr )
1683 {
1684 assert(foundclique);
1685 ++(*nfound);
1686 nunsucces = 0;
1687 }
1688 else
1689 ++nunsucces;
1690
1691 /* 2.b - no clique of at least minaggrsize size found */
1692 if( !foundclique )
1693 {
1694 assert(!foundaggr);
1695 SCIPdebugMsg(scip, "did not find a clique to exclude -> leave aggregation search\n");
1696 break;
1697 }
1698 }
1699
1700 /* leave the algorithm if we did not find something for maxstallrounds many iterations */
1701 if( nunsucces >= sepadata->maxstallrounds && *nfound == 0 )
1702 {
1703 SCIPdebugMsg(scip, "did not find an e.c. aggregation for %d iterations\n", nunsucces);
1704 break;
1705 }
1706
1707 /* exclude all edges used in the last aggregation and nodes found in the clique solution */
1708 SCIP_CALL_FINALLY( updateMIP(subscip, nlrow, forwardarcs, backwardarcs, quadvar2aggr, &nedges), tcliqueFree(&graph) );
1709 }
1710
1711TERMINATE:
1712
1713#ifdef SCIP_DEBUG
1714 SCIPdebugMsg(scip, "aggregations found:\n");
1715 for( i = 0; i < nquadvars; ++i )
1716 {
1717 SCIPdebugMsg(scip, " %d in %d\n", i, quadvar2aggr[i]);
1718 }
1719#endif
1720
1721 /* free clique graph */
1722 if( graph != NULL )
1723 tcliqueFree(&graph);
1724
1725 /* free sub-SCIP */
1726 for( i = 0; i < narcs; ++i )
1727 {
1728 SCIP_CALL( SCIPreleaseVar(subscip, &forwardarcs[i]) );
1729 SCIP_CALL( SCIPreleaseVar(subscip, &backwardarcs[i]) );
1730 }
1731
1732 SCIPfreeBufferArray(scip, &backwardarcs);
1733 SCIPfreeBufferArray(scip, &forwardarcs);
1734 SCIPfreeBufferArray(scip, &nodeweights);
1735
1736 return retcode;
1737}
1738
1739/** computes a partitioning into edge-concave aggregations for a given (quadratic) nonlinear row
1740 *
1741 * Each aggregation has to contain a cycle with an odd number of positive weighted edges (good cycles) in the corresponding graph representation.
1742 * For this we use the following algorithm:
1743 * -# use a MIP model based on binary flow variables to compute good cycles and store the implied subgraphs as an e.c. aggr.
1744 * -# if we find a good cycle, store the implied subgraph, delete it from the graph representation and go to 1)
1745 * -# if the MIP model is infeasible (there are no good cycles), STOP
1746 * -# we compute a large clique C if the MIP model fails (because of working limits, etc)
1747 * -# if we find a good cycle in C, store the implied subgraph of C, delete it from the graph representation and go to 1)
1748 * -# if C is not large enough, STOP
1749 */
1750static
1752 SCIP* scip, /**< SCIP data structure */
1753 SCIP_SEPADATA* sepadata, /**< separator data */
1754 SCIP_NLROW* nlrow, /**< nonlinear row */
1755 SCIP_SOL* sol, /**< current solution (might be NULL) */
1756 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or g(x) >= lhs (FALSE) */
1757 int* quadvar2aggr, /**< array to store for each quadratic variable in which edge-concave
1758 * aggregation it is stored (< 0: in no aggregation); size has to be at
1759 * least SCIPnlrowGetNQuadVars(nlrow) */
1760 int* nfound /**< pointer to store the number of found e.c. aggregations */
1761 )
1762{
1763 SCIP* subscip;
1764 SCIP_RETCODE retcode;
1765
1766 /* create and set up a sub-SCIP */
1767 SCIP_CALL_FINALLY( SCIPcreate(&subscip), (void)SCIPfree(&subscip) );
1768
1769 retcode = doSeachEcAggr(scip, subscip, sepadata, nlrow, sol, rhsaggr, quadvar2aggr, nfound);
1770
1771 SCIP_CALL( SCIPfree(&subscip) );
1772 SCIP_CALL( retcode );
1773
1774 return SCIP_OKAY;
1775}
1776
1777/** returns whether a given nonlinear row can be used to compute edge-concave aggregations for which their convex
1778 * envelope could dominate the termwise bilinear relaxation
1779 *
1780 * This is the case if there exists at least one cycle with
1781 * an odd number of positive edges in the corresponding graph representation of the nonlinear row.
1782 */
1783static
1785 SCIP* scip, /**< SCIP data structure */
1786 SCIP_SEPADATA* sepadata, /**< separator data */
1787 SCIP_NLROW* nlrow, /**< nonlinear row representation of a nonlinear constraint */
1788 SCIP_Bool* rhscandidate, /**< pointer to store if we should compute edge-concave aggregations for
1789 * the <= rhs case */
1790 SCIP_Bool* lhscandidate /**< pointer to store if we should compute edge-concave aggregations for
1791 * the >= lhs case */
1792 )
1793{
1794 SCIP_EXPR* expr = NULL;
1795 SCIP_Bool takerow = FALSE;
1796 int nquadvars = 0;
1797 int* degrees;
1798 int ninterestingnodes;
1799 int nposedges;
1800 int nnegedges;
1801 int i;
1802
1803 assert(rhscandidate != NULL);
1804 assert(lhscandidate != NULL);
1805
1806 *rhscandidate = TRUE;
1807 *lhscandidate = TRUE;
1808
1809 /* check whether nlrow is in the NLP, is quadratic in variables, and there are enough quadratic variables */
1810 if( SCIPnlrowIsInNLP(nlrow) && SCIPnlrowGetExpr(nlrow) != NULL )
1811 {
1812 expr = SCIPnlrowGetExpr(nlrow);
1813 SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, &takerow) );
1814 }
1815 if( takerow )
1816 takerow = SCIPexprAreQuadraticExprsVariables(expr);
1817 if( takerow )
1818 {
1819 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, NULL, NULL, NULL);
1820 takerow = nquadvars >= sepadata->minaggrsize;
1821 }
1822 if( !takerow )
1823 {
1824 *rhscandidate = FALSE;
1825 *lhscandidate = FALSE;
1826 return SCIP_OKAY;
1827 }
1828
1829 /* check for infinite rhs or lhs */
1831 *rhscandidate = FALSE;
1833 *lhscandidate = FALSE;
1834
1835 SCIP_CALL( SCIPallocClearBufferArray(scip, &degrees, nquadvars) );
1836
1837 ninterestingnodes = 0;
1838 nposedges = 0;
1839 nnegedges = 0;
1840
1841 for( i = 0; i < nquadvars; ++i )
1842 {
1843 SCIP_EXPR* qterm;
1844 SCIP_VAR* var1;
1845 int nadjbilin;
1846 int* adjbilin;
1847 int j;
1848
1849 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, &nadjbilin, &adjbilin, NULL);
1850 assert(SCIPisExprVar(scip, qterm));
1851
1852 var1 = SCIPgetVarExprVar(qterm);
1853
1854 /* do not consider global fixed variables */
1856 continue;
1857
1858 for( j = 0; j < nadjbilin; ++j )
1859 {
1860 SCIP_EXPR* qterm1;
1861 SCIP_EXPR* qterm2;
1862 SCIP_VAR* var2;
1863 SCIP_Real coef;
1864 int pos2;
1865
1866 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
1867
1868 if( qterm1 != qterm )
1869 continue;
1870
1871 var2 = SCIPgetVarExprVar(qterm2);
1872
1873 /* do not consider loops or global fixed variables */
1875 continue;
1876
1877 ++degrees[i];
1878 ++degrees[pos2];
1879
1880 /* count the number of nodes with a degree of at least 2 */
1881 if( degrees[i] == 2 )
1882 ++ninterestingnodes;
1883 if( degrees[pos2] == 2 )
1884 ++ninterestingnodes;
1885
1886 nposedges += SCIPisPositive(scip, coef) ? 1 : 0;
1887 nnegedges += SCIPisNegative(scip, coef) ? 1 : 0;
1888 }
1889 }
1890
1891 SCIPfreeBufferArray(scip, &degrees);
1892
1893 SCIPdebugMsg(scip, "nlrow contains: %d edges\n", nposedges + nnegedges);
1894
1895 /* too many edges, too few edges, or to few nodes with degree at least 2 in the graph */
1896 if( nposedges + nnegedges > sepadata->maxbilinterms || nposedges + nnegedges < sepadata->minaggrsize
1897 || ninterestingnodes < sepadata->minaggrsize )
1898 {
1899 *rhscandidate = FALSE;
1900 *lhscandidate = FALSE;
1901 return SCIP_OKAY;
1902 }
1903
1904 /* check if there are enough positive/negative edges; for a 3-clique there has to be an odd number of those edges */
1905 if( nposedges == 0 || (nposedges + nnegedges == 3 && (nposedges % 2) == 0) )
1906 *rhscandidate = FALSE;
1907 if( nnegedges == 0 || (nposedges + nnegedges == 3 && (nnegedges % 2) == 0) )
1908 *lhscandidate = FALSE;
1909
1910 return SCIP_OKAY;
1911}
1912
1913/** finds and stores edge-concave aggregations for a given nonlinear row */
1914static
1916 SCIP* scip, /**< SCIP data structure */
1917 SCIP_SEPADATA* sepadata, /**< separator data */
1918 SCIP_NLROW* nlrow, /**< nonlinear row */
1919 SCIP_SOL* sol /**< current solution (might be NULL) */
1920 )
1921{
1922 int nquadvars;
1923 int* quadvar2aggr;
1924 SCIP_Bool rhscandidate;
1925 SCIP_Bool lhscandidate;
1926
1927 assert(scip != NULL);
1928 assert(nlrow != NULL);
1929 assert(sepadata != NULL);
1930
1931#ifdef SCIP_DEBUG
1932 SCIPdebugMsg(scip, "search for edge-concave aggregation for the nonlinear row: \n");
1933 SCIP_CALL( SCIPprintNlRow(scip, nlrow, NULL) );
1934#endif
1935
1936 /* check obvious conditions for existing cycles with an odd number of positive/negative edges */
1937 SCIP_CALL( isCandidate(scip, sepadata, nlrow, &rhscandidate, &lhscandidate) );
1938 SCIPdebugMsg(scip, "rhs candidate = %u lhs candidate = %u\n", rhscandidate, lhscandidate);
1939
1940 if( !rhscandidate && !lhscandidate )
1941 return SCIP_OKAY;
1942
1944 SCIP_CALL( SCIPallocBufferArray(scip, &quadvar2aggr, nquadvars) ); /*lint !e705*/
1945
1946 /* search for edge-concave aggregations (consider <= rhs) */
1947 if( rhscandidate )
1948 {
1949 SCIP_NLROWAGGR* nlrowaggr;
1950 int nfound;
1951
1952 assert(!SCIPisInfinity(scip, REALABS(SCIPnlrowGetRhs(nlrow))));
1953
1954 SCIPdebugMsg(scip, "consider <= rhs\n");
1955 SCIP_CALL( searchEcAggr(scip, sepadata, nlrow, sol, TRUE, quadvar2aggr, &nfound) );
1956
1957 if( nfound > 0 )
1958 {
1959 SCIP_CALL( nlrowaggrCreate(scip, nlrow, &nlrowaggr, quadvar2aggr, nfound, TRUE) );
1960 assert(nlrow != NULL);
1961 SCIPdebug(nlrowaggrPrint(scip, nlrowaggr));
1962 SCIP_CALL( sepadataAddNlrowaggr(scip, sepadata, nlrowaggr) );
1963 }
1964 }
1965
1966 /* search for edge-concave aggregations (consider <= lhs) */
1967 if( lhscandidate )
1968 {
1969 SCIP_NLROWAGGR* nlrowaggr;
1970 int nfound;
1971
1972 assert(!SCIPisInfinity(scip, REALABS(SCIPnlrowGetLhs(nlrow))));
1973
1974 SCIPdebugMsg(scip, "consider >= lhs\n");
1975 SCIP_CALL( searchEcAggr(scip, sepadata, nlrow, sol, FALSE, quadvar2aggr, &nfound) );
1976
1977 if( nfound > 0 )
1978 {
1979 SCIP_CALL( nlrowaggrCreate(scip, nlrow, &nlrowaggr, quadvar2aggr, nfound, FALSE) );
1980 assert(nlrow != NULL);
1981 SCIPdebug(nlrowaggrPrint(scip, nlrowaggr));
1982 SCIP_CALL( sepadataAddNlrowaggr(scip, sepadata, nlrowaggr) );
1983 }
1984 }
1985
1986 SCIPfreeBufferArray(scip, &quadvar2aggr);
1987 return SCIP_OKAY;
1988}
1989
1990/*
1991 * methods to compute edge-concave cuts
1992 */
1993
1994#ifdef SCIP_DEBUG
1995/** prints a given facet (candidate) */
1996static
1997void printFacet(
1998 SCIP* scip, /**< SCIP data structure */
1999 SCIP_VAR** vars, /**< variables contained in the edge-concave aggregation */
2000 int nvars, /**< number of variables contained in the edge-concave aggregation */
2001 SCIP_Real* facet, /**< current facet candidate */
2002 SCIP_Real facetval /**< facet evaluated at the current solution */
2003 )
2004{
2005 int i;
2006
2007 SCIPdebugMsg(scip, "print facet (val=%e): ", facetval);
2008 for( i = 0; i < nvars; ++i )
2009 SCIPdebugMsgPrint(scip, "%e %s + ", facet[i], SCIPvarGetName(vars[i]));
2010 SCIPdebugMsgPrint(scip, "%e\n", facet[nvars]);
2011}
2012#endif
2013
2014/** checks if a facet is really an underestimate for all corners of the domain [l,u]
2015 *
2016 * Because of numerics it can happen that a facet violates a corner of the domain.
2017 * To make the facet valid we subtract the maximum violation from the constant part of the facet.
2018 */
2019static
2021 SCIP* scip, /**< SCIP data structure */
2022 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
2023 SCIP_Real* fvals, /**< array containing all corner values of the aggregation */
2024 SCIP_Real* facet /**< current facet candidate (of dimension ecaggr->nvars + 1) */
2025 )
2026{
2027 SCIP_Real maxviolation;
2028 SCIP_Real val;
2029 unsigned int i;
2030 unsigned int ncorner;
2031 unsigned int prev;
2032
2033 assert(scip != NULL);
2034 assert(ecaggr != NULL);
2035 assert(fvals != NULL);
2036 assert(facet != NULL);
2037
2038 ncorner = (unsigned int) poweroftwo[ecaggr->nvars];
2039 maxviolation = 0.0;
2040
2041 /* check for the origin */
2042 val = facet[ecaggr->nvars];
2043 for( i = 0; i < (unsigned int) ecaggr->nvars; ++i )
2044 val += facet[i] * SCIPvarGetLbLocal(ecaggr->vars[i]);
2045
2046 /* update maximum violation */
2047 maxviolation = MAX(val - fvals[0], maxviolation);
2048 assert(SCIPisFeasEQ(scip, maxviolation, 0.0));
2049
2050 prev = 0;
2051 for( i = 1; i < ncorner; ++i )
2052 {
2053 unsigned int gray;
2054 unsigned int diff;
2055 unsigned int pos;
2056
2057 gray = i ^ (i >> 1);
2058 diff = gray ^ prev;
2059
2060 /* compute position of unique 1 of diff */
2061 pos = 0;
2062 while( (diff >>= 1) != 0 )
2063 ++pos;
2064
2065 if( gray > prev )
2066 val += facet[pos] * (SCIPvarGetUbLocal(ecaggr->vars[pos]) - SCIPvarGetLbLocal(ecaggr->vars[pos]));
2067 else
2068 val -= facet[pos] * (SCIPvarGetUbLocal(ecaggr->vars[pos]) - SCIPvarGetLbLocal(ecaggr->vars[pos]));
2069
2070 /* update maximum violation */
2071 maxviolation = MAX(val - fvals[gray], maxviolation);
2072 assert(SCIPisFeasEQ(scip, maxviolation, 0.0));
2073
2074 prev = gray;
2075 }
2076
2077 SCIPdebugMsg(scip, "maximum violation of facet: %2.8e\n", maxviolation);
2078
2079 /* there seem to be numerical problems if the violation is too large; in this case we reject the facet */
2080 if( maxviolation > ADJUSTFACETTOL )
2081 return FALSE;
2082
2083 /* adjust constant part of the facet */
2084 facet[ecaggr->nvars] -= maxviolation;
2085
2086 return TRUE;
2087}
2088
2089/** set up LP interface to solve LPs to compute the facet of the convex envelope */
2090static
2092 SCIP* scip, /**< SCIP data structure */
2093 SCIP_SEPADATA* sepadata /**< separation data */
2094 )
2095{
2096 SCIP_Real* obj;
2097 SCIP_Real* lb;
2098 SCIP_Real* ub;
2099 SCIP_Real* val;
2100 int* beg;
2101 int* ind;
2102 int nnonz;
2103 int ncols;
2104 int nrows;
2105 int i;
2106 int k;
2107
2108 assert(scip != NULL);
2109 assert(sepadata != NULL);
2110 assert(sepadata->nnlrowaggrs > 0);
2111
2112 /* LP interface has been already created with enough rows/columns*/
2113 if( sepadata->lpi != NULL && sepadata->lpisize >= sepadata->maxecsize )
2114 return SCIP_OKAY;
2115
2116 /* size of lpi is too small; reconstruct lpi */
2117 if( sepadata->lpi != NULL )
2118 {
2119 SCIP_CALL( SCIPlpiFree(&sepadata->lpi) );
2120 sepadata->lpi = NULL;
2121 }
2122
2123 assert(sepadata->lpi == NULL);
2124 SCIP_CALL( SCIPlpiCreate(&(sepadata->lpi), SCIPgetMessagehdlr(scip), "e.c. LP", SCIP_OBJSEN_MINIMIZE) );
2125 sepadata->lpisize = sepadata->maxecsize;
2126
2127 nrows = sepadata->maxecsize + 1;
2128 ncols = poweroftwo[nrows - 1];
2129 nnonz = (ncols * (nrows + 1)) / 2;
2130 k = 0;
2131
2132 /* allocate necessary memory */
2133 SCIP_CALL( SCIPallocBufferArray(scip, &obj, ncols) );
2134 SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
2135 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
2136 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
2137 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
2138 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
2139
2140 /* calculate nonzero entries in the LP; set obj, lb, and ub to zero */
2141 for( i = 0; i < ncols; ++i )
2142 {
2143 int row;
2144 int a;
2145
2146 obj[i] = 0.0;
2147 lb[i] = 0.0;
2148 ub[i] = 0.0;
2149
2150 SCIPdebugMsg(scip, "col %i starts at position %d\n", i, k);
2151 beg[i] = k;
2152 row = 0;
2153 a = 1;
2154
2155 /* iterate through the bit representation of i */
2156 while( a <= i )
2157 {
2158 if( (a & i) != 0 )
2159 {
2160 val[k] = 1.0;
2161 ind[k] = row;
2162
2163 SCIPdebugMsg(scip, " val[%d][%d] = 1 (position %d)\n", row, i, k);
2164
2165 ++k;
2166 }
2167
2168 a <<= 1; /*lint !e701*/
2169 ++row;
2170 assert(poweroftwo[row] == a);
2171 }
2172
2173 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
2174 val[k] = 1.0;
2175 ind[k] = nrows - 1;
2176 ++k;
2177 SCIPdebugMsg(scip, " val[%d][%d] = 1 (position %d)\n", nrows - 1, i, k);
2178 }
2179 assert(k == nnonz);
2180
2181 /*
2182 * add all columns to the LP interface
2183 * CPLEX needs the row to exist before adding columns, so we create the rows with dummy sides
2184 * note that the assert is not needed once somebody fixes the LPI
2185 */
2186 assert(nrows <= ncols);
2187 SCIP_CALL( SCIPlpiAddRows(sepadata->lpi, nrows, obj, obj, NULL, 0, NULL, NULL, NULL) );
2188 SCIP_CALL( SCIPlpiAddCols(sepadata->lpi, ncols, obj, lb, ub, NULL, nnonz, beg, ind, val) );
2189
2190 /* free allocated memory */
2197
2198 return SCIP_OKAY;
2199}
2200
2201/** evaluates an edge-concave aggregation at a corner of the domain [l,u] */
2202static
2204 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
2205 int k /**< k-th corner */
2206 )
2207{
2208 SCIP_Real val;
2209 int i;
2210
2211 assert(ecaggr != NULL);
2212 assert(k >= 0 && k < poweroftwo[ecaggr->nvars]);
2213
2214 val = 0.0;
2215
2216 for( i = 0; i < ecaggr->nterms; ++i )
2217 {
2218 SCIP_Real coef;
2219 SCIP_Real bound1;
2220 SCIP_Real bound2;
2221 int idx1;
2222 int idx2;
2223
2224 idx1 = ecaggr->termvars1[i];
2225 idx2 = ecaggr->termvars2[i];
2226 coef = ecaggr->termcoefs[i];
2227 assert(idx1 >= 0 && idx1 < ecaggr->nvars);
2228 assert(idx2 >= 0 && idx2 < ecaggr->nvars);
2229
2230 bound1 = ((poweroftwo[idx1]) & k) == 0 ? SCIPvarGetLbLocal(ecaggr->vars[idx1]) : SCIPvarGetUbLocal(ecaggr->vars[idx1]); /*lint !e661*/
2231 bound2 = ((poweroftwo[idx2]) & k) == 0 ? SCIPvarGetLbLocal(ecaggr->vars[idx2]) : SCIPvarGetUbLocal(ecaggr->vars[idx2]); /*lint !e661*/
2232
2233 val += coef * bound1 * bound2;
2234 }
2235
2236 return val;
2237}
2238
2239/** returns (val - lb) / (ub - lb) for a in [lb, ub] */
2240static
2242 SCIP* scip, /**< SCIP data structure */
2243 SCIP_Real lb, /**< lower bound */
2244 SCIP_Real ub, /**< upper bound */
2245 SCIP_Real val /**< value in [lb,ub] */
2246 )
2247{
2248 assert(scip != NULL);
2249 assert(!SCIPisInfinity(scip, -lb));
2250 assert(!SCIPisInfinity(scip, ub));
2251 assert(!SCIPisInfinity(scip, REALABS(val)));
2252 assert(!SCIPisFeasEQ(scip, ub - lb, 0.0)); /* this would mean that a variable has been fixed */
2253
2254 /* adjust val */
2255 val = MIN(val, ub);
2256 val = MAX(val, lb);
2257
2258 val = (val - lb) / (ub - lb);
2259 assert(val >= 0.0 && val <= 1.0);
2260
2261 return val;
2262}
2263
2264/** computes a facet of the convex envelope of an edge concave aggregation
2265 *
2266 * The algorithm solves the following LP:
2267 * \f{align}{
2268 * \min & \sum_i \lambda_i f(v_i)\\
2269 * s.t. & \sum_i \lambda_i v_i = x\\
2270 * & \sum_i \lambda_i = 1\\
2271 * & \lambda \geq 0
2272 * \f}
2273 * where \f$f\f$ is an edge concave function, \f$x\in [l,u]\f$ is a solution of the current relaxation, and \f$v_i\f$ are the vertices of \f$[l,u]\f$.
2274 * The method transforms the problem to the domain \f$[0,1]^n\f$, computes a facet, and transforms this facet to the
2275 * original space. The dual solution of the LP above are the coefficients of the facet.
2276 *
2277 * The complete algorithm works as follows:
2278 * -# compute \f$f(v_i)\f$ for each corner \f$v_i\f$ of \f$[l,u]\f$
2279 * -# set up the described LP for the transformed space
2280 * -# solve the LP and store the resulting facet for the transformed space
2281 * -# transform the facet to original space
2282 * -# adjust and check facet with the algorithm of Rikun et al.
2283 */
2284static
2286 SCIP* scip, /**< SCIP data structure */
2287 SCIP_SEPADATA* sepadata, /**< separation data */
2288 SCIP_SOL* sol, /**< solution (might be NULL) */
2289 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
2290 SCIP_Real* facet, /**< array to store the coefficients of the resulting facet; size has to be at least (ecaggr->nvars + 1) */
2291 SCIP_Real* facetval, /**< pointer to store the value of the facet evaluated at the current solution */
2292 SCIP_Bool* success /**< pointer to store if we have found a facet */
2293 )
2294{
2295 SCIP_Real* fvals;
2296 SCIP_Real* side;
2297 SCIP_Real* lb;
2298 SCIP_Real* ub;
2299 SCIP_Real perturbation;
2300 int* inds;
2301 int ncorner;
2302 int ncols;
2303 int nrows;
2304 int i;
2305
2306 assert(scip != NULL);
2307 assert(sepadata != NULL);
2308 assert(ecaggr != NULL);
2309 assert(facet != NULL);
2310 assert(facetval != NULL);
2311 assert(success != NULL);
2312 assert(ecaggr->nvars <= sepadata->maxecsize);
2313
2314 *facetval = -SCIPinfinity(scip);
2315 *success = FALSE;
2316
2317 /* create LP if this has not been done yet */
2318 SCIP_CALL( createLP(scip, sepadata) );
2319
2320 assert(sepadata->lpi != NULL);
2321 assert(sepadata->lpisize >= ecaggr->nvars);
2322
2323 SCIP_CALL( SCIPlpiGetNCols(sepadata->lpi, &ncols) );
2324 SCIP_CALL( SCIPlpiGetNRows(sepadata->lpi, &nrows) );
2325 ncorner = poweroftwo[ecaggr->nvars];
2326
2327 assert(ncorner <= ncols);
2328 assert(ecaggr->nvars + 1 <= nrows);
2329 assert(nrows <= ncols);
2330
2331 /* allocate necessary memory */
2332 SCIP_CALL( SCIPallocBufferArray(scip, &fvals, ncols) );
2333 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
2334 SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
2335 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
2336 SCIP_CALL( SCIPallocBufferArray(scip, &side, ncols) );
2337
2338 /*
2339 * 1. compute f(v_i) for each corner v_i of [l,u]
2340 * 2. set up the described LP for the transformed space
2341 */
2342 for( i = 0; i < ncols; ++i )
2343 {
2344 fvals[i] = i < ncorner ? evalCorner(ecaggr, i) : 0.0;
2345 inds[i] = i;
2346
2347 /* update bounds; fix variables to zero which are currently not in the LP */
2348 lb[i] = 0.0;
2349 ub[i] = i < ncorner ? 1.0 : 0.0;
2350 SCIPdebugMsg(scip, "bounds of LP col %d = [%e, %e]; obj = %e\n", i, lb[i], ub[i], fvals[i]);
2351 }
2352
2353 /* update lhs and rhs */
2354 perturbation = 0.001;
2355 for( i = 0; i < nrows; ++i )
2356 {
2357 /* note that the last row corresponds to sum_{j} \lambda_j = 1 */
2358 if( i < ecaggr->nvars )
2359 {
2360 SCIP_VAR* x;
2361
2362 x = ecaggr->vars[i];
2363 assert(x != NULL);
2364
2366
2367 /* perturb point to enforce an LP solution with ecaggr->nvars + 1 nonzero */
2368 side[i] += side[i] > perturbation ? -perturbation : perturbation;
2369 perturbation /= 1.2;
2370 }
2371 else
2372 {
2373 side[i] = (i == nrows - 1) ? 1.0 : 0.0;
2374 }
2375
2376 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, side[i], side[i]);
2377 }
2378
2379 /* update LP */
2380 SCIP_CALL( SCIPlpiChgObj(sepadata->lpi, ncols, inds, fvals) );
2381 SCIP_CALL( SCIPlpiChgBounds(sepadata->lpi, ncols, inds, lb, ub) );
2382 SCIP_CALL( SCIPlpiChgSides(sepadata->lpi, nrows, inds, side, side) );
2383
2384 /* free memory used to build the LP */
2385 SCIPfreeBufferArray(scip, &side);
2388 SCIPfreeBufferArray(scip, &inds);
2389
2390 /*
2391 * 3. solve the LP and store the resulting facet for the transformed space
2392 */
2393 if( USEDUALSIMPLEX ) /*lint !e774 !e506*/
2394 {
2395 SCIP_CALL( SCIPlpiSolveDual(sepadata->lpi) );
2396 }
2397 else
2398 {
2399 SCIP_CALL( SCIPlpiSolvePrimal(sepadata->lpi) );
2400 }
2401
2402 /* the dual solution corresponds to the coefficients of the facet in the transformed problem; note that it might be
2403 * the case that the dual solution has more components than the facet array
2404 */
2405 if( ecaggr->nvars + 1 == ncols )
2406 {
2407 SCIP_CALL( SCIPlpiGetSol(sepadata->lpi, NULL, NULL, facet, NULL, NULL) );
2408 }
2409 else
2410 {
2411 SCIP_Real* dualsol;
2412
2413 SCIP_CALL( SCIPallocBufferArray(scip, &dualsol, nrows) );
2414
2415 /* get the dual solution */
2416 SCIP_CALL( SCIPlpiGetSol(sepadata->lpi, NULL, NULL, dualsol, NULL, NULL) );
2417
2418 for( i = 0; i < ecaggr->nvars; ++i )
2419 facet[i] = dualsol[i];
2420
2421 /* constant part of the facet is the last component of the dual solution */
2422 facet[ecaggr->nvars] = dualsol[nrows - 1];
2423
2424 SCIPfreeBufferArray(scip, &dualsol);
2425 }
2426
2427#ifdef SCIP_DEBUG
2428 SCIPdebugMsg(scip, "facet for the transformed problem: ");
2429 for( i = 0; i < ecaggr->nvars; ++i )
2430 {
2431 SCIPdebugMsgPrint(scip, "%3.4e * %s + ", facet[i], SCIPvarGetName(ecaggr->vars[i]));
2432 }
2433 SCIPdebugMsgPrint(scip, "%3.4e\n", facet[ecaggr->nvars]);
2434#endif
2435
2436 /*
2437 * 4. transform the facet to original space
2438 * we now have the linear underestimator L(x) = beta^T x + beta_0, which needs to be transform to the original space
2439 * the underestimator in the original space, G(x) = alpha^T x + alpha_0, is given by G(x) = L(T(x)), where T(.) is
2440 * the transformation applied in step 2; therefore,
2441 * alpha_i = beta_i/(ub_i - lb_i)
2442 * alpha_0 = beta_0 - sum_i lb_i * beta_i/(ub_i - lb_i)
2443 */
2444
2445 SCIPdebugMsg(scip, "facet in orig. space: ");
2446 *facetval = 0.0;
2447
2448 for( i = 0; i < ecaggr->nvars; ++i )
2449 {
2450 SCIP_Real varlb;
2451 SCIP_Real varub;
2452
2453 varlb = SCIPvarGetLbLocal(ecaggr->vars[i]);
2454 varub = SCIPvarGetUbLocal(ecaggr->vars[i]);
2455 assert(!SCIPisEQ(scip, varlb, varub));
2456
2457 /* substract (\beta_i * lb_i) / (ub_i - lb_i) from current alpha_0 */
2458 facet[ecaggr->nvars] -= (facet[i] * varlb) / (varub - varlb);
2459
2460 /* set \alpha_i := \beta_i / (ub_i - lb_i) */
2461 facet[i] = facet[i] / (varub - varlb);
2462 *facetval += facet[i] * SCIPgetSolVal(scip, sol, ecaggr->vars[i]);
2463
2464 SCIPdebugMsgPrint(scip, "%3.4e * %s + ", facet[i], SCIPvarGetName(ecaggr->vars[i]));
2465 }
2466
2467 /* add constant part to the facet value */
2468 *facetval += facet[ecaggr->nvars];
2469 SCIPdebugMsgPrint(scip, "%3.4e\n", facet[ecaggr->nvars]);
2470
2471 /*
2472 * 5. adjust and check facet with the algorithm of Rikun et al.
2473 */
2474
2475 if( checkRikun(scip, ecaggr, fvals, facet) )
2476 {
2477 SCIPdebugMsg(scip, "facet pass the check of Rikun et al.\n");
2478 *success = TRUE;
2479 }
2480
2481 /* free allocated memory */
2482 SCIPfreeBufferArray(scip, &fvals);
2483
2484 return SCIP_OKAY;
2485}
2486
2487/*
2488 * miscellaneous methods
2489 */
2490
2491/** method to add a facet of the convex envelope of an edge-concave aggregation to a given cut */
2492static
2494 SCIP* scip, /**< SCIP data structure */
2495 SCIP_SOL* sol, /**< current solution (might be NULL) */
2496 SCIP_ROW* cut, /**< current cut (modifiable) */
2497 SCIP_Real* facet, /**< coefficient of the facet (dimension nvars + 1) */
2498 SCIP_VAR** vars, /**< variables of the facet */
2499 int nvars, /**< number of variables in the facet */
2500 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
2501 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
2502 SCIP_Bool* success /**< pointer to store if everything went fine */
2503 )
2504{
2505 int i;
2506
2507 assert(cut != NULL);
2508 assert(facet != NULL);
2509 assert(vars != NULL);
2510 assert(nvars > 0);
2511 assert(cutconstant != NULL);
2512 assert(cutactivity != NULL);
2513 assert(success != NULL);
2514
2515 *success = TRUE;
2516
2517 for( i = 0; i < nvars; ++i )
2518 {
2519 if( SCIPisInfinity(scip, REALABS(facet[i])) )
2520 {
2521 *success = FALSE;
2522 return SCIP_OKAY;
2523 }
2524
2525 if( !SCIPisZero(scip, facet[i]) )
2526 {
2527 /* add only a constant if the variable has been fixed */
2528 if( SCIPvarGetLbLocal(vars[i]) == SCIPvarGetUbLocal(vars[i]) ) /*lint !e777*/
2529 {
2530 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(vars[i]), SCIPgetSolVal(scip, sol, vars[i])));
2531 *cutconstant += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
2532 *cutactivity += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
2533 }
2534 else
2535 {
2536 *cutactivity += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
2537 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[i], facet[i]) );
2538 }
2539 }
2540 }
2541
2542 /* add constant part of the facet */
2543 *cutconstant += facet[nvars];
2544 *cutactivity += facet[nvars];
2545
2546 return SCIP_OKAY;
2547}
2548
2549/** method to add a linear term to a given cut */
2550static
2552 SCIP* scip, /**< SCIP data structure */
2553 SCIP_SOL* sol, /**< current solution (might be NULL) */
2554 SCIP_ROW* cut, /**< current cut (modifiable) */
2555 SCIP_VAR* x, /**< linear variable */
2556 SCIP_Real coeff, /**< coefficient */
2557 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
2558 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
2559 SCIP_Bool* success /**< pointer to store if everything went fine */
2560 )
2561{
2562 SCIP_Real activity;
2563
2564 assert(cut != NULL);
2565 assert(x != NULL);
2566 assert(!SCIPisZero(scip, coeff));
2567 assert(!SCIPisInfinity(scip, coeff));
2568 assert(cutconstant != NULL);
2569 assert(cutactivity != NULL);
2570 assert(success != NULL);
2571
2572 *success = TRUE;
2573 activity = SCIPgetSolVal(scip, sol, x) * coeff;
2574
2575 /* do not add a term if the activity is -infinity */
2576 if( SCIPisInfinity(scip, -1.0 * REALABS(activity)) )
2577 {
2578 *success = FALSE;
2579 return SCIP_OKAY;
2580 }
2581
2582 /* add activity to the constant part if the variable has been fixed */
2583 if( SCIPvarGetLbLocal(x) == SCIPvarGetUbLocal(x) ) /*lint !e777*/
2584 {
2586 *cutconstant += activity;
2587 SCIPdebugMsg(scip, "add to cut: %e\n", activity);
2588 }
2589 else
2590 {
2591 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, coeff) );
2592 SCIPdebugMsg(scip, "add to cut: %e * %s\n", coeff, SCIPvarGetName(x));
2593 }
2594
2595 *cutactivity += activity;
2596
2597 return SCIP_OKAY;
2598}
2599
2600/** method to add an underestimate of a bilinear term to a given cut */
2601static
2603 SCIP* scip, /**< SCIP data structure */
2604 SCIP_SOL* sol, /**< current solution (might be NULL) */
2605 SCIP_ROW* cut, /**< current cut (modifiable) */
2606 SCIP_VAR* x, /**< first bilinear variable */
2607 SCIP_VAR* y, /**< seconds bilinear variable */
2608 SCIP_Real coeff, /**< coefficient */
2609 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
2610 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
2611 SCIP_Bool* success /**< pointer to store if everything went fine */
2612 )
2613{
2614 SCIP_Real activity;
2615
2616 assert(cut != NULL);
2617 assert(x != NULL);
2618 assert(y != NULL);
2619 assert(!SCIPisZero(scip, coeff));
2620 assert(cutconstant != NULL);
2621 assert(cutactivity != NULL);
2622 assert(success != NULL);
2623
2624 *success = TRUE;
2625 activity = coeff * SCIPgetSolVal(scip, sol, x) * SCIPgetSolVal(scip, sol, y);
2626
2627 if( SCIPisInfinity(scip, REALABS(coeff)) )
2628 {
2629 *success = FALSE;
2630 return SCIP_OKAY;
2631 }
2632
2633 /* do not add a term if the activity is -infinity */
2634 if( SCIPisInfinity(scip, -1.0 * REALABS(activity)) )
2635 {
2636 *success = FALSE;
2637 return SCIP_OKAY;
2638 }
2639
2640 /* quadratic case */
2641 if( x == y )
2642 {
2643 SCIP_Real refpoint;
2644 SCIP_Real lincoef;
2645 SCIP_Real linconst;
2646
2647 lincoef = 0.0;
2648 linconst = 0.0;
2649 refpoint = SCIPgetSolVal(scip, sol, x);
2650
2651 /* adjust the reference point */
2652 refpoint = SCIPisLT(scip, refpoint, SCIPvarGetLbLocal(x)) ? SCIPvarGetLbLocal(x) : refpoint;
2653 refpoint = SCIPisGT(scip, refpoint, SCIPvarGetUbLocal(x)) ? SCIPvarGetUbLocal(x) : refpoint;
2654 assert(SCIPisLE(scip, refpoint, SCIPvarGetUbLocal(x)) && SCIPisGE(scip, refpoint, SCIPvarGetLbLocal(x)));
2655
2656 if( SCIPisPositive(scip, coeff) )
2657 SCIPaddSquareLinearization(scip, coeff, refpoint, SCIPvarIsIntegral(x), &lincoef, &linconst, success);
2658 else
2659 SCIPaddSquareSecant(scip, coeff, SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x), &lincoef, &linconst, success);
2660
2661 *cutactivity += lincoef * refpoint + linconst;
2662 *cutconstant += linconst;
2663
2664 /* add underestimate to cut */
2665 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, lincoef) );
2666
2667 SCIPdebugMsg(scip, "add to cut: %e * %s + %e\n", lincoef, SCIPvarGetName(x), linconst);
2668 }
2669 /* bilinear case */
2670 else
2671 {
2672 SCIP_Real refpointx;
2673 SCIP_Real refpointy;
2674 SCIP_Real lincoefx;
2675 SCIP_Real lincoefy;
2676 SCIP_Real linconst;
2677
2678 lincoefx = 0.0;
2679 lincoefy = 0.0;
2680 linconst = 0.0;
2681 refpointx = SCIPgetSolVal(scip, sol, x);
2682 refpointy = SCIPgetSolVal(scip, sol, y);
2683
2684 /* adjust the reference points */
2685 refpointx = SCIPisLT(scip, refpointx, SCIPvarGetLbLocal(x)) ? SCIPvarGetLbLocal(x) : refpointx;
2686 refpointx = SCIPisGT(scip, refpointx, SCIPvarGetUbLocal(x)) ? SCIPvarGetUbLocal(x) : refpointx;
2687 refpointy = SCIPisLT(scip, refpointy, SCIPvarGetLbLocal(y)) ? SCIPvarGetLbLocal(y) : refpointy;
2688 refpointy = SCIPisGT(scip, refpointy, SCIPvarGetUbLocal(y)) ? SCIPvarGetUbLocal(y) : refpointy;
2689 assert(SCIPisLE(scip, refpointx, SCIPvarGetUbLocal(x)) && SCIPisGE(scip, refpointx, SCIPvarGetLbLocal(x)));
2690 assert(SCIPisLE(scip, refpointy, SCIPvarGetUbLocal(y)) && SCIPisGE(scip, refpointy, SCIPvarGetLbLocal(y)));
2691
2693 SCIPvarGetUbLocal(y), refpointy, FALSE, &lincoefx, &lincoefy, &linconst, success);
2694
2695 *cutactivity += lincoefx * refpointx + lincoefy * refpointy + linconst;
2696 *cutconstant += linconst;
2697
2698 /* add underestimate to cut */
2699 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, lincoefx) );
2700 SCIP_CALL( SCIPaddVarToRow(scip, cut, y, lincoefy) );
2701
2702 SCIPdebugMsg(scip, "add to cut: %e * %s + %e * %s + %e\n", lincoefx, SCIPvarGetName(x), lincoefy,
2703 SCIPvarGetName(y), linconst);
2704 }
2705
2706 return SCIP_OKAY;
2707}
2708
2709/** method to compute and add a cut for a nonlinear row aggregation and a given solution
2710 *
2711 * we compute for each edge concave aggregation one facet;
2712 * the remaining bilinear terms will be underestimated with McCormick, secants or linearizations;
2713 * constant and linear terms will be added to the cut directly
2714 */
2715static
2717 SCIP* scip, /**< SCIP data structure */
2718 SCIP_SEPA* sepa, /**< separator */
2719 SCIP_SEPADATA* sepadata, /**< separator data */
2720 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
2721 SCIP_SOL* sol, /**< current solution (might be NULL) */
2722 SCIP_Bool* separated, /**< pointer to store if we could separate the current solution */
2723 SCIP_Bool* cutoff /**< pointer to store if the current node gets cut off */
2724 )
2725{
2726 SCIP_ROW* cut;
2727 SCIP_Real* bestfacet;
2728 SCIP_Real bestfacetval;
2729 SCIP_Real cutconstant;
2730 SCIP_Real cutactivity;
2731 int bestfacetsize;
2732 char cutname[SCIP_MAXSTRLEN];
2733 SCIP_Bool found;
2734 SCIP_Bool islocalcut;
2735 int i;
2736
2737 assert(separated != NULL);
2738 assert(cutoff != NULL);
2739 assert(nlrowaggr->necaggr > 0);
2740 assert(nlrowaggr->nlrow != NULL);
2741 assert(SCIPnlrowIsInNLP(nlrowaggr->nlrow));
2742
2743 *separated = FALSE;
2744 *cutoff = FALSE;
2745 /* we use SCIPgetDepth because we add the cut to the global cut pool if cut is globally valid */
2746 islocalcut = SCIPgetDepth(scip) != 0;
2747
2748 /* create the cut */
2749 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "ec");
2750 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), SCIPinfinity(scip), islocalcut, FALSE,
2751 sepadata->dynamiccuts) );
2753
2754 /* track rhs and activity of the cut */
2755 cutconstant = nlrowaggr->constant;
2756 cutactivity = 0.0;
2757
2758 /* allocate necessary memory */
2759 bestfacetsize = sepadata->maxaggrsize + 1;
2760 SCIP_CALL( SCIPallocBufferArray(scip, &bestfacet, bestfacetsize) );
2761
2762#ifdef SCIP_DEBUG
2763 SCIP_CALL( SCIPprintNlRow(scip, nlrowaggr->nlrow, NULL) );
2764
2765 SCIPdebugMsg(scip, "current solution:\n");
2766 for( i = 0; i < SCIPgetNVars(scip); ++i )
2767 {
2768 SCIP_VAR* var = SCIPgetVars(scip)[i];
2769 SCIPdebugMsg(scip, " %s = [%e, %e] solval = %e\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var),
2770 SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var));
2771 }
2772#endif
2773
2774 /* compute a facet for each edge-concave aggregation */
2775 for( i = 0; i < nlrowaggr->necaggr; ++i )
2776 {
2777 SCIP_ECAGGR* ecaggr;
2778 SCIP_Bool success;
2779
2780 ecaggr = nlrowaggr->ecaggr[i];
2781 assert(ecaggr != NULL);
2782
2783 /* compute a facet of the convex envelope */
2784 SCIP_CALL( computeConvexEnvelopeFacet(scip, sepadata, sol, ecaggr, bestfacet, &bestfacetval, &found) );
2785
2786 SCIPdebugMsg(scip, "found facet for edge-concave aggregation %d/%d ? %s\n", i, nlrowaggr->necaggr,
2787 found ? "yes" : "no");
2788
2789#ifdef SCIP_DEBUG
2790 if( found )
2791 printFacet(scip, ecaggr->vars, ecaggr->nvars, bestfacet, bestfacetval);
2792#endif
2793
2794 /* do not add any cut because we did not found a facet for at least one edge-concave aggregation */
2795 if( !found ) /*lint !e774*/
2796 goto TERMINATE;
2797
2798 /* add facet to the cut and update the rhs and activity of the cut */
2799 SCIP_CALL( addFacetToCut(scip, sol, cut, bestfacet, ecaggr->vars, ecaggr->nvars, &cutconstant, &cutactivity,
2800 &success) );
2801
2802 if( !success )
2803 goto TERMINATE;
2804 }
2805
2806 /* compute an underestimate for each bilinear term which is not in any edge-concave aggregation */
2807 for( i = 0; i < nlrowaggr->nremterms; ++i )
2808 {
2809 SCIP_VAR* x;
2810 SCIP_VAR* y;
2811 SCIP_Bool success;
2812
2813 x = nlrowaggr->remtermvars1[i];
2814 y = nlrowaggr->remtermvars2[i];
2815 assert(x != NULL);
2816 assert(y != NULL);
2817
2818 SCIP_CALL( addBilinearTermToCut(scip, sol, cut, x, y, nlrowaggr->remtermcoefs[i], &cutconstant, &cutactivity,
2819 &success) );
2820
2821 if( !success )
2822 goto TERMINATE;
2823 }
2824
2825 /* add all linear terms to the cut */
2826 for( i = 0; i < nlrowaggr->nlinvars; ++i )
2827 {
2828 SCIP_VAR* x;
2829 SCIP_Real coef;
2830 SCIP_Bool success;
2831
2832 x = nlrowaggr->linvars[i];
2833 assert(x != NULL);
2834
2835 coef = nlrowaggr->lincoefs[i];
2836
2837 SCIP_CALL( addLinearTermToCut(scip, sol, cut, x, coef, &cutconstant, &cutactivity, &success) );
2838
2839 if( !success )
2840 goto TERMINATE;
2841 }
2842
2843 SCIPdebugMsg(scip, "cut activity = %e rhs(nlrow) = %e\n", cutactivity, nlrowaggr->rhs);
2844
2845 /* set rhs of the cut (substract the constant part of the cut) */
2846 SCIP_CALL( SCIPchgRowRhs(scip, cut, nlrowaggr->rhs - cutconstant) );
2848
2849 /* check activity of the row; this assert can fail because of numerics */
2850 /* assert(SCIPisFeasEQ(scip, cutactivity - cutconstant, SCIPgetRowSolActivity(scip, cut, sol)) ); */
2851
2852#ifdef SCIP_DEBUG
2853 SCIP_CALL( SCIPprintRow(scip, cut, NULL) );
2854#endif
2855
2856 SCIPdebugMsg(scip, "EC cut <%s>: act=%f eff=%f rank=%d range=%e\n",
2859
2860 /* try to add the cut has a finite rhs, is efficacious, and does not exceed the maximum cut range */
2861 if( !SCIPisInfinity(scip, nlrowaggr->rhs - cutconstant) && SCIPisCutEfficacious(scip, sol, cut)
2862 && SCIPgetRowMaxCoef(scip, cut) / SCIPgetRowMinCoef(scip, cut) < sepadata->cutmaxrange )
2863 {
2864 /* add the cut if it is separating the given solution by at least minviolation */
2865 if( SCIPisGE(scip, cutactivity - nlrowaggr->rhs, sepadata->minviolation) )
2866 {
2867 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
2868 *separated = TRUE;
2869 SCIPdebugMsg(scip, "added separating cut\n");
2870 }
2871
2872 if( !(*cutoff) && !islocalcut )
2873 {
2874 SCIP_CALL( SCIPaddPoolCut(scip, cut) );
2875 SCIPdebugMsg(scip, "added cut to cut pool\n");
2876 }
2877 }
2878
2879TERMINATE:
2880 /* free allocated memory */
2881 SCIPfreeBufferArray(scip, &bestfacet);
2882
2883 /* release the row */
2884 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
2885
2886 return SCIP_OKAY;
2887}
2888
2889/** returns whether it is possible to compute a cut for a given nonlinear row aggregation */
2890static
2892 SCIP* scip, /**< SCIP data structure */
2893 SCIP_SOL* sol, /**< current solution (might be NULL) */
2894 SCIP_NLROWAGGR* nlrowaggr /**< nonlinear row aggregation */
2895 )
2896{
2897 int i;
2898
2899 assert(scip != NULL);
2900 assert(nlrowaggr != NULL);
2901
2902 if( !SCIPnlrowIsInNLP(nlrowaggr->nlrow) )
2903 {
2904 SCIPdebugMsg(scip, "nlrow is not in NLP anymore\n");
2905 return FALSE;
2906 }
2907
2908 for( i = 0; i < nlrowaggr->nquadvars; ++i )
2909 {
2910 SCIP_VAR* var = nlrowaggr->quadvars[i];
2911 assert(var != NULL);
2912
2913 /* check whether the variable has infinite bounds */
2915 || SCIPisInfinity(scip, REALABS(SCIPgetSolVal(scip, sol, var))) )
2916 {
2917 SCIPdebugMsg(scip, "nlrow aggregation contains unbounded variables\n");
2918 return FALSE;
2919 }
2920
2921 /* check whether the variable has been fixed and is in one edge-concave aggregation */
2922 if( nlrowaggr->quadvar2aggr[i] >= 0 && SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
2923 {
2924 SCIPdebugMsg(scip, "nlrow aggregation contains fixed variables in an e.c. aggregation\n");
2925 return FALSE;
2926 }
2927 }
2928
2929 return TRUE;
2930}
2931
2932/** searches and tries to add edge-concave cuts */
2933static
2935 SCIP* scip, /**< SCIP data structure */
2936 SCIP_SEPA* sepa, /**< separator */
2937 SCIP_SEPADATA* sepadata, /**< separator data */
2938 int depth, /**< current depth */
2939 SCIP_SOL* sol, /**< current solution */
2940 SCIP_RESULT* result /**< pointer to store the result of the separation call */
2941 )
2942{
2943 int nmaxcuts;
2944 int ncuts;
2945 int i;
2946
2947 assert(*result == SCIP_DIDNOTRUN);
2948
2949 SCIPdebugMsg(scip, "separate cuts...\n");
2950
2951 /* skip if there are no nonlinear row aggregations */
2952 if( sepadata->nnlrowaggrs == 0 )
2953 {
2954 SCIPdebugMsg(scip, "no aggregations exists -> skip call\n");
2955 return SCIP_OKAY;
2956 }
2957
2958 /* get the maximal number of cuts allowed in a separation round */
2959 nmaxcuts = depth == 0 ? sepadata->maxsepacutsroot : sepadata->maxsepacuts;
2960 ncuts = 0;
2961
2962 /* try to compute cuts for each nonlinear row independently */
2963 for( i = 0; i < sepadata->nnlrowaggrs && ncuts < nmaxcuts && !SCIPisStopped(scip); ++i )
2964 {
2965 SCIP_NLROWAGGR* nlrowaggr;
2966 SCIP_Bool separated;
2967 SCIP_Bool cutoff;
2968
2969 nlrowaggr = sepadata->nlrowaggrs[i];
2970 assert(nlrowaggr != NULL);
2971
2972 /* skip nonlinear aggregations for which it is obviously not possible to compute a cut */
2973 if( !isPossibleToComputeCut(scip, sol, nlrowaggr) )
2974 return SCIP_OKAY;
2975
2976 *result = (*result == SCIP_DIDNOTRUN) ? SCIP_DIDNOTFIND : *result;
2977
2978 SCIPdebugMsg(scip, "try to compute a cut for nonlinear row aggregation %d\n", i);
2979
2980 /* compute and add cut */
2981 SCIP_CALL( computeCut(scip, sepa, sepadata, nlrowaggr, sol, &separated, &cutoff) );
2982 SCIPdebugMsg(scip, "found a cut: %s cutoff: %s\n", separated ? "yes" : "no", cutoff ? "yes" : "no");
2983
2984 /* stop if the current node gets cut off */
2985 if( cutoff )
2986 {
2987 assert(separated);
2988 *result = SCIP_CUTOFF;
2989 return SCIP_OKAY;
2990 }
2991
2992 /* do not compute more cuts if we already separated the given solution */
2993 if( separated )
2994 {
2995 assert(!cutoff);
2996 *result = SCIP_SEPARATED;
2997 ++ncuts;
2998 }
2999 }
3000
3001 return SCIP_OKAY;
3002}
3003
3004/*
3005 * Callback methods of separator
3006 */
3007
3008/** copy method for separator plugins (called when SCIP copies plugins) */
3009static
3010SCIP_DECL_SEPACOPY(sepaCopyEccuts)
3011{ /*lint --e{715}*/
3012 assert(scip != NULL);
3013 assert(sepa != NULL);
3014 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
3015
3016 /* call inclusion method of constraint handler */
3018
3019 return SCIP_OKAY;
3020}
3021
3022/** destructor of separator to free user data (called when SCIP is exiting) */
3023static
3024SCIP_DECL_SEPAFREE(sepaFreeEccuts)
3025{ /*lint --e{715}*/
3026 SCIP_SEPADATA* sepadata;
3027
3028 sepadata = SCIPsepaGetData(sepa);
3029 assert(sepadata != NULL);
3030
3031 SCIP_CALL( sepadataFree(scip, &sepadata) );
3032 SCIPsepaSetData(sepa, NULL);
3033
3034 return SCIP_OKAY;
3035}
3036
3037/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
3038static
3039SCIP_DECL_SEPAEXITSOL(sepaExitsolEccuts)
3040{ /*lint --e{715}*/
3041 SCIP_SEPADATA* sepadata;
3042
3043 sepadata = SCIPsepaGetData(sepa);
3044 assert(sepadata != NULL);
3045
3046 /* print statistics */
3047#ifdef SCIP_STATISTIC
3048 SCIPstatisticMessage("rhs-AGGR %d\n", sepadata->nrhsnlrowaggrs);
3049 SCIPstatisticMessage("lhs-AGGR %d\n", sepadata->nlhsnlrowaggrs);
3050 SCIPstatisticMessage("aggr. search time = %f\n", sepadata->aggrsearchtime);
3051#endif
3052
3053 /* free nonlinear row aggregations */
3054 SCIP_CALL( sepadataFreeNlrows(scip, sepadata) );
3055
3056 /* mark that we should search again for nonlinear row aggregations */
3057 sepadata->searchedforaggr = FALSE;
3058
3059 SCIPdebugMsg(scip, "exitsol\n");
3060
3061 return SCIP_OKAY;
3062}
3063
3064/** LP solution separation method of separator */
3065static
3066SCIP_DECL_SEPAEXECLP(sepaExeclpEccuts)
3067{ /*lint --e{715}*/
3068 SCIP_SEPADATA* sepadata;
3069 int ncalls;
3070
3071 sepadata = SCIPsepaGetData(sepa);
3072 assert(sepadata != NULL);
3073
3074 *result = SCIP_DIDNOTRUN;
3075
3076 if( !allowlocal )
3077 return SCIP_OKAY;
3078
3079 /* check min- and maximal aggregation size */
3080 if( sepadata->maxaggrsize < sepadata->minaggrsize )
3082
3083 /* only call separator, if we are not close to terminating */
3084 if( SCIPisStopped(scip) )
3085 return SCIP_OKAY;
3086
3087 /* skip if the LP is not constructed yet */
3089 {
3090 SCIPdebugMsg(scip, "Skip since NLP is not constructed yet.\n");
3091 return SCIP_OKAY;
3092 }
3093
3094 /* only call separator up to a maximum depth */
3095 if ( sepadata->maxdepth >= 0 && depth > sepadata->maxdepth )
3096 return SCIP_OKAY;
3097
3098 /* only call separator a given number of times at each node */
3099 ncalls = SCIPsepaGetNCallsAtNode(sepa);
3100 if ( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
3101 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
3102 return SCIP_OKAY;
3103
3104 /* search for nonlinear row aggregations */
3105 if( !sepadata->searchedforaggr )
3106 {
3107 int i;
3108
3109 SCIPstatistic( sepadata->aggrsearchtime -= SCIPgetTotalTime(scip) );
3110
3111 SCIPdebugMsg(scip, "search for nonlinear row aggregations\n");
3112 for( i = 0; i < SCIPgetNNLPNlRows(scip) && !SCIPisStopped(scip); ++i )
3113 {
3114 SCIP_NLROW* nlrow = SCIPgetNLPNlRows(scip)[i];
3115 SCIP_CALL( findAndStoreEcAggregations(scip, sepadata, nlrow, NULL) );
3116 }
3117 sepadata->searchedforaggr = TRUE;
3118
3119 SCIPstatistic( sepadata->aggrsearchtime += SCIPgetTotalTime(scip) );
3120 }
3121
3122 /* search for edge-concave cuts */
3123 SCIP_CALL( separateCuts(scip, sepa, sepadata, depth, NULL, result) );
3124
3125 return SCIP_OKAY;
3126}
3127
3128/*
3129 * separator specific interface methods
3130 */
3131
3132/** creates the edge-concave separator and includes it in SCIP
3133 *
3134 * @ingroup SeparatorIncludes
3135 */
3137 SCIP* scip /**< SCIP data structure */
3138 )
3139{
3140 SCIP_SEPADATA* sepadata;
3141 SCIP_SEPA* sepa;
3142
3143 /* create eccuts separator data */
3144 SCIP_CALL( sepadataCreate(scip, &sepadata) );
3145
3146 /* include separator */
3148 SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpEccuts, NULL, sepadata) );
3149
3150 assert(sepa != NULL);
3151
3152 /* set non fundamental callbacks via setter functions */
3153 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyEccuts) );
3154 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeEccuts) );
3155 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolEccuts) );
3156
3157 /* add eccuts separator parameters */
3159 "separating/" SEPA_NAME "/dynamiccuts",
3160 "should generated cuts be removed from the LP if they are no longer tight?",
3161 &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
3162
3164 "separating/" SEPA_NAME "/maxrounds",
3165 "maximal number of eccuts separation rounds per node (-1: unlimited)",
3166 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
3167
3169 "separating/" SEPA_NAME "/maxroundsroot",
3170 "maximal number of eccuts separation rounds in the root node (-1: unlimited)",
3171 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
3172
3174 "separating/" SEPA_NAME "/maxdepth",
3175 "maximal depth at which the separator is applied (-1: unlimited)",
3176 &sepadata->maxdepth, FALSE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
3177
3179 "separating/" SEPA_NAME "/maxsepacuts",
3180 "maximal number of edge-concave cuts separated per separation round",
3181 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
3182
3184 "separating/" SEPA_NAME "/maxsepacutsroot",
3185 "maximal number of edge-concave cuts separated per separation round in the root node",
3186 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
3187
3188 SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/cutmaxrange",
3189 "maximal coef. range of a cut (max coef. divided by min coef.) in order to be added to LP relaxation",
3190 &sepadata->cutmaxrange, FALSE, DEFAULT_CUTMAXRANGE, 0.0, SCIPinfinity(scip), NULL, NULL) );
3191
3192 SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/minviolation",
3193 "minimal violation of an edge-concave cut to be separated",
3194 &sepadata->minviolation, FALSE, DEFAULT_MINVIOLATION, 0.0, 0.5, NULL, NULL) );
3195
3197 "separating/" SEPA_NAME "/minaggrsize",
3198 "search for edge-concave aggregations of at least this size",
3199 &sepadata->minaggrsize, TRUE, DEFAULT_MINAGGRSIZE, 3, 5, NULL, NULL) );
3200
3202 "separating/" SEPA_NAME "/maxaggrsize",
3203 "search for edge-concave aggregations of at most this size",
3204 &sepadata->maxaggrsize, TRUE, DEFAULT_MAXAGGRSIZE, 3, 5, NULL, NULL) );
3205
3207 "separating/" SEPA_NAME "/maxbilinterms",
3208 "maximum number of bilinear terms allowed to be in a quadratic constraint",
3209 &sepadata->maxbilinterms, TRUE, DEFAULT_MAXBILINTERMS, 0, INT_MAX, NULL, NULL) );
3210
3212 "separating/" SEPA_NAME "/maxstallrounds",
3213 "maximum number of unsuccessful rounds in the edge-concave aggregation search",
3214 &sepadata->maxstallrounds, TRUE, DEFAULT_MAXSTALLROUNDS, 0, INT_MAX, NULL, NULL) );
3215
3216 return SCIP_OKAY;
3217}
SCIP_VAR * a
Definition: circlepacking.c:66
SCIP_VAR ** y
Definition: circlepacking.c:64
SCIP_VAR ** x
Definition: circlepacking.c:63
Constraint handler for XOR constraints, .
#define NULL
Definition: def.h:262
#define SCIP_MAXSTRLEN
Definition: def.h:283
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:238
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:234
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:390
#define REALABS(x)
Definition: def.h:196
#define SCIP_CALL(x)
Definition: def.h:369
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:411
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: expr_pow.c:3253
void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: expr_pow.c:3321
#define nnodes
Definition: gastrans.c:74
#define narcs
Definition: gastrans.c:77
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPcreateConsBasicXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars)
Definition: cons_xor.c:6068
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:734
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:349
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:317
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:508
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_RETCODE SCIPsetObjsense(SCIP *scip, SCIP_OBJSENSE objsense)
Definition: scip_prob.c:1242
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:180
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3110
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3076
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3425
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3194
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition: lpi_clp.cpp:1179
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:920
SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
Definition: lpi_clp.cpp:1096
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:643
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition: lpi_clp.cpp:2816
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1908
SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:758
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1833
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:531
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition: lpi_clp.cpp:1252
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1447
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition: lpi_clp.cpp:1429
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
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 SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
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 SCIPsetHeuristics(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition: scip_param.c:930
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
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
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:94
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4215
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4251
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:4130
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1438
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2383
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:416
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:4175
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip_mem.h:107
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
int SCIPgetNNLPNlRows(SCIP *scip)
Definition: scip_nlp.c:341
SCIP_NLROW ** SCIPgetNLPNlRows(SCIP *scip)
Definition: scip_nlp.c:319
SCIP_Real SCIPnlrowGetRhs(SCIP_NLROW *nlrow)
Definition: nlp.c:1926
SCIP_Real SCIPnlrowGetLhs(SCIP_NLROW *nlrow)
Definition: nlp.c:1916
int SCIPnlrowGetNLinearVars(SCIP_NLROW *nlrow)
Definition: nlp.c:1876
SCIP_VAR ** SCIPnlrowGetLinearVars(SCIP_NLROW *nlrow)
Definition: nlp.c:1886
SCIP_Real SCIPnlrowGetConstant(SCIP_NLROW *nlrow)
Definition: nlp.c:1866
SCIP_EXPR * SCIPnlrowGetExpr(SCIP_NLROW *nlrow)
Definition: nlp.c:1906
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1965
SCIP_Real * SCIPnlrowGetLinearCoefs(SCIP_NLROW *nlrow)
Definition: nlp.c:1896
SCIP_RETCODE SCIPprintNlRow(SCIP *scip, SCIP_NLROW *nlrow, FILE *file)
Definition: scip_nlp.c:1617
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1926
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1908
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1639
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1662
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1705
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2216
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17380
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1566
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1457
int SCIProwGetRank(SCIP_ROW *row)
Definition: lp.c:17410
SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
Definition: scip_lp.c:1611
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2148
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip_sepa.c:115
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:743
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:880
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:173
SCIP_RETCODE SCIPsetSepaExitsol(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXITSOL((*sepaexitsol)))
Definition: scip_sepa.c:237
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:633
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:643
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:157
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2165
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:1627
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2066
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1213
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3339
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2491
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Real SCIPgetTotalTime(SCIP *scip)
Definition: scip_timing.c:351
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18162
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4889
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18106
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17776
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17437
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17628
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18152
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18096
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:194
SCIP_RETCODE SCIPincludeSepaEccuts(SCIP *scip)
Definition: sepa_eccuts.c:3136
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10878
#define BMSclearMemory(ptr)
Definition: memory.h:129
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
internal methods for NLP management
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPstatisticMessage
Definition: pub_message.h:123
#define SCIPdebug(x)
Definition: pub_message.h:93
#define SCIPdebugMessage
Definition: pub_message.h:96
#define SCIPstatistic(x)
Definition: pub_message.h:120
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
default SCIP plugins
#define SEPA_PRIORITY
Definition: sepa_eccuts.c:47
#define CLIQUE_MINWEIGHT
Definition: sepa_eccuts.c:55
static SCIP_RETCODE doSeachEcAggr(SCIP *scip, SCIP *subscip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol, SCIP_Bool rhsaggr, int *quadvar2aggr, int *nfound)
Definition: sepa_eccuts.c:1554
static SCIP_RETCODE ecaggrAddBilinTerm(SCIP *scip, SCIP_ECAGGR *ecaggr, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coef)
Definition: sepa_eccuts.c:237
static SCIP_RETCODE sepadataCreate(SCIP *scip, SCIP_SEPADATA **sepadata)
Definition: sepa_eccuts.c:728
static SCIP_RETCODE searchEcAggrWithMIP(SCIP *subscip, SCIP_Real timelimit, int nedges, SCIP_Bool *aggrleft, SCIP_Bool *found)
Definition: sepa_eccuts.c:1248
#define SEPA_DELAY
Definition: sepa_eccuts.c:51
static SCIP_RETCODE nlrowaggrCreate(SCIP *scip, SCIP_NLROW *nlrow, SCIP_NLROWAGGR **nlrowaggr, int *quadvar2aggr, int nfound, SCIP_Bool rhsaggr)
Definition: sepa_eccuts.c:430
static SCIP_DECL_SEPAFREE(sepaFreeEccuts)
Definition: sepa_eccuts.c:3024
static SCIP_RETCODE ecaggrAddQuadvar(SCIP_ECAGGR *ecaggr, SCIP_VAR *x)
Definition: sepa_eccuts.c:226
#define USEDUALSIMPLEX
Definition: sepa_eccuts.c:76
#define ADJUSTFACETTOL
Definition: sepa_eccuts.c:75
static SCIP_Real transformValue(SCIP *scip, SCIP_Real lb, SCIP_Real ub, SCIP_Real val)
Definition: sepa_eccuts.c:2241
#define CLIQUE_MAXFIRSTNODEWEIGHT
Definition: sepa_eccuts.c:53
static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int depth, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: sepa_eccuts.c:2934
#define DEFAULT_DYNAMICCUTS
Definition: sepa_eccuts.c:59
static SCIP_RETCODE addFacetToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Real *facet, SCIP_VAR **vars, int nvars, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
Definition: sepa_eccuts.c:2493
static SCIP_RETCODE sepadataAddNlrowaggr(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROWAGGR *nlrowaggr)
Definition: sepa_eccuts.c:800
static SCIP_RETCODE findAndStoreEcAggregations(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol)
Definition: sepa_eccuts.c:1915
#define SEPA_DESC
Definition: sepa_eccuts.c:46
static SCIP_RETCODE nlrowaggrAddLinearTerm(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *linvar, SCIP_Real lincoef)
Definition: sepa_eccuts.c:352
#define DEFAULT_MAXROUNDSROOT
Definition: sepa_eccuts.c:61
static SCIP_RETCODE updateMIP(SCIP *subscip, SCIP_NLROW *nlrow, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, int *quadvar2aggr, int *nedges)
Definition: sepa_eccuts.c:1083
#define SEPA_USESSUBSCIP
Definition: sepa_eccuts.c:50
static SCIP_RETCODE searchEcAggr(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol, SCIP_Bool rhsaggr, int *quadvar2aggr, int *nfound)
Definition: sepa_eccuts.c:1751
static SCIP_RETCODE nlrowaggrAddQuadraticVar(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *quadvar)
Definition: sepa_eccuts.c:385
static SCIP_RETCODE addBilinearTermToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coeff, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
Definition: sepa_eccuts.c:2602
#define DEFAULT_MAXDEPTH
Definition: sepa_eccuts.c:62
static SCIP_Bool isPossibleToComputeCut(SCIP *scip, SCIP_SOL *sol, SCIP_NLROWAGGR *nlrowaggr)
Definition: sepa_eccuts.c:2891
static SCIP_Real phi(SCIP *scip, SCIP_Real val, SCIP_Real lb, SCIP_Real ub)
Definition: sepa_eccuts.c:844
#define DEFAULT_MINVIOLATION
Definition: sepa_eccuts.c:67
static SCIP_RETCODE sepadataFreeNlrows(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition: sepa_eccuts.c:744
#define CLIQUE_BACKTRACKFREQ
Definition: sepa_eccuts.c:57
#define CLIQUE_MAXNTREENODES
Definition: sepa_eccuts.c:56
static SCIP_RETCODE nlrowaggrFree(SCIP *scip, SCIP_NLROWAGGR **nlrowaggr)
Definition: sepa_eccuts.c:652
static SCIP_RETCODE nlrowaggrAddRemBilinTerm(SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coef)
Definition: sepa_eccuts.c:405
static SCIP_RETCODE addLinearTermToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_VAR *x, SCIP_Real coeff, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
Definition: sepa_eccuts.c:2551
static SCIP_RETCODE storeAggrFromMIP(SCIP *subscip, SCIP_NLROW *nlrow, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, int *quadvar2aggr, int nfoundsofar)
Definition: sepa_eccuts.c:1162
static SCIP_DECL_SEPAEXITSOL(sepaExitsolEccuts)
Definition: sepa_eccuts.c:3039
#define DEFAULT_MAXSEPACUTSROOT
Definition: sepa_eccuts.c:64
static SCIP_DECL_SEPACOPY(sepaCopyEccuts)
Definition: sepa_eccuts.c:3010
static SCIP_DECL_SEPAEXECLP(sepaExeclpEccuts)
Definition: sepa_eccuts.c:3066
static SCIP_RETCODE computeCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_NLROWAGGR *nlrowaggr, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
Definition: sepa_eccuts.c:2716
static SCIP_RETCODE sepadataFree(SCIP *scip, SCIP_SEPADATA **sepadata)
Definition: sepa_eccuts.c:774
#define DEFAULT_MAXAGGRSIZE
Definition: sepa_eccuts.c:69
static SCIP_RETCODE createTcliqueGraph(SCIP_NLROW *nlrow, TCLIQUE_GRAPH **graph, SCIP_Real *nodeweights)
Definition: sepa_eccuts.c:1314
static SCIP_RETCODE ecaggrFree(SCIP *scip, SCIP_ECAGGR **ecaggr)
Definition: sepa_eccuts.c:205
#define SEPA_MAXBOUNDDIST
Definition: sepa_eccuts.c:49
static SCIP_RETCODE createLP(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition: sepa_eccuts.c:2091
#define DEFAULT_MINAGGRSIZE
Definition: sepa_eccuts.c:68
static SCIP_RETCODE computeConvexEnvelopeFacet(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_ECAGGR *ecaggr, SCIP_Real *facet, SCIP_Real *facetval, SCIP_Bool *success)
Definition: sepa_eccuts.c:2285
#define SEPA_FREQ
Definition: sepa_eccuts.c:48
static SCIP_RETCODE createMIP(SCIP *scip, SCIP *subscip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_Bool rhsaggr, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, SCIP_Real *nodeweights, int *nedges, int *narcs)
Definition: sepa_eccuts.c:869
static SCIP_Bool checkRikun(SCIP *scip, SCIP_ECAGGR *ecaggr, SCIP_Real *fvals, SCIP_Real *facet)
Definition: sepa_eccuts.c:2020
#define DEFAULT_MAXSEPACUTS
Definition: sepa_eccuts.c:63
#define SEPA_NAME
Definition: sepa_eccuts.c:45
#define DEFAULT_MAXSTALLROUNDS
Definition: sepa_eccuts.c:71
#define SUBSCIP_NODELIMIT
Definition: sepa_eccuts.c:73
#define DEFAULT_MAXBILINTERMS
Definition: sepa_eccuts.c:70
#define DEFAULT_MAXROUNDS
Definition: sepa_eccuts.c:60
static SCIP_RETCODE searchEcAggrWithCliques(SCIP *scip, TCLIQUE_GRAPH *graph, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, int *quadvar2aggr, int nfoundsofar, SCIP_Bool rhsaggr, SCIP_Bool *foundaggr, SCIP_Bool *foundclique)
Definition: sepa_eccuts.c:1405
static SCIP_RETCODE ecaggrCreateEmpty(SCIP *scip, SCIP_ECAGGR **ecaggr, int nquadvars, int nquadterms)
Definition: sepa_eccuts.c:175
static SCIP_Real evalCorner(SCIP_ECAGGR *ecaggr, int k)
Definition: sepa_eccuts.c:2203
#define DEFAULT_CUTMAXRANGE
Definition: sepa_eccuts.c:65
static SCIP_RETCODE isCandidate(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_Bool *rhscandidate, SCIP_Bool *lhscandidate)
Definition: sepa_eccuts.c:1784
static const int poweroftwo[]
Definition: sepa_eccuts.c:79
static SCIP_RETCODE nlrowaggrStoreLinearTerms(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nlinvars)
Definition: sepa_eccuts.c:311
edge concave cut separator
int * termvars1
Definition: sepa_eccuts.c:95
int termsize
Definition: sepa_eccuts.c:98
SCIP_Real * termcoefs
Definition: sepa_eccuts.c:94
int * termvars2
Definition: sepa_eccuts.c:96
int nterms
Definition: sepa_eccuts.c:97
SCIP_VAR ** vars
Definition: sepa_eccuts.c:90
int varsize
Definition: sepa_eccuts.c:92
int nvars
Definition: sepa_eccuts.c:91
SCIP_VAR ** linvars
Definition: sepa_eccuts.c:112
int linvarssize
Definition: sepa_eccuts.c:115
int remtermsize
Definition: sepa_eccuts.c:127
SCIP_VAR ** remtermvars2
Definition: sepa_eccuts.c:124
SCIP_Real * lincoefs
Definition: sepa_eccuts.c:113
SCIP_Bool rhsaggr
Definition: sepa_eccuts.c:106
SCIP_Real * remtermcoefs
Definition: sepa_eccuts.c:125
int quadvarssize
Definition: sepa_eccuts.c:121
int * quadvar2aggr
Definition: sepa_eccuts.c:118
SCIP_Real constant
Definition: sepa_eccuts.c:130
SCIP_VAR ** quadvars
Definition: sepa_eccuts.c:117
SCIP_Real rhs
Definition: sepa_eccuts.c:129
int nquadvars
Definition: sepa_eccuts.c:120
int nlinvars
Definition: sepa_eccuts.c:114
SCIP_NLROW * nlrow
Definition: sepa_eccuts.c:105
SCIP_ECAGGR ** ecaggr
Definition: sepa_eccuts.c:109
int nremterms
Definition: sepa_eccuts.c:126
SCIP_VAR ** remtermvars1
Definition: sepa_eccuts.c:123
SCIP_Real rhs
Definition: struct_nlp.h:68
tclique user interface
@ TCLIQUE_OPTIMAL
Definition: tclique.h:66
void tcliqueChangeWeight(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
void tcliqueFree(TCLIQUE_GRAPH **tcliquegraph)
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:68
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
TCLIQUE_Bool tcliqueFlush(TCLIQUE_GRAPH *tcliquegraph)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:49
TCLIQUE_Bool tcliqueCreate(TCLIQUE_GRAPH **tcliquegraph)
TCLIQUE_Bool tcliqueAddNode(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
TCLIQUE_Bool tcliqueAddEdge(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
@ SCIP_OBJSEN_MINIMIZE
Definition: type_lpi.h:43
@ SCIP_PARAMSETTING_AGGRESSIVE
Definition: type_paramset.h:61
@ SCIP_OBJSENSE_MAXIMIZE
Definition: type_prob.h:47
@ 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
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_PARAMETERWRONGVAL
Definition: type_retcode.h:57
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:52
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:63
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:64
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:62
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62