SCIP Doxygen Documentation
Loading...
Searching...
No Matches
sepa_rlt.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-2026 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_rlt.c
26 * @ingroup DEFPLUGINS_SEPA
27 * @brief separator for cuts generated by Reformulation-Linearization-Technique (RLT)
28 * @author Fabian Wegscheider
29 * @author Ksenia Bestuzheva
30 *
31 * @todo implement the possibility to add extra auxiliary variables for RLT (like in DOI 10.1080/10556788.2014.916287)
32 * @todo add RLT cuts for the product of equality constraints
33 * @todo implement dynamic addition of RLT cuts during branching (see DOI 10.1007/s10898-012-9874-7)
34 * @todo use SCIPvarIsBinary instead of SCIPvarGetType() == SCIP_VARTYPE_BINARY ?
35 * @todo parameter maxusedvars seems arbitrary (too large for small problems; too small for large problems); something more adaptive we can do? (e.g., all variables with priority >= x% of highest prio)
36 */
37
38/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39
40#include "scip/sepa_rlt.h"
41#include "scip/cons_nonlinear.h"
42#include "scip/pub_lp.h"
43#include "scip/expr_pow.h"
45#include "scip/cutsel_hybrid.h"
46
47
48#define SEPA_NAME "rlt"
49#define SEPA_DESC "reformulation-linearization-technique separator"
50#define SEPA_PRIORITY 10 /**< priority for separation */
51#define SEPA_FREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
52#define SEPA_MAXBOUNDDIST 1.0 /**< maximal relative distance from the current node's dual bound to primal bound
53 * compared to best node's dual bound for applying separation.*/
54#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
55#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
56
57#define DEFAULT_MAXUNKNOWNTERMS 0 /**< maximum number of unknown bilinear terms a row can have to be used */
58#define DEFAULT_MAXUSEDVARS 100 /**< maximum number of variables that will be used to compute rlt cuts */
59#define DEFAULT_MAXNCUTS -1 /**< maximum number of cuts that will be added per round */
60#define DEFAULT_MAXROUNDS 1 /**< maximum number of separation rounds per node (-1: unlimited) */
61#define DEFAULT_MAXROUNDSROOT 10 /**< maximum number of separation rounds in the root node (-1: unlimited) */
62#define DEFAULT_ONLYEQROWS FALSE /**< whether only equality rows should be used for rlt cuts */
63#define DEFAULT_ONLYCONTROWS FALSE /**< whether only continuous rows should be used for rlt cuts */
64#define DEFAULT_ONLYORIGINAL TRUE /**< whether only original variables and rows should be used for rlt cuts */
65#define DEFAULT_USEINSUBSCIP FALSE /**< whether the separator should also be used in sub-scips */
66#define DEFAULT_USEPROJECTION FALSE /**< whether the separator should first check projected rows */
67#define DEFAULT_DETECTHIDDEN FALSE /**< whether implicit products should be detected and separated by McCormick */
68#define DEFAULT_HIDDENRLT FALSE /**< whether RLT cuts should be added for hidden products */
69#define DEFAULT_ADDTOPOOL TRUE /**< whether globally valid RLT cuts are added to the global cut pool */
70
71#define DEFAULT_GOODSCORE 1.0 /**< threshold for score of cut relative to best score to be considered good,
72 * so that less strict filtering is applied */
73#define DEFAULT_BADSCORE 0.5 /**< threshold for score of cut relative to best score to be discarded */
74#define DEFAULT_OBJPARALWEIGHT 0.0 /**< weight of objective parallelism in cut score calculation */
75#define DEFAULT_EFFICACYWEIGHT 1.0 /**< weight of efficacy in cut score calculation */
76#define DEFAULT_DIRCUTOFFDISTWEIGHT 0.0 /**< weight of directed cutoff distance in cut score calculation */
77#define DEFAULT_GOODMAXPARALL 0.1 /**< maximum parallelism for good cuts */
78#define DEFAULT_MAXPARALL 0.1 /**< maximum parallelism for non-good cuts */
79
80#define MAXVARBOUND 1e+5 /**< maximum allowed variable bound for computing an RLT-cut */
81
82/*
83 * Data structures
84 */
85
86/** data object for pairs and triples of variables */
87struct HashData
88{
89 SCIP_VAR* vars[3]; /**< variables in the pair or triple, used for hash comparison */
90 int nvars; /**< number of variables */
91 int nrows; /**< number of rows */
92 int firstrow; /**< beginning of the corresponding row linked list */
93};
94typedef struct HashData HASHDATA;
95
96/** data structure representing an array of variables together with number of elements and size;
97 * used for storing variables that are in some sense adjacent to a given variable
98 */
100{
101 SCIP_VAR** adjacentvars; /**< adjacent vars */
102 int nadjacentvars; /**< number of vars in adjacentvars */
103 int sadjacentvars; /**< size of adjacentvars */
104};
106
107/** separator data */
108struct SCIP_SepaData
109{
110 SCIP_CONSHDLR* conshdlr; /**< nonlinear constraint handler */
111 SCIP_Bool iscreated; /**< indicates whether the sepadata has been initialized yet */
112 SCIP_Bool isinitialround; /**< indicates that this is the first round and original rows are used */
113
114 /* bilinear variables */
115 SCIP_VAR** varssorted; /**< variables that occur in bilinear terms sorted by priority */
116 SCIP_HASHMAP* bilinvardatamap; /**< maps each bilinear var to ADJACENTVARDATA containing vars appearing
117 together with it in bilinear products */
118 int* varpriorities; /**< priorities of variables */
119 int nbilinvars; /**< total number of variables occurring in bilinear terms */
120 int sbilinvars; /**< size of arrays for variables occurring in bilinear terms */
121
122 /* information about bilinear terms */
123 int* eqauxexpr; /**< position of the auxexpr that is equal to the product (-1 if none) */
124 int nbilinterms; /**< total number of bilinear terms */
125
126 /* parameters */
127 int maxunknownterms; /**< maximum number of unknown bilinear terms a row can have to be used (-1: unlimited) */
128 int maxusedvars; /**< maximum number of variables that will be used to compute rlt cuts (-1: unlimited) */
129 int maxncuts; /**< maximum number of cuts that will be added per round (-1: unlimited) */
130 int maxrounds; /**< maximum number of separation rounds per node (-1: unlimited) */
131 int maxroundsroot; /**< maximum number of separation rounds in the root node (-1: unlimited) */
132 SCIP_Bool onlyeqrows; /**< whether only equality rows should be used for rlt cuts */
133 SCIP_Bool onlycontrows; /**< whether only continuous rows should be used for rlt cuts */
134 SCIP_Bool onlyoriginal; /**< whether only original rows and variables should be used for rlt cuts */
135 SCIP_Bool useinsubscip; /**< whether the separator should also be used in sub-scips */
136 SCIP_Bool useprojection; /**< whether the separator should first check projected rows */
137 SCIP_Bool detecthidden; /**< whether implicit products should be detected and separated by McCormick */
138 SCIP_Bool hiddenrlt; /**< whether RLT cuts should be added for hidden products */
139 SCIP_Bool addtopool; /**< whether globally valid RLT cuts are added to the global cut pool */
140
141 /* cut selection parameters */
142 SCIP_Real goodscore; /**< threshold for score of cut relative to best score to be considered good,
143 * so that less strict filtering is applied */
144 SCIP_Real badscore; /**< threshold for score of cut relative to best score to be discarded */
145 SCIP_Real objparalweight; /**< weight of objective parallelism in cut score calculation */
146 SCIP_Real efficacyweight; /**< weight of efficacy in cut score calculation */
147 SCIP_Real dircutoffdistweight;/**< weight of directed cutoff distance in cut score calculation */
148 SCIP_Real goodmaxparall; /**< maximum parallelism for good cuts */
149 SCIP_Real maxparall; /**< maximum parallelism for non-good cuts */
150};
151
152/* a simplified representation of an LP row */
154{
155 const char* name; /**< name of the row */
156 SCIP_Real* coefs; /**< coefficients */
157 SCIP_VAR** vars; /**< variables */
158 SCIP_Real rhs; /**< right hand side */
159 SCIP_Real lhs; /**< left hand side */
160 SCIP_Real cst; /**< constant */
161 int nnonz; /**< number of nonzeroes */
162 int size; /**< size of the coefs and vars arrays */
163};
165
166/*
167 * Local methods
168 */
169
170/** returns TRUE iff both keys are equal
171 *
172 * two variable pairs/triples are equal if the variables are equal
173 */
174static
175SCIP_DECL_HASHKEYEQ(hashdataKeyEqConss)
176{ /*lint --e{715}*/
177 HASHDATA* hashdata1;
178 HASHDATA* hashdata2;
179 int v;
180
181 hashdata1 = (HASHDATA*)key1;
182 hashdata2 = (HASHDATA*)key2;
183
184 /* check data structure */
185 assert(hashdata1->nvars == hashdata2->nvars);
186 assert(hashdata1->firstrow != -1 || hashdata2->firstrow != -1);
187
188 for( v = hashdata1->nvars-1; v >= 0; --v )
189 {
190 /* tests if variables are equal */
191 if( hashdata1->vars[v] != hashdata2->vars[v] )
192 return FALSE;
193
194 assert(SCIPvarCompare(hashdata1->vars[v], hashdata2->vars[v]) == 0);
195 }
196
197 /* if two hashdata objects have the same variables, then either one of them doesn't have a row list yet
198 * (firstrow == -1) or they both point to the same row list
199 */
200 assert(hashdata1->firstrow == -1 || hashdata2->firstrow == -1 || hashdata1->firstrow == hashdata2->firstrow);
201
202 return TRUE;
203}
204
205/** returns the hash value of the key */
206static
207SCIP_DECL_HASHKEYVAL(hashdataKeyValConss)
208{ /*lint --e{715}*/
209 HASHDATA* hashdata;
210 int minidx;
211 int mididx;
212 int maxidx;
213 int idx[3];
214
215 hashdata = (HASHDATA*)key;
216 assert(hashdata != NULL);
217 assert(hashdata->nvars == 3 || hashdata->nvars == 2);
218
219 idx[0] = SCIPvarGetIndex(hashdata->vars[0]);
220 idx[1] = SCIPvarGetIndex(hashdata->vars[1]);
221 idx[2] = SCIPvarGetIndex(hashdata->vars[hashdata->nvars - 1]);
222
223 minidx = MIN3(idx[0], idx[1], idx[2]);
224 maxidx = MAX3(idx[0], idx[1], idx[2]);
225 if( idx[0] == maxidx )
226 mididx = MAX(idx[1], idx[2]);
227 else
228 mididx = MAX(idx[0], MIN(idx[1], idx[2]));
229
230 /* vars should already be sorted by index */
231 assert(minidx <= mididx && mididx <= maxidx);
232
233 return SCIPhashFour(hashdata->nvars, minidx, mididx, maxidx);
234}
235
236/** store a pair of adjacent variables */
237static
239 SCIP* scip, /**< SCIP data structure */
240 SCIP_HASHMAP* adjvarmap, /**< hashmap mapping variables to their ADJACENTVARDATAs */
241 SCIP_VAR** vars /**< variable pair to be stored */
242 )
243{
244 int v1;
245 int v2;
246 int i;
247 ADJACENTVARDATA* adjacentvardata;
248
249 assert(adjvarmap != NULL);
250
251 /* repeat for each variable of the new pair */
252 for( v1 = 0; v1 < 2; ++v1 )
253 {
254 v2 = 1 - v1;
255
256 /* look for data of the first variable */
257 adjacentvardata = (ADJACENTVARDATA*) SCIPhashmapGetImage(adjvarmap, (void*)(size_t) SCIPvarGetIndex(vars[v1]));
258
259 /* if the first variable has not been added to adjvarmap yet, add it here */
260 if( adjacentvardata == NULL )
261 {
262 SCIP_CALL( SCIPallocClearBlockMemory(scip, &adjacentvardata) );
263 SCIP_CALL( SCIPhashmapInsert(adjvarmap, (void*)(size_t) SCIPvarGetIndex(vars[v1]), adjacentvardata) );
264 }
265
266 assert(adjacentvardata != NULL);
267
268 /* look for second variable in adjacentvars of the first variable */
269 if( adjacentvardata->adjacentvars == NULL )
270 {
271 /* we don't know how many adjacent vars there will be - take a guess */
272 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &adjacentvardata->adjacentvars, 4) );
273 adjacentvardata->adjacentvars[0] = vars[v2];
274 ++adjacentvardata->nadjacentvars;
275 adjacentvardata->sadjacentvars = 4;
276 }
277 else
278 {
279 SCIP_Bool found;
280 int pos2;
281
282 found = SCIPsortedvecFindPtr((void**) adjacentvardata->adjacentvars, SCIPvarComp, vars[v2],
283 adjacentvardata->nadjacentvars, &pos2);
284
285 /* add second var to adjacentvardata->adjacentvars, if not already added */
286 if( !found )
287 {
288 /* ensure size of adjacentvardata->adjacentvars */
289 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &adjacentvardata->adjacentvars, &adjacentvardata->sadjacentvars,
290 adjacentvardata->nadjacentvars + 1) );
291
292 /* insert second var at the correct position */
293 for( i = adjacentvardata->nadjacentvars; i > pos2; --i )
294 {
295 adjacentvardata->adjacentvars[i] = adjacentvardata->adjacentvars[i-1];
296 }
297 adjacentvardata->adjacentvars[pos2] = vars[v2];
298 ++adjacentvardata->nadjacentvars;
299 }
300 }
301
302 /* if this is a self-adjacent var, only need to add the connection once */
303 if( vars[v1] == vars[v2] )
304 break;
305 }
306
307 return SCIP_OKAY;
308}
309
310/** returns the array of adjacent variables for a given variable */
311static
313 SCIP_HASHMAP* adjvarmap, /**< hashmap mapping variables to their ADJACENTVARDATAs */
314 SCIP_VAR* var, /**< variable */
315 int* nadjacentvars /**< buffer to store the number of variables in the returned array */
316 )
317{
318 ADJACENTVARDATA* adjacentvardata;
319
320 assert(adjvarmap != NULL);
321
322 *nadjacentvars = 0;
323 adjacentvardata = (ADJACENTVARDATA*) SCIPhashmapGetImage(adjvarmap, (void*)(size_t) SCIPvarGetIndex(var));
324
325 if( adjacentvardata == NULL )
326 return NULL;
327
328 *nadjacentvars = adjacentvardata->nadjacentvars;
329
330 return adjacentvardata->adjacentvars;
331}
332
333/** frees all ADJACENTVARDATAs stored in a hashmap */
334static
336 SCIP* scip, /**< SCIP data structure */
337 SCIP_HASHMAP* adjvarmap /**< hashmap mapping variables to their ADJACENTVARDATAs */
338 )
339{
340 int i;
341 SCIP_HASHMAPENTRY* entry;
342 ADJACENTVARDATA* adjacentvardata;
343
344 assert(adjvarmap != NULL);
345
346 for( i = 0; i < SCIPhashmapGetNEntries(adjvarmap); ++i )
347 {
348 entry = SCIPhashmapGetEntry(adjvarmap, i);
349
350 if( entry == NULL )
351 continue;
352
353 adjacentvardata = (ADJACENTVARDATA*) SCIPhashmapEntryGetImage(entry);
354
355 /* if adjacentvardata has been added to the hashmap, it can't be empty */
356 assert(adjacentvardata->adjacentvars != NULL);
357
358 SCIPfreeBlockMemoryArray(scip, &adjacentvardata->adjacentvars, adjacentvardata->sadjacentvars);
359 SCIPfreeBlockMemory(scip, &adjacentvardata);
360 }
361}
362
363/** free separator data */
364static
366 SCIP* scip, /**< SCIP data structure */
367 SCIP_SEPADATA* sepadata /**< separation data */
368 )
369{ /*lint --e{715}*/
370 int i;
371
372 assert(sepadata->iscreated);
373
374 if( sepadata->nbilinvars != 0 )
375 {
376 /* release bilinvars that were captured for rlt and free all related arrays */
377
378 /* if there are bilinear vars, some of them must also participate in the same product */
379 assert(sepadata->bilinvardatamap != NULL);
380
381 clearVarAdjacency(scip, sepadata->bilinvardatamap);
382
383 for( i = 0; i < sepadata->nbilinvars; ++i )
384 {
385 assert(sepadata->varssorted[i] != NULL);
386 SCIP_CALL( SCIPreleaseVar(scip, &(sepadata->varssorted[i])) );
387 }
388
389 SCIPhashmapFree(&sepadata->bilinvardatamap);
390 SCIPfreeBlockMemoryArray(scip, &sepadata->varssorted, sepadata->sbilinvars);
391 SCIPfreeBlockMemoryArray(scip, &sepadata->varpriorities, sepadata->sbilinvars);
392 sepadata->nbilinvars = 0;
393 sepadata->sbilinvars = 0;
394 }
395
396 /* free the remaining array */
397 if( sepadata->nbilinterms > 0 )
398 {
399 SCIPfreeBlockMemoryArray(scip, &sepadata->eqauxexpr, sepadata->nbilinterms);
400 }
401
402 sepadata->iscreated = FALSE;
403
404 return SCIP_OKAY;
405}
406
407/** creates and returns rows of original linear constraints */
408static
410 SCIP* scip, /**< SCIP data structure */
411 SCIP_ROW*** rows, /**< buffer to store the rows */
412 int* nrows /**< buffer to store the number of linear rows */
413 )
414{
415 SCIP_CONS** conss;
416 int nconss;
417 int i;
418
419 assert(rows != NULL);
420 assert(nrows != NULL);
421
422 conss = SCIPgetConss(scip);
423 nconss = SCIPgetNConss(scip);
424 *nrows = 0;
425
426 SCIP_CALL( SCIPallocBufferArray(scip, rows, nconss) );
427
428 for( i = 0; i < nconss; ++i )
429 {
430 SCIP_ROW *row;
431
432 row = SCIPconsGetRow(scip, conss[i]);
433
434 if( row != NULL )
435 {
436 (*rows)[*nrows] = row;
437 ++*nrows;
438 }
439 }
440
441 return SCIP_OKAY;
442}
443
444/** fills an array of rows suitable for RLT cut generation */
445static
447 SCIP* scip, /**< SCIP data structure */
448 SCIP_SEPA* sepa, /**< separator */
449 SCIP_SEPADATA* sepadata, /**< separator data */
450 SCIP_ROW** prob_rows, /**< problem rows */
451 SCIP_ROW** rows, /**< an array to be filled with suitable rows */
452 int* nrows, /**< buffer to store the number of suitable rows */
453 SCIP_HASHMAP* row_to_pos, /**< hashmap linking row indices to positions in rows */
454 SCIP_Bool allowlocal /**< are local rows allowed? */
455 )
456{
457 int new_nrows;
458 int r;
459 int j;
460 SCIP_Bool iseqrow;
461 SCIP_COL** cols;
462 SCIP_Bool iscontrow;
463
464 new_nrows = 0;
465
466 for( r = 0; r < *nrows; ++r )
467 {
468 iseqrow = SCIPisEQ(scip, SCIProwGetLhs(prob_rows[r]), SCIProwGetRhs(prob_rows[r]));
469
470 /* if equality rows are requested, only those can be used */
471 if( sepadata->onlyeqrows && !iseqrow )
472 continue;
473
474 /* if global cuts are requested, only globally valid rows can be used */
475 if( !allowlocal && SCIProwIsLocal(prob_rows[r]) )
476 continue;
477
478 /* if continuous rows are requested, only those can be used */
479 if( sepadata->onlycontrows )
480 {
481 cols = SCIProwGetCols(prob_rows[r]);
482 iscontrow = TRUE;
483
484 /* check row for integral variables */
485 for( j = 0; j < SCIProwGetNNonz(prob_rows[r]); ++j )
486 {
487 if( SCIPcolIsIntegral(cols[j]) )
488 {
489 iscontrow = FALSE;
490 break;
491 }
492 }
493
494 if( !iscontrow )
495 continue;
496 }
497
498 /* don't try to use rows that have been generated by the RLT separator */
499 if( SCIProwGetOriginSepa(prob_rows[r]) == sepa )
500 continue;
501
502 /* if we are here, the row has passed all checks and should be added to rows */
503 rows[new_nrows] = prob_rows[r];
504 SCIP_CALL( SCIPhashmapSetImageInt(row_to_pos, (void*)(size_t)SCIProwGetIndex(prob_rows[r]), new_nrows) ); /*lint !e571 */
505 ++new_nrows;
506 }
507
508 *nrows = new_nrows;
509
510 return SCIP_OKAY;
511}
512
513/** make sure that the arrays in sepadata are large enough to store information on n variables */
514static
516 SCIP* scip, /**< SCIP data structure */
517 SCIP_SEPADATA* sepadata, /**< separator data */
518 int n /**< number of variables that we need to store */
519 )
520{
521 int newsize;
522
523 /* check whether array is large enough */
524 if( n <= sepadata->sbilinvars )
525 return SCIP_OKAY;
526
527 /* compute new size */
528 newsize = SCIPcalcMemGrowSize(scip, n);
529 assert(n <= newsize);
530
531 /* realloc arrays */
532 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->varssorted, sepadata->sbilinvars, newsize) );
533 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->varpriorities, sepadata->sbilinvars, newsize) );
534
535 sepadata->sbilinvars = newsize;
536
537 return SCIP_OKAY;
538}
539
540/** saves variables x and y to separator data and stores information about their connection
541 *
542 * variables must be captured separately
543 */
544static
546 SCIP* scip, /**< SCIP data structure */
547 SCIP_SEPADATA* sepadata, /**< separator data */
548 SCIP_VAR* x, /**< x variable */
549 SCIP_VAR* y, /**< y variable */
550 SCIP_HASHMAP* varmap, /**< hashmap linking var index to position */
551 int nlocks /**< number of locks */
552 )
553{
554 int xpos;
555 int ypos;
556 int xidx;
557 int yidx;
558 SCIP_VAR* vars[2];
559
560 if( sepadata->bilinvardatamap == NULL )
561 {
562 int varmapsize;
563 int nvars;
564
565 /* the number of variables participating in bilinear products cannot exceed twice the number of bilinear terms;
566 * however, if we detect hidden products, the number of terms is yet unknown, so use the number of variables
567 */
569 varmapsize = sepadata->detecthidden ? nvars : MIN(nvars, sepadata->nbilinterms * 2);
570
571 SCIP_CALL( SCIPhashmapCreate(&sepadata->bilinvardatamap, SCIPblkmem(scip), varmapsize) );
572 }
573
574 xidx = SCIPvarGetIndex(x);
575 yidx = SCIPvarGetIndex(y);
576
577 xpos = SCIPhashmapGetImageInt(varmap, (void*)(size_t) xidx); /*lint !e571 */
578
579 if( xpos == INT_MAX )
580 {
581 /* add x to sepadata and initialise its priority */
582 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)(size_t) xidx, sepadata->nbilinvars) ); /*lint !e571*/
583 SCIP_CALL( ensureVarsSize(scip, sepadata, sepadata->nbilinvars + 1) );
584 sepadata->varssorted[sepadata->nbilinvars] = x;
585 sepadata->varpriorities[sepadata->nbilinvars] = 0;
586 xpos = sepadata->nbilinvars;
587 ++sepadata->nbilinvars;
588 }
589
590 assert(xpos >= 0 && xpos < sepadata->nbilinvars );
591 assert(xpos == SCIPhashmapGetImageInt(varmap, (void*)(size_t) xidx)); /*lint !e571 */
592
593 /* add locks to priority of x */
594 sepadata->varpriorities[xpos] += nlocks;
595
596 if( xidx != yidx )
597 {
598 ypos = SCIPhashmapGetImageInt(varmap, (void*)(size_t) yidx); /*lint !e571 */
599
600 if( ypos == INT_MAX )
601 {
602 /* add y to sepadata and initialise its priority */
603 SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)(size_t) yidx, sepadata->nbilinvars) ); /*lint !e571*/
604 SCIP_CALL( ensureVarsSize(scip, sepadata, sepadata->nbilinvars + 1) );
605 sepadata->varssorted[sepadata->nbilinvars] = y;
606 sepadata->varpriorities[sepadata->nbilinvars] = 0;
607 ypos = sepadata->nbilinvars;
608 ++sepadata->nbilinvars;
609 }
610
611 assert(ypos >= 0 && ypos < sepadata->nbilinvars);
612 assert(ypos == SCIPhashmapGetImageInt(varmap, (void*)(size_t) yidx)); /*lint !e571 */
613
614 /* add locks to priority of y */
615 sepadata->varpriorities[ypos] += nlocks;
616 }
617
618 /* remember the connection between x and y */
619 vars[0] = x;
620 vars[1] = y;
621 SCIP_CALL( addAdjacentVars(scip, sepadata->bilinvardatamap, vars) );
622
623 return SCIP_OKAY;
624}
625
626/** extract a bilinear product from two linear relations, if possible
627 *
628 * First, the two given rows are brought to the form:
629 * \f[
630 * a_1x + b_1w + c_1y \leq/\geq d_1,\\
631 * a_2x + b_2w + c_2y \leq/\geq d_2,
632 * \f]
633 * where \f$ a_1a_2 \leq 0 \f$ and the first implied relation is enabled when \f$ x = 1 \f$
634 * and the second when \f$ x = 0 \f$, and \f$ b_1, b_2 > 0 \f$, the product relation can be written as:
635 * \f[
636 * \frac{b_1b_2w + (b_2(a_1 - d_1) + b_1d_2)x + b_1c_2y - b_1d_2}{b_1c_2 - c_1b_2} \leq/\geq xy.
637 * \f]
638 * The inequality sign in the product relation is similar to that in the given linear relations if
639 * \f$ b_1c_2 - c_1b_2 > 0 \f$ and opposite if \f$ b_1c_2 - c_1b_2 > 0 \f$.
640 *
641 * To obtain this formula, the given relations are first multiplied by scaling factors \f$ \alpha \f$
642 * and \f$ \beta \f$, which is necessary in order for the solution to always exist, and written as
643 * implications:
644 * \f{align}{
645 * x = 1 & ~\Rightarrow~ \alpha b_1w + \alpha c_1y \leq/\geq \alpha(d_1 - a_1), \\
646 * x = 0 & ~\Rightarrow~ \beta b_2w + \beta c_2y \leq/\geq \beta d_2.
647 * \f}
648 * Then a linear system is solved which ensures that the coefficients of the two implications of the product
649 * relation are equal to the corresponding coefficients in the linear relations.
650 * If the product relation is written as:
651 * \f[
652 * Ax + Bw + Cy + D \leq/\geq xy,
653 * \f]
654 * then the system is
655 * \f[
656 * B = \alpha b_1, ~C - 1 = \alpha c_1, ~D+A = \alpha(a_1-d_1),\\
657 * B = \beta b_2, ~C = \beta c_2, ~D = -\beta d_2.
658 * \f]
659 */
660static
662 SCIP* scip, /**< SCIP data structure */
663 SCIP_SEPADATA* sepadata, /**< separator data */
664 SCIP_VAR** vars_xwy, /**< 3 variables involved in the inequalities in the order x,w,y */
665 SCIP_Real* coefs1, /**< coefficients of the first inequality (always implied, i.e. has x) */
666 SCIP_Real* coefs2, /**< coefficients of the second inequality (can be unconditional) */
667 SCIP_Real d1, /**< side of the first inequality */
668 SCIP_Real d2, /**< side of the second inequality */
669 SCIP_SIDETYPE sidetype1, /**< side type (lhs or rls) in the first inequality */
670 SCIP_SIDETYPE sidetype2, /**< side type (lhs or rhs) in the second inequality */
671 SCIP_HASHMAP* varmap, /**< variable map */
672 SCIP_Bool f /**< the first relation is an implication x == f */
673 )
674{
675 SCIP_Real mult;
676
677 /* coefficients and constant of the auxexpr */
678 SCIP_Real A; /* coefficient of x */
679 SCIP_Real B; /* coefficient of w */
680 SCIP_Real C; /* coefficient of y */
681 SCIP_Real D; /* constant */
682
683 /* variables */
684 SCIP_VAR* w;
685 SCIP_VAR* x;
686 SCIP_VAR* y;
687
688 /* does auxexpr overestimate the product? */
689 SCIP_Bool overestimate;
690
691 /* coefficients in given relations: a for x, b for w, c for y; 1 and 2 for 1st and 2nd relation, respectively */
692 SCIP_Real a1 = coefs1[0];
693 SCIP_Real b1 = coefs1[1];
694 SCIP_Real c1 = coefs1[2];
695 SCIP_Real a2 = coefs2[0];
696 SCIP_Real b2 = coefs2[1];
697 SCIP_Real c2 = coefs2[2];
698
699 x = vars_xwy[0];
700 w = vars_xwy[1];
701 y = vars_xwy[2];
702
703 /* check given linear relations and decide if to continue */
704
705 assert(SCIPvarGetType(x) == SCIP_VARTYPE_BINARY); /* x must be binary */
706 assert(a1 != 0.0); /* the first relation is always conditional */
707 assert(b1 != 0.0 || b2 != 0.0); /* at least one w coefficient must be nonzero */
708
709 SCIPdebugMsg(scip, "Extracting product from two implied relations:\n");
710 SCIPdebugMsg(scip, "Relation 1: <%s> == %u => %g<%s> + %g<%s> %s %g\n", SCIPvarGetName(x), f, b1,
711 SCIPvarGetName(w), c1, SCIPvarGetName(y), sidetype1 == SCIP_SIDETYPE_LEFT ? ">=" : "<=",
712 f ? d1 - a1 : d1);
713 SCIPdebugMsg(scip, "Relation 2: <%s> == %d => %g<%s> + %g<%s> %s %g\n", SCIPvarGetName(x), !f, b2,
714 SCIPvarGetName(w), c2, SCIPvarGetName(y), sidetype2 == SCIP_SIDETYPE_LEFT ? ">=" : "<=",
715 f ? d2 : d2 - a2);
716
717 /* cannot use a global bound on x to detect a product */
718 if( (b1 == 0.0 && c1 == 0.0) || (b2 == 0.0 && c2 == 0.0) )
719 return SCIP_OKAY;
720
721 /* cannot use a global bound on y to detect a non-redundant product relation */
722 if( a2 == 0.0 && b2 == 0.0 ) /* only check the 2nd relation because the 1st at least has x */
723 {
724 SCIPdebugMsg(scip, "Ignoring a global bound on y\n");
725 return SCIP_OKAY;
726 }
727
728 SCIPdebugMsg(scip, "binary var = <%s>, product of its coefs: %g\n", SCIPvarGetName(x), a1*a2);
729
730 /* rewrite the linear relations in a standard form:
731 * a1x + b1w + c1y <=/>= d1,
732 * a2x + b2w + c2y <=/>= d2,
733 * where b1 > 0, b2 > 0 and first implied relation is activated when x == 1
734 */
735
736 /* if needed, multiply the rows by -1 so that coefs of w are positive */
737 if( b1 < 0 )
738 {
739 a1 *= -1.0;
740 b1 *= -1.0;
741 c1 *= -1.0;
742 d1 *= -1.0;
743 sidetype1 = sidetype1 == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT;
744 }
745 if( b2 < 0 )
746 {
747 a2 *= -1.0;
748 b2 *= -1.0;
749 c2 *= -1.0;
750 d2 *= -1.0;
751 sidetype2 = sidetype2 == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT;
752 }
753
754 /* the linear relations imply a product only if the inequality signs are similar */
755 if( sidetype1 != sidetype2 )
756 return SCIP_OKAY;
757
758 /* when b1c2 = b2c1, the linear relations do not imply a product relation */
759 if( SCIPisRelEQ(scip, b2*c1, c2*b1) )
760 {
761 SCIPdebugMsg(scip, "Ignoring a pair of linear relations because b1c2 = b2c1\n");
762 return SCIP_OKAY;
763 }
764
765 if( !f )
766 {
767 /* swap the linear relations so that the relation implied by x == TRUE goes first */
768 SCIPswapReals(&a1, &a2);
769 SCIPswapReals(&b1, &b2);
770 SCIPswapReals(&c1, &c2);
771 SCIPswapReals(&d1, &d2);
772 }
773
774 /* all conditions satisfied, we can extract the product and write it as:
775 * (1/(b1c2 - c1b2))*(b1b2w + (b2(a1 - d1) + b1d2)x + b1c2y - b1d2) >=/<= xy,
776 * where the inequality sign in the product relation is similar to that in the given linear relations
777 * if b1c2 - c1b2 > 0 and opposite if b1c2 - c1b2 > 0
778 */
779
780 /* compute the multiplier */
781 mult = 1/(b1*c2 - c1*b2);
782
783 /* determine the inequality sign; only check sidetype1 because sidetype2 is equal to it */
784 overestimate = (sidetype1 == SCIP_SIDETYPE_LEFT && mult > 0.0) || (sidetype1 == SCIP_SIDETYPE_RIGHT && mult < 0.0);
785
786 SCIPdebugMsg(scip, "found suitable implied rels (w,x,y): %g<%s> + %g<%s> + %g<%s> <= %g\n", a1,
788 SCIPdebugMsg(scip, " and %g<%s> + %g<%s> + %g<%s> <= %g\n", a2, SCIPvarGetName(x),
789 b2, SCIPvarGetName(w), c2, SCIPvarGetName(y), d2);
790
791 /* compute the coefficients for x, w and y and the constant in auxexpr */
792 A = (b2*a1 - d1*b2 + d2*b1)*mult;
793 B = b1*b2*mult;
794 C = b1*c2*mult;
795 D = -b1*d2*mult;
796
797 SCIPdebugMsg(scip, "product: <%s><%s> %s %g<%s> + %g<%s> + %g<%s> + %g\n", SCIPvarGetName(x), SCIPvarGetName(y),
798 overestimate ? "<=" : ">=", A, SCIPvarGetName(x), B, SCIPvarGetName(w), C, SCIPvarGetName(y), D);
799
800 SCIP_CALL( addProductVars(scip, sepadata, x, y, varmap, 1) );
801 SCIP_CALL( SCIPinsertBilinearTermImplicitNonlinear(scip, sepadata->conshdlr, x, y, w, A, C, B, D, overestimate) );
802
803 return SCIP_OKAY;
804}
805
806/** convert an implied bound: `binvar` = `binval` &rArr; `implvar` &le;/&ge; `implbnd` into a big-M constraint */
807static
809 SCIP* scip, /**< SCIP data structure */
810 SCIP_VAR** vars_xwy, /**< variables in order x,w,y */
811 int binvarpos, /**< position of binvar in vars_xwy */
812 int implvarpos, /**< position of implvar in vars_xwy */
813 SCIP_BOUNDTYPE bndtype, /**< type of implied bound */
814 SCIP_Bool binval, /**< value of binvar which implies the bound */
815 SCIP_Real implbnd, /**< value of the implied bound */
816 SCIP_Real* coefs, /**< coefficients of the big-M constraint */
817 SCIP_Real* side /**< side of the big-M constraint */
818 )
819{
820 SCIP_VAR* implvar;
821 SCIP_Real globbnd;
822
823 assert(vars_xwy != NULL);
824 assert(coefs != NULL);
825 assert(side != NULL);
826 assert(binvarpos != implvarpos);
827
828 implvar = vars_xwy[implvarpos];
829 globbnd = bndtype == SCIP_BOUNDTYPE_LOWER ? SCIPvarGetLbGlobal(implvar) : SCIPvarGetUbGlobal(implvar);
830
831 /* Depending on the bound type and binval, there are four possibilities:
832 * binvar == 1 => implvar >= implbnd <=> (implvar^l - implbnd)binvar + implvar >= implvar^l;
833 * binvar == 0 => implvar >= implbnd <=> (implbnd - implvar^l)binvar + implvar >= implbnd;
834 * binvar == 1 => implvar <= implbnd <=> (implvar^u - implbnd)binvar + implvar <= implvar^u;
835 * binvar == 0 => implvar <= implbnd <=> (implbnd - implvar^u)binvar + implvar <= implbnd.
836 */
837
838 coefs[0] = 0.0;
839 coefs[1] = 0.0;
840 coefs[2] = 0.0;
841 coefs[binvarpos] = binval ? globbnd - implbnd : implbnd - globbnd;
842 coefs[implvarpos] = 1.0;
843 *side = binval ? globbnd : implbnd;
844
845 SCIPdebugMsg(scip, "Got an implied relation with binpos = %d, implpos = %d, implbnd = %g, "
846 "bnd type = %s, binval = %u, glbbnd = %g\n", binvarpos, implvarpos, implbnd,
847 bndtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", binval, globbnd);
848 SCIPdebugMsg(scip, "Constructed big-M: %g*bvar + implvar %s %g\n", coefs[binvarpos],
849 bndtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", *side);
850}
851
852/** extract products from a relation given by coefs1, vars, side1 and sidetype1 and
853 * implied bounds of the form `binvar` = `!f` &rArr; `implvar` &ge;/&le; `implbnd`
854 */
855static
857 SCIP* scip, /**< SCIP data structure */
858 SCIP_SEPADATA* sepadata, /**< separator data */
859 SCIP_Real* coefs1, /**< coefficients of the first linear relation */
860 SCIP_VAR** vars_xwy, /**< variables in the order x, w, y */
861 SCIP_Real side1, /**< side of the first relation */
862 SCIP_SIDETYPE sidetype1, /**< is the left or right hand side given for the first relation? */
863 int binvarpos, /**< position of the indicator variable in the vars_xwy array */
864 int implvarpos, /**< position of the variable that is bounded */
865 SCIP_HASHMAP* varmap, /**< variable map */
866 SCIP_Bool f /**< the value of x that activates the first relation */
867 )
868{
869 SCIP_Real coefs2[3] = { 0., 0., 0. };
870 SCIP_Real impllb;
871 SCIP_Real implub;
872 SCIP_VAR* binvar;
873 SCIP_VAR* implvar;
874 SCIP_Real side2;
875 int i;
876 SCIP_Bool binvals[2] = {!f, f};
877
878 assert(binvarpos != implvarpos);
879 assert(implvarpos != 0); /* implied variable must be continuous, therefore it can't be x */
880
881 binvar = vars_xwy[binvarpos];
882 implvar = vars_xwy[implvarpos];
883
886
887 /* loop over binvals; if binvar is x (case binvarpos == 0), then we want to use only implications from
888 * binvar == !f (which is the option complementing the first relation, which is implied from f); if
889 * binvar is not x, this doesn't matter since the implbnd doesn't depend on x, therefore try both !f and f
890 */
891 for( i = 0; i < (binvarpos == 0 ? 1 : 2); ++i )
892 {
893 /* get implications binvar == binval => implvar <=/>= implbnd */
894 SCIPvarGetImplicVarBounds(binvar, binvals[i], implvar, &impllb, &implub);
895
896 if( impllb != SCIP_INVALID ) /*lint !e777*/
897 {
898 /* write the implied bound as a big-M constraint */
899 implBndToBigM(scip, vars_xwy, binvarpos, implvarpos, SCIP_BOUNDTYPE_LOWER, binvals[i], impllb, coefs2, &side2);
900
901 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1, side2, sidetype1,
902 SCIP_SIDETYPE_LEFT, varmap, f) );
903 }
904
905 if( implub != SCIP_INVALID ) /*lint !e777*/
906 {
907 /* write the implied bound as a big-M constraint */
908 implBndToBigM(scip, vars_xwy, binvarpos, implvarpos, SCIP_BOUNDTYPE_UPPER, binvals[i], implub, coefs2, &side2);
909
910 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1, side2, sidetype1,
911 SCIP_SIDETYPE_RIGHT, varmap, f) );
912 }
913 }
914
915 return SCIP_OKAY;
916}
917
918/** extract products from a relation given by `coefs1`, `vars_xwy`, `side1` and `sidetype1` and
919 * cliques containing `vars_xwy[varpos1]` and `vars_xwy[varpos2]`
920 */
921static
923 SCIP* scip, /**< SCIP data structure */
924 SCIP_SEPADATA* sepadata, /**< separator data */
925 SCIP_Real* coefs1, /**< coefficients of the first linear relation */
926 SCIP_VAR** vars_xwy, /**< variables of the first relation in the order x, w, y */
927 SCIP_Real side1, /**< side of the first relation */
928 SCIP_SIDETYPE sidetype1, /**< is the left or right hand side given for the first relation? */
929 int varpos1, /**< position of the first variable in the vars_xwy array */
930 int varpos2, /**< position of the second variable in the vars_xwy array */
931 SCIP_HASHMAP* varmap, /**< variable map */
932 SCIP_Bool f /**< the value of x that activates the first relation */
933 )
934{
935 SCIP_Real coefs2[3] = { 0., 0., 0. };
936 SCIP_VAR* var1;
937 SCIP_VAR* var2;
938 SCIP_Real side2;
939 int i;
940 int imax;
941 SCIP_Bool binvals[2] = {!f, f};
942
943 var1 = vars_xwy[varpos1];
944 var2 = vars_xwy[varpos2];
945
946 /* this decides whether we do one or two iterations of the loop for binvals: if var1
947 * or var2 is x, we only want cliques with x = !f (which is the option complementing
948 * the first relation, which is implied from f); otherwise this doesn't matter since
949 * the clique doesn't depend on x, therefore try both !f and f
950 */
951 imax = (varpos1 == 0 || varpos2 == 0) ? 1 : 2;
952
955
956 for( i = 0; i < imax; ++i )
957 {
958 /* if var1=TRUE and var2=TRUE are in a clique (binvals[i] == TRUE), the relation var1 + var2 <= 1 is implied
959 * if var1=FALSE and var2=TRUE are in a clique (binvals[i] == FALSE), the relation (1 - var1) + var2 <= 1 is implied
960 */
961 if( SCIPvarsHaveCommonClique(var1, binvals[i], var2, TRUE, TRUE) )
962 {
963 SCIPdebugMsg(scip, "vars %s<%s> and <%s> are in a clique\n", binvals[i] ? "" : "!", SCIPvarGetName(var1), SCIPvarGetName(var2));
964 coefs2[varpos1] = binvals[i] ? 1.0 : -1.0;
965 coefs2[varpos2] = 1.0;
966 side2 = binvals[i] ? 1.0 : 0.0;
967
968 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1, side2, sidetype1,
969 SCIP_SIDETYPE_RIGHT, varmap, f) );
970 }
971
972 /* if var1=TRUE and var2=FALSE are in the same clique, the relation var1 + (1-var2) <= 1 is implied
973 * if var1=FALSE and var2=FALSE are in the same clique, the relation (1-var1) + (1-var2) <= 1 is implied
974 */
975 if( SCIPvarsHaveCommonClique(var1, binvals[i], var2, FALSE, TRUE) )
976 {
977 SCIPdebugMsg(scip, "vars %s<%s> and !<%s> are in a clique\n", binvals[i] ? "" : "!", SCIPvarGetName(var1), SCIPvarGetName(var2));
978 coefs2[varpos1] = binvals[i] ? 1.0 : -1.0;
979 coefs2[varpos2] = -1.0;
980 side2 = binvals[i] ? 0.0 : -1.0;
981
982 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1, side2, sidetype1,
983 SCIP_SIDETYPE_RIGHT, varmap, f) );
984 }
985 }
986
987 return SCIP_OKAY;
988}
989
990
991/** extract products from a relation given by `coefs1`, `vars`, `side1` and `sidetype1` and unconditional relations
992 * (inequalities with 2 nonzeros) containing `vars[varpos1]` and `vars[varpos2]`
993 */
994static
996 SCIP* scip, /**< SCIP data structure */
997 SCIP_SEPADATA* sepadata, /**< separator data */
998 SCIP_ROW** rows, /**< problem rows */
999 int* row_list, /**< linked list of rows corresponding to 2 or 3 var sets */
1000 SCIP_HASHTABLE* hashtable, /**< hashtable storing unconditional relations */
1001 SCIP_Real* coefs1, /**< coefficients of the first linear relation */
1002 SCIP_VAR** vars_xwy, /**< variables of the first relation in the order x, w, y */
1003 SCIP_Real side1, /**< side of the first relation */
1004 SCIP_SIDETYPE sidetype1, /**< is the left or right hand side given for the first relation? */
1005 int varpos1, /**< position of the first unconditional variable in the vars_xwy array */
1006 int varpos2, /**< position of the second unconditional variable in the vars_xwy array */
1007 SCIP_HASHMAP* varmap, /**< variable map */
1008 SCIP_Bool f /**< the value of x that activates the first relation */
1009 )
1010{
1011 HASHDATA hashdata;
1012 HASHDATA* foundhashdata;
1013 SCIP_ROW* row2;
1014 int r2;
1015 int pos1;
1016 int pos2;
1017 SCIP_Real coefs2[3] = { 0., 0., 0. };
1018 SCIP_VAR* var1;
1019 SCIP_VAR* var2;
1020
1021 /* always unconditional, therefore x must not be one of the two variables */
1022 assert(varpos1 != 0);
1023 assert(varpos2 != 0);
1024
1025 var1 = vars_xwy[varpos1];
1026 var2 = vars_xwy[varpos2];
1027
1028 hashdata.nvars = 2;
1029 hashdata.firstrow = -1;
1030 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
1031 {
1032 pos1 = 0;
1033 pos2 = 1;
1034 }
1035 else
1036 {
1037 pos1 = 1;
1038 pos2 = 0;
1039 }
1040
1041 hashdata.vars[pos1] = var1;
1042 hashdata.vars[pos2] = var2;
1043
1044 foundhashdata = (HASHDATA*)SCIPhashtableRetrieve(hashtable, &hashdata);
1045
1046 if( foundhashdata != NULL )
1047 {
1048 /* if the var pair exists, use all corresponding rows */
1049 r2 = foundhashdata->firstrow;
1050
1051 while( r2 != -1 )
1052 {
1053 row2 = rows[r2];
1054 assert(SCIProwGetNNonz(row2) == 2);
1055 assert(var1 == SCIPcolGetVar(SCIProwGetCols(row2)[pos1]));
1056 assert(var2 == SCIPcolGetVar(SCIProwGetCols(row2)[pos2]));
1057
1058 coefs2[varpos1] = SCIProwGetVals(row2)[pos1];
1059 coefs2[varpos2] = SCIProwGetVals(row2)[pos2];
1060
1061 SCIPdebugMsg(scip, "Unconditional:\n");
1062 if( !SCIPisInfinity(scip, -SCIProwGetLhs(row2)) )
1063 {
1064 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1065 SCIProwGetLhs(row2) - SCIProwGetConstant(row2), sidetype1, SCIP_SIDETYPE_LEFT, varmap, f) );
1066 }
1067 if( !SCIPisInfinity(scip, SCIProwGetRhs(row2)) )
1068 {
1069 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1070 SCIProwGetRhs(row2) - SCIProwGetConstant(row2), sidetype1, SCIP_SIDETYPE_RIGHT, varmap, f) );
1071 }
1072
1073 r2 = row_list[r2];
1074 }
1075 }
1076
1077 return SCIP_OKAY;
1078}
1079
1080/** finds and stores implied relations (x = f &rArr; ay + bw &le; c, f can be 0 or 1) and 2-variable relations
1081 *
1082 * Fills the following:
1083 *
1084 * - An array of variables that participate in two variable relations; for each such variable, ADJACENTVARDATA
1085 * containing an array of variables that participate in two variable relations together with it; and a hashmap
1086 * mapping variables to ADJACENTVARDATAs.
1087 *
1088 * - Hashtables storing hashdata objects with the two or three variables and the position of the first row in the
1089 * `prob_rows` array, which in combination with the linked list (described below) will allow access to all rows that
1090 * depend only on the corresponding variables.
1091 *
1092 * - Linked lists of row indices. Each list corresponds to a pair or triple of variables and contains positions of rows
1093 * which depend only on those variables. All lists are stored in `row_list`, an array of length `nrows`, which is
1094 * possible because each row belongs to at most one list. The array indices of `row_list` represent the positions of
1095 * rows in `prob_rows`, and a value in the `row_list` array represents the next index in the list (-1 if there is no next
1096 * list element). The first index of each list is stored in one of the hashdata objects as firstrow.
1097 */
1098static
1100 SCIP* scip, /**< SCIP data structure */
1101 SCIP_ROW** prob_rows, /**< linear rows of the problem */
1102 int nrows, /**< number of rows */
1103 SCIP_HASHTABLE* hashtable2, /**< hashtable to store 2-variable relations */
1104 SCIP_HASHTABLE* hashtable3, /**< hashtable to store implied relations */
1105 SCIP_HASHMAP* vars_in_2rels, /**< connections between variables that appear in 2-variable relations */
1106 int* row_list /**< linked lists of row positions for each 2 or 3 variable set */
1107 )
1108{
1109 int r;
1110 SCIP_COL** cols;
1111 HASHDATA searchhashdata;
1112 HASHDATA* elementhashdata;
1113
1114 assert(prob_rows != NULL);
1115 assert(nrows > 0);
1116 assert(hashtable2 != NULL);
1117 assert(hashtable3 != NULL);
1118 assert(vars_in_2rels != NULL);
1119 assert(row_list != NULL);
1120
1121 for( r = 0; r < nrows; ++r )
1122 {
1123 assert(prob_rows[r] != NULL);
1124
1125 cols = SCIProwGetCols(prob_rows[r]);
1126 assert(cols != NULL);
1127
1128 /* initialise with the "end of list" value */
1129 row_list[r] = -1;
1130
1131 /* look for unconditional relations with 2 variables */
1132 if( SCIProwGetNNonz(prob_rows[r]) == 2 )
1133 {
1134 /* if at least one of the variables is binary, this is either an implied bound
1135 * or a clique; these are covered separately */
1138 {
1139 SCIPdebugMsg(scip, "ignoring relation <%s> because a var is binary\n", SCIProwGetName(prob_rows[r]));
1140 continue;
1141 }
1142
1143 /* fill in searchhashdata so that to search for the two variables in hashtable2 */
1144 searchhashdata.nvars = 2;
1145 searchhashdata.firstrow = -1;
1146 searchhashdata.vars[0] = SCIPcolGetVar(cols[0]);
1147 searchhashdata.vars[1] = SCIPcolGetVar(cols[1]);
1148
1149 /* get the element corresponding to the two variables */
1150 elementhashdata = (HASHDATA*)SCIPhashtableRetrieve(hashtable2, &searchhashdata);
1151
1152 if( elementhashdata != NULL )
1153 {
1154 /* if element exists, update it by adding the row */
1155 row_list[r] = elementhashdata->firstrow;
1156 elementhashdata->firstrow = r;
1157 ++elementhashdata->nrows;
1158 }
1159 else
1160 {
1161 /* create an element for the combination of two variables */
1162 SCIP_CALL( SCIPallocBuffer(scip, &elementhashdata) );
1163
1164 elementhashdata->nvars = 2;
1165 elementhashdata->nrows = 1;
1166 elementhashdata->vars[0] = searchhashdata.vars[0];
1167 elementhashdata->vars[1] = searchhashdata.vars[1];
1168 elementhashdata->firstrow = r;
1169
1170 SCIP_CALL( SCIPhashtableInsert(hashtable2, (void*)elementhashdata) );
1171
1172 /* hashdata.vars are two variables participating together in a two variable relation, therefore update
1173 * these variables' adjacency data
1174 */
1175 SCIP_CALL( addAdjacentVars(scip, vars_in_2rels, searchhashdata.vars) );
1176 }
1177 }
1178
1179 /* look for implied relations (three variables, at least one binary variable) */
1180 if( SCIProwGetNNonz(prob_rows[r]) == 3 )
1181 {
1182 /* an implied relation contains at least one binary variable */
1186 continue;
1187
1188 /* fill in hashdata so that to search for the three variables in hashtable3 */
1189 searchhashdata.nvars = 3;
1190 searchhashdata.firstrow = -1;
1191 searchhashdata.vars[0] = SCIPcolGetVar(cols[0]);
1192 searchhashdata.vars[1] = SCIPcolGetVar(cols[1]);
1193 searchhashdata.vars[2] = SCIPcolGetVar(cols[2]);
1194
1195 /* get the element corresponding to the three variables */
1196 elementhashdata = (HASHDATA*)SCIPhashtableRetrieve(hashtable3, &searchhashdata);
1197
1198 if( elementhashdata != NULL )
1199 {
1200 /* if element exists, update it by adding the row */
1201 row_list[r] = elementhashdata->firstrow;
1202 elementhashdata->firstrow = r;
1203 ++elementhashdata->nrows;
1204 }
1205 else
1206 {
1207 /* create an element for the combination of three variables */
1208 SCIP_CALL( SCIPallocBuffer(scip, &elementhashdata) );
1209
1210 elementhashdata->nvars = 3;
1211 elementhashdata->nrows = 1;
1212 elementhashdata->vars[0] = searchhashdata.vars[0];
1213 elementhashdata->vars[1] = searchhashdata.vars[1];
1214 elementhashdata->vars[2] = searchhashdata.vars[2];
1215 elementhashdata->firstrow = r;
1216
1217 SCIP_CALL( SCIPhashtableInsert(hashtable3, (void*)elementhashdata) );
1218 }
1219 }
1220 }
1221
1222 return SCIP_OKAY;
1223}
1224
1225/** detect bilinear products encoded in linear constraints */
1226static
1228 SCIP* scip, /**< SCIP data structure */
1229 SCIP_SEPADATA* sepadata, /**< separation data */
1230 SCIP_HASHMAP* varmap /**< variable map */
1231 )
1232{
1233 int r1; /* first relation index */
1234 int r2; /* second relation index */
1235 int i; /* outer loop counter */
1236 int permwy; /* index for permuting w and y */
1237 int nrows;
1238 SCIP_ROW** prob_rows;
1239 SCIP_HASHTABLE* hashtable3;
1240 SCIP_HASHTABLE* hashtable2;
1241 HASHDATA* foundhashdata;
1242 SCIP_VAR* vars_xwy[3];
1243 SCIP_Real coefs1[3];
1244 SCIP_Real coefs2[3];
1245 SCIP_ROW* row1;
1246 SCIP_ROW* row2;
1247 int xpos;
1248 int ypos;
1249 int wpos;
1250 int f; /* value of the binary variable */
1251 SCIP_VAR** relatedvars;
1252 int nrelatedvars;
1253 SCIP_Bool xfixing;
1254 SCIP_SIDETYPE sidetype1;
1255 SCIP_SIDETYPE sidetype2;
1256 SCIP_Real side1;
1257 SCIP_Real side2;
1258 int* row_list;
1259 SCIP_HASHMAP* vars_in_2rels;
1260 int nvars;
1261
1262 /* get the (original) rows */
1263 SCIP_CALL( getOriginalRows(scip, &prob_rows, &nrows) );
1264
1265 if( nrows == 0 )
1266 {
1267 SCIPfreeBufferArray(scip, &prob_rows);
1268 return SCIP_OKAY;
1269 }
1270
1271 /* create tables of implied and unconditional relations */
1272 SCIP_CALL( SCIPhashtableCreate(&hashtable3, SCIPblkmem(scip), nrows, SCIPhashGetKeyStandard,
1273 hashdataKeyEqConss, hashdataKeyValConss, NULL) );
1274 SCIP_CALL( SCIPhashtableCreate(&hashtable2, SCIPblkmem(scip), nrows, SCIPhashGetKeyStandard,
1275 hashdataKeyEqConss, hashdataKeyValConss, NULL) );
1276 SCIP_CALL( SCIPallocBufferArray(scip, &row_list, nrows) );
1277
1278 /* allocate the adjacency data map for variables that appear in 2-var relations */
1280 SCIP_CALL( SCIPhashmapCreate(&vars_in_2rels, SCIPblkmem(scip), MIN(nvars, nrows * 2)) );
1281
1282 /* fill the data structures that will be used for product detection: hashtables and linked lists allowing to access
1283 * two and three variable relations by the variables; and the hashmap for accessing variables participating in two
1284 * variable relations with each given variable */
1285 SCIP_CALL( fillRelationTables(scip, prob_rows, nrows, hashtable2, hashtable3, vars_in_2rels, row_list) );
1286
1287 /* start actually looking for products */
1288 /* go through all sets of three variables */
1289 for( i = 0; i < SCIPhashtableGetNEntries(hashtable3); ++i )
1290 {
1291 foundhashdata = (HASHDATA*)SCIPhashtableGetEntry(hashtable3, i);
1292 if( foundhashdata == NULL )
1293 continue;
1294
1295 SCIPdebugMsg(scip, "(<%s>, <%s>, <%s>): ", SCIPvarGetName(foundhashdata->vars[0]),
1296 SCIPvarGetName(foundhashdata->vars[1]), SCIPvarGetName(foundhashdata->vars[2]));
1297
1298 /* An implied relation has the form: x == f => l(w,y) <=/>= side (f is 0 or 1, l is a linear function). Given
1299 * a linear relation with three variables, any binary var can be x: we try them all here because this can
1300 * produce different products.
1301 */
1302 for( xpos = 0; xpos < 3; ++xpos )
1303 {
1304 /* in vars_xwy, the order of variables is always as in the name: x, w, y */
1305 vars_xwy[0] = foundhashdata->vars[xpos];
1306
1307 /* x must be binary */
1308 if( SCIPvarGetType(vars_xwy[0]) != SCIP_VARTYPE_BINARY )
1309 continue;
1310
1311 /* the first row might be an implication from f == 0 or f == 1: try both */
1312 for( f = 0; f <= 1; ++f )
1313 {
1314 xfixing = f == 1;
1315
1316 /* go through implied relations for the corresponding three variables */
1317 for( r1 = foundhashdata->firstrow; r1 != -1; r1 = row_list[r1] )
1318 {
1319 /* get the implied relation */
1320 row1 = prob_rows[r1];
1321
1322 assert(SCIProwGetNNonz(row1) == 3);
1323 /* the order of variables in all rows should be the same, and similar to the order in hashdata->vars,
1324 * therefore the x variable from vars_xwy should be similar to the column variable at xpos
1325 */
1326 assert(vars_xwy[0] == SCIPcolGetVar(SCIProwGetCols(row1)[xpos]));
1327
1328 coefs1[0] = SCIProwGetVals(row1)[xpos];
1329
1330 /* use the side for which the inequality becomes tighter when x == xfixing than when x == !xfixing */
1331 if( (!xfixing && coefs1[0] > 0.0) || (xfixing && coefs1[0] < 0.0) )
1332 {
1333 sidetype1 = SCIP_SIDETYPE_LEFT;
1334 side1 = SCIProwGetLhs(row1);
1335 }
1336 else
1337 {
1338 sidetype1 = SCIP_SIDETYPE_RIGHT;
1339 side1 = SCIProwGetRhs(row1);
1340 }
1341
1342 if( SCIPisInfinity(scip, REALABS(side1)) )
1343 continue;
1344
1345 side1 -= SCIProwGetConstant(row1);
1346
1347 /* permute w and y */
1348 for( permwy = 1; permwy <= 2; ++permwy )
1349 {
1350 wpos = (xpos + permwy) % 3;
1351 ypos = (xpos - permwy + 3) % 3;
1352 vars_xwy[1] = foundhashdata->vars[wpos];
1353 vars_xwy[2] = foundhashdata->vars[ypos];
1354
1355 assert(vars_xwy[1] == SCIPcolGetVar(SCIProwGetCols(row1)[wpos]));
1356 assert(vars_xwy[2] == SCIPcolGetVar(SCIProwGetCols(row1)[ypos]));
1357
1358 coefs1[1] = SCIProwGetVals(row1)[wpos];
1359 coefs1[2] = SCIProwGetVals(row1)[ypos];
1360
1361 /* look for the second relation: it should be tighter when x == !xfixing than when x == xfixing
1362 * and can be either another implied relation or one of several types of two and one variable
1363 * relations
1364 */
1365
1366 /* go through the remaining rows (implied relations) for these three variables */
1367 for( r2 = row_list[r1]; r2 != -1; r2 = row_list[r2] )
1368 {
1369 /* get the second implied relation */
1370 row2 = prob_rows[r2];
1371
1372 assert(SCIProwGetNNonz(row2) == 3);
1373 assert(vars_xwy[0] == SCIPcolGetVar(SCIProwGetCols(row2)[xpos]));
1374 assert(vars_xwy[1] == SCIPcolGetVar(SCIProwGetCols(row2)[wpos]));
1375 assert(vars_xwy[2] == SCIPcolGetVar(SCIProwGetCols(row2)[ypos]));
1376
1377 coefs2[0] = SCIProwGetVals(row2)[xpos];
1378 coefs2[1] = SCIProwGetVals(row2)[wpos];
1379 coefs2[2] = SCIProwGetVals(row2)[ypos];
1380
1381 /* use the side for which the inequality becomes tighter when x == !xfixing than when x == xfixing */
1382 if( (!xfixing && coefs2[0] > 0.0) || (xfixing && coefs2[0] < 0.0) )
1383 {
1384 sidetype2 = SCIP_SIDETYPE_RIGHT;
1385 side2 = SCIProwGetRhs(row2);
1386 }
1387 else
1388 {
1389 sidetype2 = SCIP_SIDETYPE_LEFT;
1390 side2 = SCIProwGetLhs(row2);
1391 }
1392
1393 if( SCIPisInfinity(scip, REALABS(side2)) )
1394 continue;
1395
1396 side2 -= SCIProwGetConstant(row2);
1397
1398 SCIPdebugMsg(scip, "Two implied relations:\n");
1399 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1, side2, sidetype1,
1400 sidetype2, varmap, xfixing) );
1401 }
1402
1403 /* use global bounds on w */
1404 coefs2[0] = 0.0;
1405 coefs2[1] = 1.0;
1406 coefs2[2] = 0.0;
1407 SCIPdebugMsg(scip, "w global bounds:\n");
1408 if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(vars_xwy[1])) )
1409 {
1410 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1411 SCIPvarGetLbGlobal(vars_xwy[1]), sidetype1, SCIP_SIDETYPE_LEFT, varmap, xfixing) );
1412 }
1413
1414 if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(vars_xwy[1])) )
1415 {
1416 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1417 SCIPvarGetUbGlobal(vars_xwy[1]), sidetype1, SCIP_SIDETYPE_RIGHT, varmap, xfixing) );
1418 }
1419
1420 /* use implied bounds and cliques with w */
1421 if( SCIPvarGetType(vars_xwy[1]) != SCIP_VARTYPE_BINARY )
1422 {
1423 /* w is non-binary - look for implied bounds x == !f => w >=/<= bound */
1424 SCIPdebugMsg(scip, "Implied relation + implied bounds on w:\n");
1425 SCIP_CALL( detectProductsImplbnd(scip, sepadata, coefs1, vars_xwy, side1, sidetype1, 0, 1,
1426 varmap, xfixing) );
1427 }
1428 else
1429 {
1430 /* w is binary - look for cliques containing x and w */
1431 SCIPdebugMsg(scip, "Implied relation + cliques with x and w:\n");
1432 SCIP_CALL( detectProductsClique(scip, sepadata, coefs1, vars_xwy, side1, sidetype1, 0, 1,
1433 varmap, xfixing) );
1434 }
1435
1436 /* use unconditional relations (i.e. relations of w and y) */
1437
1438 /* implied bound w == 0/1 => y >=/<= bound */
1439 if( SCIPvarGetType(vars_xwy[1]) == SCIP_VARTYPE_BINARY && SCIPvarGetType(vars_xwy[2]) != SCIP_VARTYPE_BINARY )
1440 {
1441 SCIPdebugMsg(scip, "Implied relation + implied bounds with w and y:\n");
1442 SCIP_CALL( detectProductsImplbnd(scip, sepadata, coefs1, vars_xwy, side1, sidetype1, 1, 2, varmap, xfixing) );
1443 }
1444
1445 /* implied bound y == 0/1 => w >=/<= bound */
1446 if( SCIPvarGetType(vars_xwy[2]) == SCIP_VARTYPE_BINARY && SCIPvarGetType(vars_xwy[1]) != SCIP_VARTYPE_BINARY )
1447 {
1448 SCIPdebugMsg(scip, "Implied relation + implied bounds with y and w:\n");
1449 SCIP_CALL( detectProductsImplbnd(scip, sepadata, coefs1, vars_xwy, side1, sidetype1, 2, 1, varmap, xfixing) );
1450 }
1451
1452 /* cliques containing w and y */
1453 if( SCIPvarGetType(vars_xwy[1]) == SCIP_VARTYPE_BINARY && SCIPvarGetType(vars_xwy[2]) == SCIP_VARTYPE_BINARY )
1454 {
1455 SCIPdebugMsg(scip, "Implied relation + cliques with w and y:\n");
1456 SCIP_CALL( detectProductsClique(scip, sepadata, coefs1, vars_xwy, side1, sidetype1, 1, 2, varmap, xfixing) );
1457 }
1458
1459 /* inequalities containing w and y */
1460 if( SCIPvarGetType(vars_xwy[1]) != SCIP_VARTYPE_BINARY && SCIPvarGetType(vars_xwy[2]) != SCIP_VARTYPE_BINARY )
1461 {
1462 SCIPdebugMsg(scip, "Implied relation + unconditional with w and y:\n");
1463 SCIP_CALL( detectProductsUnconditional(scip, sepadata, prob_rows, row_list, hashtable2, coefs1,
1464 vars_xwy, side1, sidetype1, 1, 2, varmap, xfixing) );
1465 }
1466 }
1467 }
1468 }
1469 }
1470 SCIPfreeBuffer(scip, &foundhashdata);
1471 }
1472
1473 /* also loop through implied bounds to look for products */
1474 for( i = 0; i < SCIPgetNBinVars(scip); ++i )
1475 {
1476 /* first choose the x variable: it can be any binary variable in the problem */
1477 vars_xwy[0] = SCIPgetVars(scip)[i];
1478
1479 assert(SCIPvarGetType(vars_xwy[0]) == SCIP_VARTYPE_BINARY);
1480
1481 /* consider both possible values of x */
1482 for( f = 0; f <= 1; ++f )
1483 {
1484 xfixing = f == 1;
1485
1486 /* go through implications of x */
1487 for( r1 = 0; r1 < SCIPvarGetNImpls(vars_xwy[0], xfixing); ++r1 )
1488 {
1489 /* w is the implication var */
1490 vars_xwy[1] = SCIPvarGetImplVars(vars_xwy[0], xfixing)[r1];
1491 assert(SCIPvarGetType(vars_xwy[1]) != SCIP_VARTYPE_BINARY);
1492
1493 /* write the implication as a big-M constraint */
1494 implBndToBigM(scip, vars_xwy, 0, 1, SCIPvarGetImplTypes(vars_xwy[0], xfixing)[r1], xfixing,
1495 SCIPvarGetImplBounds(vars_xwy[0], xfixing)[r1], coefs1, &side1);
1496 sidetype1 = SCIPvarGetImplTypes(vars_xwy[0], xfixing)[r1] == SCIP_BOUNDTYPE_LOWER ?
1498
1499 /* if the global bound is equal to the implied bound, there is nothing to do */
1500 if( SCIPisZero(scip, coefs1[0]) )
1501 continue;
1502
1503 SCIPdebugMsg(scip, "Implication %s == %u => %s %s %g\n", SCIPvarGetName(vars_xwy[0]), xfixing,
1504 SCIPvarGetName(vars_xwy[1]), sidetype1 == SCIP_SIDETYPE_LEFT ? ">=" : "<=",
1505 SCIPvarGetImplBounds(vars_xwy[0], xfixing)[r1]);
1506 SCIPdebugMsg(scip, "Written as big-M: %g%s + %s %s %g\n", coefs1[0], SCIPvarGetName(vars_xwy[0]),
1507 SCIPvarGetName(vars_xwy[1]), sidetype1 == SCIP_SIDETYPE_LEFT ? ">=" : "<=", side1);
1508
1509 /* the second relation is in w and y (y could be anything, but must be in relation with w) */
1510
1511 /* x does not participate in the second relation, so we immediately set its coefficient to 0.0 */
1512 coefs2[0] = 0.0;
1513
1514 SCIPdebugMsg(scip, "Implic of x = <%s> + implied lb on w = <%s>:\n", SCIPvarGetName(vars_xwy[0]), SCIPvarGetName(vars_xwy[1]));
1515
1516 /* use implied lower bounds on w: w >= b*y + d */
1517 for( r2 = 0; r2 < SCIPvarGetNVlbs(vars_xwy[1]); ++r2 )
1518 {
1519 vars_xwy[2] = SCIPvarGetVlbVars(vars_xwy[1])[r2];
1520 if( vars_xwy[2] == vars_xwy[0] )
1521 continue;
1522
1523 coefs2[1] = 1.0;
1524 coefs2[2] = -SCIPvarGetVlbCoefs(vars_xwy[1])[r2];
1525
1526 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1527 SCIPvarGetVlbConstants(vars_xwy[1])[r2], sidetype1, SCIP_SIDETYPE_LEFT, varmap, xfixing) );
1528 }
1529
1530 SCIPdebugMsg(scip, "Implic of x = <%s> + implied ub on w = <%s>:\n", SCIPvarGetName(vars_xwy[0]), SCIPvarGetName(vars_xwy[1]));
1531
1532 /* use implied upper bounds on w: w <= b*y + d */
1533 for( r2 = 0; r2 < SCIPvarGetNVubs(vars_xwy[1]); ++r2 )
1534 {
1535 vars_xwy[2] = SCIPvarGetVubVars(vars_xwy[1])[r2];
1536 if( vars_xwy[2] == vars_xwy[0] )
1537 continue;
1538
1539 coefs2[1] = 1.0;
1540 coefs2[2] = -SCIPvarGetVubCoefs(vars_xwy[1])[r2];
1541
1542 SCIP_CALL( extractProducts(scip, sepadata, vars_xwy, coefs1, coefs2, side1,
1543 SCIPvarGetVubConstants(vars_xwy[1])[r2], sidetype1, SCIP_SIDETYPE_RIGHT, varmap, xfixing) );
1544 }
1545
1546 /* use unconditional relations containing w */
1547 relatedvars = getAdjacentVars(vars_in_2rels, vars_xwy[1], &nrelatedvars);
1548 if( relatedvars == NULL )
1549 continue;
1550
1551 for( r2 = 0; r2 < nrelatedvars; ++r2 )
1552 {
1553 vars_xwy[2] = relatedvars[r2];
1554 SCIPdebugMsg(scip, "Implied bound + unconditional with w and y:\n");
1555 SCIP_CALL( detectProductsUnconditional(scip, sepadata, prob_rows, row_list, hashtable2, coefs1,
1556 vars_xwy, side1, sidetype1, 1, 2, varmap, xfixing) );
1557 }
1558 }
1559 }
1560 }
1561
1562 /* free memory */
1563 clearVarAdjacency(scip, vars_in_2rels);
1564 SCIPhashmapFree(&vars_in_2rels);
1565
1566 SCIPdebugMsg(scip, "Unconditional relations table:\n");
1567 for( i = 0; i < SCIPhashtableGetNEntries(hashtable2); ++i )
1568 {
1569 foundhashdata = (HASHDATA*)SCIPhashtableGetEntry(hashtable2, i);
1570 if( foundhashdata == NULL )
1571 continue;
1572
1573 SCIPdebugMsg(scip, "(%s, %s): ", SCIPvarGetName(foundhashdata->vars[0]),
1574 SCIPvarGetName(foundhashdata->vars[1]));
1575
1576 SCIPfreeBuffer(scip, &foundhashdata);
1577 }
1578
1579 SCIPfreeBufferArray(scip, &row_list);
1580
1581 SCIPhashtableFree(&hashtable2);
1582 SCIPhashtableFree(&hashtable3);
1583
1584 SCIPfreeBufferArray(scip, &prob_rows);
1585
1586 return SCIP_OKAY;
1587}
1588
1589/** helper method to create separation data */
1590static
1592 SCIP* scip, /**< SCIP data structure */
1593 SCIP_SEPADATA* sepadata /**< separation data */
1594 )
1595{
1596 SCIP_HASHMAP* varmap;
1597 int i;
1598 SCIP_CONSNONLINEAR_BILINTERM* bilinterms;
1599 int varmapsize;
1600 int nvars;
1601
1602 assert(sepadata != NULL);
1603
1604 /* initialize some fields of sepadata */
1605 sepadata->varssorted = NULL;
1606 sepadata->varpriorities = NULL;
1607 sepadata->bilinvardatamap = NULL;
1608 sepadata->eqauxexpr = NULL;
1609 sepadata->nbilinvars = 0;
1610 sepadata->sbilinvars = 0;
1611
1612 /* get total number of bilinear terms */
1613 sepadata->nbilinterms = SCIPgetNBilinTermsNonlinear(sepadata->conshdlr);
1614
1615 /* skip if there are no bilinear terms and implicit product detection is off */
1616 if( sepadata->nbilinterms == 0 && !sepadata->detecthidden )
1617 return SCIP_OKAY;
1618
1619 /* the number of variables participating in bilinear products cannot exceed twice the number of bilinear terms;
1620 * however, if we detect hidden products, the number of terms is yet unknown, so use the number of variables
1621 */
1623 varmapsize = sepadata->detecthidden ? nvars : MIN(nvars, sepadata->nbilinterms * 2);
1624
1625 /* create variable map */
1626 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), varmapsize) );
1627
1628 /* get all bilinear terms from the nonlinear constraint handler */
1629 bilinterms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
1630
1631 /* store the information of all variables that appear bilinearly */
1632 for( i = 0; i < sepadata->nbilinterms; ++i )
1633 {
1634 assert(bilinterms[i].x != NULL);
1635 assert(bilinterms[i].y != NULL);
1636 assert(bilinterms[i].nlockspos + bilinterms[i].nlocksneg > 0);
1637
1638 /* skip bilinear term if it does not have an auxiliary variable */
1639 if( bilinterms[i].aux.var == NULL )
1640 continue;
1641
1642 /* if only original variables should be used, skip products that contain at least one auxiliary variable */
1643 if( sepadata->onlyoriginal && (SCIPvarIsRelaxationOnly(bilinterms[i].x) ||
1644 SCIPvarIsRelaxationOnly(bilinterms[i].y)) )
1645 continue;
1646
1647 /* coverity[var_deref_model] */
1648 SCIP_CALL( addProductVars(scip, sepadata, bilinterms[i].x, bilinterms[i].y, varmap,
1649 bilinterms[i].nlockspos + bilinterms[i].nlocksneg) );
1650 }
1651
1652 if( sepadata->detecthidden )
1653 {
1654 int oldnterms = sepadata->nbilinterms;
1655
1656 /* coverity[var_deref_model] */
1658
1659 /* update nbilinterms and bilinterms, as detectHiddenProducts might have found new terms */
1660 sepadata->nbilinterms = SCIPgetNBilinTermsNonlinear(sepadata->conshdlr);
1661 bilinterms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
1662
1663 if( sepadata->nbilinterms > oldnterms )
1664 {
1665 SCIPstatisticMessage(" Number of hidden products: %d\n", sepadata->nbilinterms - oldnterms);
1666 }
1667 }
1668
1669 SCIPhashmapFree(&varmap);
1670
1671 if( sepadata->nbilinterms == 0 )
1672 {
1673 return SCIP_OKAY;
1674 }
1675
1676 /* mark positions of aux.exprs that must be equal to the product */
1677 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &sepadata->eqauxexpr, sepadata->nbilinterms) );
1678
1679 for( i = 0; i < sepadata->nbilinterms; ++i )
1680 {
1681 int j;
1682
1683 sepadata->eqauxexpr[i] = -1;
1684 for( j = 0; j < bilinterms[i].nauxexprs; ++j )
1685 {
1686 assert(bilinterms[i].aux.exprs[j] != NULL);
1687
1688 if( bilinterms[i].aux.exprs[j]->underestimate && bilinterms[i].aux.exprs[j]->overestimate )
1689 {
1690 sepadata->eqauxexpr[i] = j;
1691 break;
1692 }
1693 }
1694 }
1695
1696 /* find maxnumber of variables that occur most often and sort them by number of occurrences
1697 * (same as normal sort, except that entries at positions maxusedvars..nbilinvars may be unsorted at end)
1698 */
1699 SCIPselectDownIntPtr(sepadata->varpriorities, (void**) sepadata->varssorted, MIN(sepadata->maxusedvars,sepadata->nbilinvars-1),
1700 sepadata->nbilinvars);
1701
1702 /* capture all variables */
1703 for( i = 0; i < sepadata->nbilinvars; ++i )
1704 {
1705 assert(sepadata->varssorted[i] != NULL);
1706 SCIP_CALL( SCIPcaptureVar(scip, sepadata->varssorted[i]) );
1707 }
1708
1709 /* mark that separation data has been created */
1710 sepadata->iscreated = TRUE;
1711 sepadata->isinitialround = TRUE;
1712
1713 if( SCIPgetNBilinTermsNonlinear(sepadata->conshdlr) > 0 )
1714 SCIPstatisticMessage(" Found bilinear terms\n");
1715 else
1716 SCIPstatisticMessage(" No bilinear terms\n");
1717
1718 return SCIP_OKAY;
1719}
1720
1721/** get the positions of the most violated auxiliary under- and overestimators for each product
1722 *
1723 * -1 means no relation with given product is violated
1724 */
1725static
1727 SCIP* scip, /**< SCIP data structure */
1728 SCIP_SEPADATA* sepadata, /**< separator data */
1729 SCIP_SOL* sol, /**< solution at which to evaluate the expressions */
1730 int* bestunderestimators,/**< array of indices of best underestimators for each term */
1731 int* bestoverestimators /**< array of indices of best overestimators for each term */
1732 )
1733{
1734 SCIP_Real prodval;
1735 SCIP_Real auxval;
1736 SCIP_Real prodviol;
1737 SCIP_Real viol_below;
1738 SCIP_Real viol_above;
1739 int i;
1740 int j;
1742
1743 assert(bestunderestimators != NULL);
1744 assert(bestoverestimators != NULL);
1745
1746 terms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
1747
1748 for( j = 0; j < SCIPgetNBilinTermsNonlinear(sepadata->conshdlr); ++j )
1749 {
1750 viol_below = 0.0;
1751 viol_above = 0.0;
1752
1753 /* evaluate the product expression */
1754 prodval = SCIPgetSolVal(scip, sol, terms[j].x) * SCIPgetSolVal(scip, sol, terms[j].y);
1755
1756 bestunderestimators[j] = -1;
1757 bestoverestimators[j] = -1;
1758
1759 /* if there are any auxexprs, look there */
1760 for( i = 0; i < terms[j].nauxexprs; ++i )
1761 {
1762 auxval = SCIPevalBilinAuxExprNonlinear(scip, terms[j].x, terms[j].y, terms[j].aux.exprs[i], sol);
1763 prodviol = auxval - prodval;
1764
1765 if( terms[j].aux.exprs[i]->underestimate && SCIPisFeasGT(scip, auxval, prodval) && prodviol > viol_below )
1766 {
1767 viol_below = prodviol;
1768 bestunderestimators[j] = i;
1769 }
1770 if( terms[j].aux.exprs[i]->overestimate && SCIPisFeasGT(scip, prodval, auxval) && -prodviol > viol_above )
1771 {
1772 viol_above = -prodviol;
1773 bestoverestimators[j] = i;
1774 }
1775 }
1776
1777 /* if the term has a plain auxvar, it will be treated differently - do nothing here */
1778 }
1779}
1780
1781/** tests if a row contains too many unknown bilinear terms w.r.t. the parameters */
1782static
1784 SCIP_SEPADATA* sepadata, /**< separation data */
1785 SCIP_ROW* row, /**< the row to be tested */
1786 SCIP_VAR* var, /**< the variable that is to be multiplied with row */
1787 int* currentnunknown, /**< buffer to store number of unknown terms in current row if acceptable */
1788 SCIP_Bool* acceptable /**< buffer to store the result */
1789 )
1790{
1791 int i;
1792 int idx;
1794
1795 assert(row != NULL);
1796 assert(var != NULL);
1797
1798 *currentnunknown = 0;
1799 terms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
1800
1801 for( i = 0; (i < SCIProwGetNNonz(row)) && (sepadata->maxunknownterms < 0 || *currentnunknown <= sepadata->maxunknownterms); ++i )
1802 {
1804
1805 /* if the product hasn't been found, no auxiliary expressions for it are known */
1806 if( idx < 0 )
1807 {
1808 ++(*currentnunknown);
1809 continue;
1810 }
1811
1812 /* known terms are only those that have an aux.var or equality estimators */
1813 if( sepadata->eqauxexpr[idx] == -1 && !(terms[idx].nauxexprs == 0 && terms[idx].aux.var != NULL) )
1814 {
1815 ++(*currentnunknown);
1816 }
1817 }
1818
1819 *acceptable = sepadata->maxunknownterms < 0 || *currentnunknown <= sepadata->maxunknownterms;
1820
1821 return SCIP_OKAY;
1822}
1823
1824/** adds coefficients and constant of an auxiliary expression
1825 *
1826 * the variables the pointers are pointing to must already be initialized
1827 */
1828static
1830 SCIP_VAR* var1, /**< first product variable */
1831 SCIP_VAR* var2, /**< second product variable */
1832 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to be added */
1833 SCIP_Real coef, /**< coefficient of the auxiliary expression */
1834 SCIP_Real* coefaux, /**< pointer to add the coefficient of the auxiliary variable */
1835 SCIP_Real* coef1, /**< pointer to add the coefficient of the first variable */
1836 SCIP_Real* coef2, /**< pointer to add the coefficient of the second variable */
1837 SCIP_Real* cst /**< pointer to add the constant */
1838 )
1839{
1840 assert(auxexpr != NULL);
1841 assert(auxexpr->auxvar != NULL);
1842 assert(coefaux != NULL);
1843 assert(coef1 != NULL);
1844 assert(coef2 != NULL);
1845 assert(cst != NULL);
1846
1847 *coefaux += auxexpr->coefs[0] * coef;
1848
1849 /* in auxexpr, x goes before y and has the smaller index,
1850 * so compare vars to figure out which one is x and which is y
1851 */
1852 if( SCIPvarCompare(var1, var2) < 1 )
1853 {
1854 *coef1 += auxexpr->coefs[1] * coef;
1855 *coef2 += auxexpr->coefs[2] * coef;
1856 }
1857 else
1858 {
1859 *coef1 += auxexpr->coefs[2] * coef;
1860 *coef2 += auxexpr->coefs[1] * coef;
1861 }
1862 *cst += coef * auxexpr->cst;
1863}
1864
1865/** add a linear term `coef`*`colvar` multiplied by a bound factor (var - lb(var)) or (ub(var) - var)
1866 *
1867 * adds the linear term with `colvar` to `cut` and updates `coefvar` and `cst`
1868 */
1869static
1871 SCIP* scip, /**< SCIP data structure */
1872 SCIP_SEPADATA* sepadata, /**< separator data */
1873 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
1874 int* bestunderest, /**< positions of most violated underestimators for each product term */
1875 int* bestoverest, /**< positions of most violated overestimators for each product term */
1876 SCIP_ROW* cut, /**< cut to which the term is to be added */
1877 SCIP_VAR* var, /**< multiplier variable */
1878 SCIP_VAR* colvar, /**< row variable to be multiplied */
1879 SCIP_Real coef, /**< coefficient of the bilinear term */
1880 SCIP_Bool uselb, /**< whether we multiply with (var - lb) or (ub - var) */
1881 SCIP_Bool uselhs, /**< whether to create a cut for the lhs or rhs */
1882 SCIP_Bool local, /**< whether local or global cuts should be computed */
1883 SCIP_Bool computeEqCut, /**< whether conditions are fulfilled to compute equality cuts */
1884 SCIP_Real* coefvar, /**< coefficient of var */
1885 SCIP_Real* cst, /**< buffer to store the constant part of the cut */
1886 SCIP_Bool* success /**< buffer to store whether cut was updated successfully */
1887 )
1888{
1889 SCIP_Real lbvar;
1890 SCIP_Real ubvar;
1891 SCIP_Real refpointvar;
1892 SCIP_Real signfactor;
1893 SCIP_Real boundfactor;
1894 SCIP_Real coefauxvar;
1895 SCIP_Real coefcolvar;
1896 SCIP_Real coefterm;
1897 int auxpos;
1898 int idx;
1900 SCIP_VAR* auxvar;
1901
1902 terms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
1903
1904 if( computeEqCut )
1905 {
1906 lbvar = 0.0;
1907 ubvar = 0.0;
1908 }
1909 else
1910 {
1911 lbvar = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
1912 ubvar = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
1913 }
1914
1915 refpointvar = MAX(lbvar, MIN(ubvar, SCIPgetSolVal(scip, sol, var))); /*lint !e666*/
1916
1917 signfactor = (uselb ? 1.0 : -1.0);
1918 boundfactor = (uselb ? -lbvar : ubvar);
1919
1920 coefterm = coef * signfactor; /* coefficient of the bilinear term */
1921 coefcolvar = coef * boundfactor; /* coefficient of the linear term */
1922 coefauxvar = 0.0; /* coefficient of the auxiliary variable corresponding to the bilinear term */
1923 auxvar = NULL;
1924
1925 assert(!SCIPisInfinity(scip, REALABS(coefterm)));
1926
1927 /* first, add the linearisation of the bilinear term */
1928
1929 idx = SCIPgetBilinTermIdxNonlinear(sepadata->conshdlr, var, colvar);
1930 auxpos = -1;
1931
1932 /* for an implicit term, get the position of the best estimator */
1933 if( idx >= 0 && terms[idx].nauxexprs > 0 )
1934 {
1935 if( computeEqCut )
1936 {
1937 /* use an equality auxiliary expression (which should exist for computeEqCut to be TRUE) */
1938 assert(sepadata->eqauxexpr[idx] >= 0);
1939 auxpos = sepadata->eqauxexpr[idx];
1940 }
1941 else if( (uselhs && coefterm > 0.0) || (!uselhs && coefterm < 0.0) )
1942 {
1943 /* use an overestimator */
1944 auxpos = bestoverest[idx];
1945 }
1946 else
1947 {
1948 /* use an underestimator */
1949 auxpos = bestunderest[idx];
1950 }
1951 }
1952
1953 /* if the term is implicit and a suitable auxiliary expression for var*colvar exists, add the coefficients
1954 * of the auxiliary expression for coefterm*var*colvar to coefauxvar, coefcolvar, coefvar and cst
1955 */
1956 if( auxpos >= 0 )
1957 {
1958 SCIPdebugMsg(scip, "auxiliary expression for <%s> and <%s> found, will be added to cut:\n",
1960 addAuxexprCoefs(var, colvar, terms[idx].aux.exprs[auxpos], coefterm, &coefauxvar, coefvar, &coefcolvar, cst);
1961 auxvar = terms[idx].aux.exprs[auxpos]->auxvar;
1962 }
1963 /* for an existing term, use the auxvar if there is one */
1964 else if( idx >= 0 && terms[idx].nauxexprs == 0 && terms[idx].aux.var != NULL )
1965 {
1966 SCIPdebugMsg(scip, "auxvar for <%s> and <%s> found, will be added to cut:\n",
1968 coefauxvar += coefterm;
1969 auxvar = terms[idx].aux.var;
1970 }
1971
1972 /* otherwise, use clique information or the McCormick estimator in place of the bilinear term */
1973 else if( colvar != var )
1974 {
1975 SCIP_Bool found_clique = FALSE;
1976 SCIP_Real lbcolvar = local ? SCIPvarGetLbLocal(colvar) : SCIPvarGetLbGlobal(colvar);
1977 SCIP_Real ubcolvar = local ? SCIPvarGetUbLocal(colvar) : SCIPvarGetUbGlobal(colvar);
1978 SCIP_Real refpointcolvar = MAX(lbcolvar, MIN(ubcolvar, SCIPgetSolVal(scip, sol, colvar))); /*lint !e666*/
1979
1980 assert(!computeEqCut);
1981
1982 if( REALABS(lbcolvar) > MAXVARBOUND || REALABS(ubcolvar) > MAXVARBOUND )
1983 {
1984 *success = FALSE;
1985 return SCIP_OKAY;
1986 }
1987
1988 SCIPdebugMsg(scip, "auxvar for <%s> and <%s> not found, will linearize the product\n", SCIPvarGetName(colvar), SCIPvarGetName(var));
1989
1990 /* if both variables are binary, check if they are contained together in some clique */
1992 {
1993 int c;
1994 SCIP_CLIQUE** varcliques;
1995
1996 varcliques = SCIPvarGetCliques(var, TRUE);
1997
1998 /* look through cliques containing var */
1999 for( c = 0; c < SCIPvarGetNCliques(var, TRUE); ++c )
2000 {
2001 if( SCIPcliqueHasVar(varcliques[c], colvar, TRUE) ) /* var + colvar <= 1 => var*colvar = 0 */
2002 {
2003 /* product is zero, add nothing */
2004 found_clique = TRUE;
2005 break;
2006 }
2007
2008 if( SCIPcliqueHasVar(varcliques[c], colvar, FALSE) ) /* var + (1-colvar) <= 1 => var*colvar = var */
2009 {
2010 *coefvar += coefterm;
2011 found_clique = TRUE;
2012 break;
2013 }
2014 }
2015
2016 if( !found_clique )
2017 {
2018 varcliques = SCIPvarGetCliques(var, FALSE);
2019
2020 /* look through cliques containing complement of var */
2021 for( c = 0; c < SCIPvarGetNCliques(var, FALSE); ++c )
2022 {
2023 if( SCIPcliqueHasVar(varcliques[c], colvar, TRUE) ) /* (1-var) + colvar <= 1 => var*colvar = colvar */
2024 {
2025 coefcolvar += coefterm;
2026 found_clique = TRUE;
2027 break;
2028 }
2029
2030 if( SCIPcliqueHasVar(varcliques[c], colvar, FALSE) ) /* (1-var) + (1-colvar) <= 1 => var*colvar = var + colvar - 1 */
2031 {
2032 *coefvar += coefterm;
2033 coefcolvar += coefterm;
2034 *cst -= coefterm;
2035 found_clique = TRUE;
2036 break;
2037 }
2038 }
2039 }
2040 }
2041
2042 if( !found_clique )
2043 {
2044 SCIPdebugMsg(scip, "clique for <%s> and <%s> not found or at least one of them is not binary, will use McCormick\n", SCIPvarGetName(colvar), SCIPvarGetName(var));
2045 SCIPaddBilinMcCormick(scip, coefterm, lbvar, ubvar, refpointvar, lbcolvar,
2046 ubcolvar, refpointcolvar, uselhs, coefvar, &coefcolvar, cst, success);
2047 if( !*success )
2048 return SCIP_OKAY;
2049 }
2050 }
2051
2052 /* or, if it's a quadratic term, use a secant for overestimation and a gradient for underestimation */
2053 else
2054 {
2055 SCIPdebugMsg(scip, "auxvar for <%s>^2 not found, will use gradient and secant estimators\n", SCIPvarGetName(colvar));
2056
2057 assert(!computeEqCut);
2058
2059 /* for a binary var, var^2 = var */
2061 {
2062 *coefvar += coefterm;
2063 }
2064 else
2065 {
2066 /* depending on over-/underestimation and the sign of the column variable, compute secant or tangent */
2067 if( (uselhs && coefterm > 0.0) || (!uselhs && coefterm < 0.0) )
2068 SCIPaddSquareSecant(scip, coefterm, lbvar, ubvar, coefvar, cst, success);
2069 else
2070 SCIPaddSquareLinearization(scip, coefterm, refpointvar, SCIPvarIsIntegral(var), coefvar, cst, success);
2071
2072 if( !*success )
2073 return SCIP_OKAY;
2074 }
2075 }
2076
2077 /* add the auxiliary variable if its coefficient is nonzero */
2078 if( !SCIPisZero(scip, coefauxvar) )
2079 {
2080 assert(auxvar != NULL);
2081 /* coverity[var_deref_model] */
2082 SCIP_CALL( SCIPaddVarToRow(scip, cut, auxvar, coefauxvar) );
2083 }
2084
2085 /* we are done with the product linearisation, now add the term which comes from multiplying
2086 * coef*colvar by the constant part of the bound factor
2087 */
2088
2089 if( colvar != var )
2090 {
2091 assert(!SCIPisInfinity(scip, REALABS(coefcolvar)));
2092 SCIP_CALL( SCIPaddVarToRow(scip, cut, colvar, coefcolvar) );
2093 }
2094 else
2095 *coefvar += coefcolvar;
2096
2097 return SCIP_OKAY;
2098}
2099
2100/** creates the RLT cut formed by multiplying a given row with (x - lb) or (ub - x)
2101 *
2102 * In detail:
2103 * - The row is multiplied either with (x - lb(x)) or with (ub(x) - x), depending on parameter `uselb`, or by x if
2104 * this is an equality cut
2105 * - The (inequality) cut is computed either for lhs or rhs, depending on parameter `uselhs`.
2106 * - Terms for which no auxiliary variable and no clique relation exists are replaced by either McCormick, secants,
2107 * or gradient linearization cuts.
2108 */
2109static
2111 SCIP* scip, /**< SCIP data structure */
2112 SCIP_SEPA* sepa, /**< separator */
2113 SCIP_SEPADATA* sepadata, /**< separation data */
2114 SCIP_ROW** cut, /**< buffer to store the cut */
2115 SCIP_ROW* row, /**< the row that is used for the rlt cut (NULL if using projected row) */
2116 RLT_SIMPLEROW* projrow, /**< projected row that is used for the rlt cut (NULL if using row) */
2117 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
2118 int* bestunderest, /**< positions of most violated underestimators for each product term */
2119 int* bestoverest, /**< positions of most violated overestimators for each product term */
2120 SCIP_VAR* var, /**< the variable that is used for the rlt cuts */
2121 SCIP_Bool* success, /**< buffer to store whether cut was created successfully */
2122 SCIP_Bool uselb, /**< whether we multiply with (var - lb) or (ub - var) */
2123 SCIP_Bool uselhs, /**< whether to create a cut for the lhs or rhs */
2124 SCIP_Bool local, /**< whether local or global cuts should be computed */
2125 SCIP_Bool computeEqCut, /**< whether conditions are fulfilled to compute equality cuts */
2126 SCIP_Bool useprojrow /**< whether to use projected row instead of normal row */
2127 )
2128{ /*lint --e{413}*/
2129 SCIP_Real signfactor;
2130 SCIP_Real boundfactor;
2131 SCIP_Real lbvar;
2132 SCIP_Real ubvar;
2133 SCIP_Real coefvar;
2134 SCIP_Real consside;
2135 SCIP_Real finalside;
2136 SCIP_Real cstterm;
2137 SCIP_Real lhs;
2138 SCIP_Real rhs;
2139 SCIP_Real rowcst;
2140 int i;
2141 const char* rowname;
2142 char cutname[SCIP_MAXSTRLEN];
2143
2144 assert(sepadata != NULL);
2145 assert(cut != NULL);
2146 assert(useprojrow || row != NULL);
2147 assert(!useprojrow || projrow != NULL);
2148 assert(var != NULL);
2149 assert(success != NULL);
2150
2151 lhs = useprojrow ? projrow->lhs : SCIProwGetLhs(row);
2152 rhs = useprojrow ? projrow->rhs : SCIProwGetRhs(row);
2153 rowname = useprojrow ? projrow->name : SCIProwGetName(row);
2154 rowcst = useprojrow ? projrow ->cst : SCIProwGetConstant(row);
2155
2156 assert(!computeEqCut || SCIPisEQ(scip, lhs, rhs));
2157
2158 *cut = NULL;
2159
2160 /* get data for given variable */
2161 if( computeEqCut )
2162 {
2163 lbvar = 0.0;
2164 ubvar = 0.0;
2165 }
2166 else
2167 {
2168 lbvar = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
2169 ubvar = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
2170 }
2171
2172 /* get row side */
2173 consside = uselhs ? lhs : rhs;
2174
2175 /* if the bounds are too large or the respective side is infinity, skip this cut */
2176 if( (uselb && REALABS(lbvar) > MAXVARBOUND) || (!uselb && REALABS(ubvar) > MAXVARBOUND)
2177 || SCIPisInfinity(scip, REALABS(consside)) )
2178 {
2179 SCIPdebugMsg(scip, "cut generation for %srow <%s>, %s, and variable <%s> with its %s %g not possible\n",
2180 useprojrow ? "projected " : "", rowname, uselhs ? "lhs" : "rhs", SCIPvarGetName(var),
2181 uselb ? "lower bound" : "upper bound", uselb ? lbvar : ubvar);
2182
2183 if( REALABS(lbvar) > MAXVARBOUND )
2184 SCIPdebugMsg(scip, " because of lower bound\n");
2185 if( REALABS(ubvar) > MAXVARBOUND )
2186 SCIPdebugMsg(scip, " because of upper bound\n");
2187 if( SCIPisInfinity(scip, REALABS(consside)) )
2188 SCIPdebugMsg(scip, " because of side %g\n", consside);
2189
2190 *success = FALSE;
2191 return SCIP_OKAY;
2192 }
2193
2194 /* initialize some factors needed for computation */
2195 coefvar = 0.0;
2196 cstterm = 0.0;
2197 signfactor = (uselb ? 1.0 : -1.0);
2198 boundfactor = (uselb ? -lbvar : ubvar);
2199 *success = TRUE;
2200
2201 /* create an empty row which we then fill with variables step by step */
2202 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "rlt_%scut_%s_%s_%s_%s_%" SCIP_LONGINT_FORMAT, useprojrow ? "proj" : "", rowname,
2203 uselhs ? "lhs" : "rhs", SCIPvarGetName(var), uselb ? "lb" : "ub", SCIPgetNLPs(scip));
2205 SCIPgetDepth(scip) > 0 && local, FALSE, FALSE) ); /* TODO SCIPgetDepth() should be replaced by depth that is passed on to the SEPAEXEC calls (?) */
2206
2208
2209 /* iterate over all variables in the row and add the corresponding terms coef*colvar*(bound factor) to the cuts */
2210 for( i = 0; i < (useprojrow ? projrow->nnonz : SCIProwGetNNonz(row)); ++i )
2211 {
2212 SCIP_VAR* colvar;
2213
2214 colvar = useprojrow ? projrow->vars[i] : SCIPcolGetVar(SCIProwGetCols(row)[i]);
2215 SCIP_CALL( addRltTerm(scip, sepadata, sol, bestunderest, bestoverest, *cut, var, colvar,
2216 useprojrow ? projrow->coefs[i] : SCIProwGetVals(row)[i], uselb, uselhs, local, computeEqCut,
2217 &coefvar, &cstterm, success) );
2218 }
2219
2220 if( REALABS(cstterm) > MAXVARBOUND )
2221 {
2222 *success = FALSE;
2223 return SCIP_OKAY;
2224 }
2225
2226 /* multiply (x-lb) or (ub -x) with the lhs and rhs of the row */
2227 coefvar += signfactor * (rowcst - consside);
2228 finalside = boundfactor * (consside - rowcst) - cstterm;
2229
2230 assert(!SCIPisInfinity(scip, REALABS(coefvar)));
2231 assert(!SCIPisInfinity(scip, REALABS(finalside)));
2232
2233 /* set the coefficient of var and update the side */
2234 SCIP_CALL( SCIPaddVarToRow(scip, *cut, var, coefvar) );
2236 if( uselhs || computeEqCut )
2237 {
2238 SCIP_CALL( SCIPchgRowLhs(scip, *cut, finalside) );
2239 }
2240 if( !uselhs || computeEqCut )
2241 {
2242 SCIP_CALL( SCIPchgRowRhs(scip, *cut, finalside) );
2243 }
2244
2245 SCIPdebugMsg(scip, "%scut was generated successfully:\n", useprojrow ? "projected " : "");
2246#ifdef SCIP_DEBUG
2247 SCIP_CALL( SCIPprintRow(scip, *cut, NULL) );
2248#endif
2249
2250 return SCIP_OKAY;
2251}
2252
2253/** store a row projected by fixing all variables that are at bound at sol; the result is a simplified row */
2254static
2256 SCIP* scip, /**< SCIP data structure */
2257 RLT_SIMPLEROW* simplerow, /**< pointer to the simplified row */
2258 SCIP_ROW* row, /**< row to be projected */
2259 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
2260 SCIP_Bool local /**< whether local bounds should be checked */
2261 )
2262{
2263 int i;
2264 SCIP_VAR* var;
2265 SCIP_Real val;
2266 SCIP_Real vlb;
2267 SCIP_Real vub;
2268
2269 assert(simplerow != NULL);
2270
2272 strlen(SCIProwGetName(row))+1) ); /*lint !e666*/
2273 simplerow->nnonz = 0;
2274 simplerow->size = 0;
2275 simplerow->vars = NULL;
2276 simplerow->coefs = NULL;
2277 simplerow->lhs = SCIProwGetLhs(row);
2278 simplerow->rhs = SCIProwGetRhs(row);
2279 simplerow->cst = SCIProwGetConstant(row);
2280
2281 for( i = 0; i < SCIProwGetNNonz(row); ++i )
2282 {
2284 val = SCIPgetSolVal(scip, sol, var);
2285 vlb = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
2286 vub = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
2287 if( SCIPisFeasEQ(scip, vlb, val) || SCIPisFeasEQ(scip, vub, val) )
2288 {
2289 /* if we are projecting and the var is at bound, add var as a constant to simplerow */
2290 if( !SCIPisInfinity(scip, -simplerow->lhs) )
2291 simplerow->lhs -= SCIProwGetVals(row)[i]*val;
2292 if( !SCIPisInfinity(scip, simplerow->rhs) )
2293 simplerow->rhs -= SCIProwGetVals(row)[i]*val;
2294 }
2295 else
2296 {
2297 if( simplerow->nnonz + 1 > simplerow->size )
2298 {
2299 int newsize;
2300
2301 newsize = SCIPcalcMemGrowSize(scip, simplerow->nnonz + 1);
2302 SCIP_CALL( SCIPreallocBufferArray(scip, &simplerow->coefs, newsize) );
2303 SCIP_CALL( SCIPreallocBufferArray(scip, &simplerow->vars, newsize) );
2304 simplerow->size = newsize;
2305 }
2306
2307 /* add the term to simplerow */
2308 simplerow->vars[simplerow->nnonz] = var;
2309 simplerow->coefs[simplerow->nnonz] = SCIProwGetVals(row)[i];
2310 ++(simplerow->nnonz);
2311 }
2312 }
2313
2314 return SCIP_OKAY;
2315}
2316
2317/** free the projected row */
2318static
2320 SCIP* scip, /**< SCIP data structure */
2321 RLT_SIMPLEROW* simplerow /**< simplified row to be freed */
2322 )
2323{
2324 assert(simplerow != NULL);
2325
2326 if( simplerow->size > 0 )
2327 {
2328 assert(simplerow->vars != NULL);
2329 assert(simplerow->coefs != NULL);
2330
2331 SCIPfreeBufferArray(scip, &simplerow->vars);
2332 SCIPfreeBufferArray(scip, &simplerow->coefs);
2333 }
2334 SCIPfreeBlockMemoryArray(scip, &simplerow->name, strlen(simplerow->name)+1);
2335}
2336
2337/** creates the projected problem
2338 *
2339 * All variables that are at their bounds at the current solution are added
2340 * to left and/or right hand sides as constant values.
2341 */
2342static
2344 SCIP* scip, /**< SCIP data structure */
2345 SCIP_ROW** rows, /**< problem rows */
2346 int nrows, /**< number of rows */
2347 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
2348 RLT_SIMPLEROW** projrows, /**< the projected rows to be filled */
2349 SCIP_Bool local, /**< are local cuts allowed? */
2350 SCIP_Bool* allcst /**< buffer to store whether all projected rows have only constants */
2351 )
2352{
2353 int i;
2354
2355 assert(scip != NULL);
2356 assert(rows != NULL);
2357 assert(projrows != NULL);
2358 assert(allcst != NULL);
2359
2360 *allcst = TRUE;
2361 SCIP_CALL( SCIPallocBufferArray(scip, projrows, nrows) );
2362
2363 for( i = 0; i < nrows; ++i )
2364 {
2365 /* get a simplified and projected row */
2366 SCIP_CALL( createProjRow(scip, &(*projrows)[i], rows[i], sol, local) );
2367 if( (*projrows)[i].nnonz > 0 )
2368 *allcst = FALSE;
2369 }
2370
2371 return SCIP_OKAY;
2372}
2373
2374#ifdef SCIP_DEBUG
2375/* prints the projected LP */
2376static
2377void printProjRows(
2378 SCIP* scip, /**< SCIP data structure */
2379 RLT_SIMPLEROW* projrows, /**< the projected rows */
2380 int nrows, /**< number of projected rows */
2381 FILE* file /**< output file (or NULL for standard output) */
2382 )
2383{
2384 int i;
2385 int j;
2386
2387 assert(projrows != NULL);
2388
2389 for( i = 0; i < nrows; ++i )
2390 {
2391 SCIPinfoMessage(scip, file, "\nproj_row[%d]: ", i);
2392 if( !SCIPisInfinity(scip, -projrows[i].lhs) )
2393 SCIPinfoMessage(scip, file, "%.15g <= ", projrows[i].lhs);
2394 for( j = 0; j < projrows[i].nnonz; ++j )
2395 {
2396 if( j == 0 )
2397 {
2398 if( projrows[i].coefs[j] < 0 )
2399 SCIPinfoMessage(scip, file, "-");
2400 }
2401 else
2402 {
2403 if( projrows[i].coefs[j] < 0 )
2404 SCIPinfoMessage(scip, file, " - ");
2405 else
2406 SCIPinfoMessage(scip, file, " + ");
2407 }
2408
2409 if( projrows[i].coefs[j] != 1.0 )
2410 SCIPinfoMessage(scip, file, "%.15g*", REALABS(projrows[i].coefs[j]));
2411 SCIPinfoMessage(scip, file, "<%s>", SCIPvarGetName(projrows[i].vars[j]));
2412 }
2413 if( projrows[i].cst > 0 )
2414 SCIPinfoMessage(scip, file, " + %.15g", projrows[i].cst);
2415 else if( projrows[i].cst < 0 )
2416 SCIPinfoMessage(scip, file, " - %.15g", REALABS(projrows[i].cst));
2417
2418 if( !SCIPisInfinity(scip, projrows[i].rhs) )
2419 SCIPinfoMessage(scip, file, " <= %.15g", projrows[i].rhs);
2420 }
2421 SCIPinfoMessage(scip, file, "\n");
2422}
2423#endif
2424
2425/** frees the projected rows */
2426static
2428 SCIP* scip, /**< SCIP data structure */
2429 RLT_SIMPLEROW** projrows, /**< the projected LP */
2430 int nrows /**< number of rows in projrows */
2431 )
2432{
2433 int i;
2434
2435 for( i = 0; i < nrows; ++i )
2436 freeProjRow(scip, &(*projrows)[i]);
2437
2438 SCIPfreeBufferArray(scip, projrows);
2439}
2440
2441/** mark a row for rlt cut selection
2442 *
2443 * depending on the sign of the coefficient and violation, set or update mark which cut is required:
2444 * - 1 - cuts for axy < aw case,
2445 * - 2 - cuts for axy > aw case,
2446 * - 3 - cuts for both cases
2447 */
2448static
2450 int ridx, /**< row index */
2451 SCIP_Real a, /**< coefficient of x in the row */
2452 SCIP_Bool violatedbelow, /**< whether the relation auxexpr <= xy is violated */
2453 SCIP_Bool violatedabove, /**< whether the relation xy <= auxexpr is violated */
2454 int* row_idcs, /**< sparse array with indices of marked rows */
2455 unsigned int* row_marks, /**< sparse array to store the marks */
2456 int* nmarked /**< number of marked rows */
2457 )
2458{
2459 unsigned int newmark;
2460 int pos;
2461 SCIP_Bool exists;
2462
2463 assert(a != 0.0);
2464
2465 if( (a > 0.0 && violatedbelow) || (a < 0.0 && violatedabove) )
2466 newmark = 1; /* axy < aw case */
2467 else
2468 newmark = 2; /* axy > aw case */
2469
2470 /* find row idx in row_idcs */
2471 exists = SCIPsortedvecFindInt(row_idcs, ridx, *nmarked, &pos);
2472
2473 if( exists )
2474 {
2475 /* we found the row index: update the mark at pos */
2476 row_marks[pos] |= newmark;
2477 }
2478 else /* the given row index does not yet exist in row_idcs */
2479 {
2480 int i;
2481
2482 /* insert row index at the correct position */
2483 for( i = *nmarked; i > pos; --i )
2484 {
2485 row_idcs[i] = row_idcs[i-1];
2486 row_marks[i] = row_marks[i-1];
2487 }
2488 row_idcs[pos] = ridx;
2489 row_marks[pos] = newmark;
2490 (*nmarked)++;
2491 }
2492}
2493
2494/** mark all rows that should be multiplied by xj */
2495static
2497 SCIP* scip, /**< SCIP data structure */
2498 SCIP_SEPADATA* sepadata, /**< separator data */
2499 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
2500 SCIP_SOL* sol, /**< point to be separated (can be NULL) */
2501 int j, /**< index of the multiplier variable in sepadata */
2502 SCIP_Bool local, /**< are local cuts allowed? */
2503 SCIP_HASHMAP* row_to_pos, /**< hashmap linking row indices to positions in array */
2504 int* bestunderest, /**< positions of most violated underestimators for each product term */
2505 int* bestoverest, /**< positions of most violated overestimators for each product term */
2506 unsigned int* row_marks, /**< sparse array storing the row marks */
2507 int* row_idcs, /**< sparse array storing the marked row positions */
2508 int* nmarked /**< number of marked rows */
2509 )
2510{
2511 int i;
2512 int idx;
2513 int ncolrows;
2514 int r;
2515 int ridx;
2516 SCIP_VAR* xi;
2517 SCIP_VAR* xj;
2518 SCIP_Real vlb;
2519 SCIP_Real vub;
2520 SCIP_Real vali;
2521 SCIP_Real valj;
2522 SCIP_Real a;
2523 SCIP_COL* coli;
2524 SCIP_Real* colvals;
2525 SCIP_ROW** colrows;
2527 SCIP_Bool violatedbelow;
2528 SCIP_Bool violatedabove;
2529 SCIP_VAR** bilinadjvars;
2530 int nbilinadjvars;
2531
2532 *nmarked = 0;
2533
2534 xj = sepadata->varssorted[j];
2535 assert(xj != NULL);
2536
2537 valj = SCIPgetSolVal(scip, sol, xj);
2538 vlb = local ? SCIPvarGetLbLocal(xj) : SCIPvarGetLbGlobal(xj);
2539 vub = local ? SCIPvarGetUbLocal(xj) : SCIPvarGetUbGlobal(xj);
2540
2541 if( sepadata->useprojection && (SCIPisFeasEQ(scip, vlb, valj) || SCIPisFeasEQ(scip, vub, valj)) )
2542 {
2543 /* we don't want to multiply by variables that are at bound */
2544 SCIPdebugMsg(scip, "Rejected multiplier <%s> in [%g,%g] because it is at bound (current value %g)\n", SCIPvarGetName(xj), vlb, vub, valj);
2545 return SCIP_OKAY;
2546 }
2547
2548 terms = SCIPgetBilinTermsNonlinear(conshdlr);
2549 bilinadjvars = getAdjacentVars(sepadata->bilinvardatamap, xj, &nbilinadjvars);
2550 assert(bilinadjvars != NULL);
2551
2552 /* for each var which appears in a bilinear product together with xj, mark rows */
2553 for( i = 0; i < nbilinadjvars; ++i )
2554 {
2555 xi = bilinadjvars[i];
2556
2558 continue;
2559
2560 vali = SCIPgetSolVal(scip, sol, xi);
2561 vlb = local ? SCIPvarGetLbLocal(xi) : SCIPvarGetLbGlobal(xi);
2562 vub = local ? SCIPvarGetUbLocal(xi) : SCIPvarGetUbGlobal(xi);
2563
2564 /* if we use projection, we aren't interested in products with variables that are at bound */
2565 if( sepadata->useprojection && (SCIPisFeasEQ(scip, vlb, vali) || SCIPisFeasEQ(scip, vub, vali)) )
2566 continue;
2567
2568 /* get the index of the bilinear product */
2569 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, xj, xi);
2570 assert(idx >= 0 && idx < SCIPgetNBilinTermsNonlinear(conshdlr));
2571
2572 /* skip implicit products if we don't want to add RLT cuts for them */
2573 if( !sepadata->hiddenrlt && !terms[idx].existing )
2574 continue;
2575
2576 /* use the most violated under- and overestimators for this product;
2577 * if equality cuts are computed, we might end up using a different auxiliary expression;
2578 * so this is an optimistic (i.e. taking the largest possible violation) estimation
2579 */
2580 if( bestunderest == NULL || bestunderest[idx] == -1 )
2581 { /* no violated implicit underestimation relations -> either use auxvar or set violatedbelow to FALSE */
2582 if( terms[idx].nauxexprs == 0 && terms[idx].aux.var != NULL )
2583 {
2584 assert(terms[idx].existing);
2585 violatedbelow = SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, terms[idx].aux.var) - valj * vali);
2586 }
2587 else
2588 {
2589 assert(bestunderest != NULL);
2590 violatedbelow = FALSE;
2591 }
2592 }
2593 else
2594 {
2595 assert(bestunderest[idx] >= 0 && bestunderest[idx] < terms[idx].nauxexprs);
2596
2597 /* if we are here, the relation with the best underestimator must be violated */
2599 terms[idx].aux.exprs[bestunderest[idx]], sol) - valj * vali));
2600 violatedbelow = TRUE;
2601 }
2602
2603 if( bestoverest == NULL || bestoverest[idx] == -1 )
2604 { /* no violated implicit overestimation relations -> either use auxvar or set violatedabove to FALSE */
2605 if( terms[idx].nauxexprs == 0 && terms[idx].aux.var != NULL )
2606 {
2607 assert(terms[idx].existing);
2608 violatedabove = SCIPisFeasPositive(scip, valj * vali - SCIPgetSolVal(scip, sol, terms[idx].aux.var));
2609 }
2610 else
2611 {
2612 assert(bestoverest != NULL);
2613 violatedabove = FALSE;
2614 }
2615 }
2616 else
2617 {
2618 assert(bestoverest[idx] >= 0 && bestoverest[idx] < terms[idx].nauxexprs);
2619
2620 /* if we are here, the relation with the best overestimator must be violated */
2621 assert(SCIPisFeasPositive(scip, valj * vali - SCIPevalBilinAuxExprNonlinear(scip, terms[idx].x, terms[idx].y,
2622 terms[idx].aux.exprs[bestoverest[idx]], sol)));
2623 violatedabove = TRUE;
2624 }
2625
2626 /* only violated products contribute to row marks */
2627 if( !violatedbelow && !violatedabove )
2628 {
2629 SCIPdebugMsg(scip, "the product for vars <%s> and <%s> is not violated\n", SCIPvarGetName(xj), SCIPvarGetName(xi));
2630 continue;
2631 }
2632
2633 /* get the column of xi */
2634 coli = SCIPvarGetCol(xi);
2635 colvals = SCIPcolGetVals(coli);
2636 ncolrows = SCIPcolGetNNonz(coli);
2637 colrows = SCIPcolGetRows(coli);
2638
2639 SCIPdebugMsg(scip, "marking rows for xj = <%s>, xi = <%s>\n", SCIPvarGetName(xj), SCIPvarGetName(xi));
2640
2641 /* mark the rows */
2642 for( r = 0; r < ncolrows; ++r )
2643 {
2644 ridx = SCIProwGetIndex(colrows[r]);
2645
2646 if( !SCIPhashmapExists(row_to_pos, (void*)(size_t)ridx) )
2647 continue; /* if row index is not in row_to_pos, it means that storeSuitableRows decided to ignore this row */
2648
2649 a = colvals[r];
2650 if( a == 0.0 )
2651 continue;
2652
2653 SCIPdebugMsg(scip, "Marking row %d\n", ridx);
2654 addRowMark(ridx, a, violatedbelow, violatedabove, row_idcs, row_marks, nmarked);
2655 }
2656 }
2657
2658 return SCIP_OKAY;
2659}
2660
2661/** adds McCormick inequalities for implicit products */
2662static
2664 SCIP* scip, /**< SCIP data structure */
2665 SCIP_SEPA* sepa, /**< separator */
2666 SCIP_SEPADATA* sepadata, /**< separator data */
2667 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
2668 int* bestunderestimators,/**< indices of auxiliary underestimators with largest violation in sol */
2669 int* bestoverestimators, /**< indices of auxiliary overestimators with largest violation in sol */
2670 SCIP_RESULT* result /**< pointer to store the result */
2671 )
2672{
2673 int i;
2674 int j;
2676 SCIP_ROW* cut;
2677 char name[SCIP_MAXSTRLEN];
2678 SCIP_Bool underestimate;
2679 SCIP_Real xcoef;
2680 SCIP_Real ycoef;
2681 SCIP_Real auxcoef;
2682 SCIP_Real constant;
2683 SCIP_Bool success;
2686 SCIP_Real refpointx;
2687 SCIP_Real refpointy;
2688 SCIP_INTERVAL bndx;
2689 SCIP_INTERVAL bndy;
2690#ifndef NDEBUG
2691 SCIP_Real productval;
2692 SCIP_Real auxval;
2693#endif
2694
2695 assert(sepadata->nbilinterms == SCIPgetNBilinTermsNonlinear(sepadata->conshdlr));
2696 assert(bestunderestimators != NULL && bestoverestimators != NULL);
2697
2698 cutoff = FALSE;
2699 terms = SCIPgetBilinTermsNonlinear(sepadata->conshdlr);
2700
2701 for( i = 0; i < sepadata->nbilinterms; ++i )
2702 {
2703 if( terms[i].existing )
2704 continue;
2705
2706 assert(terms[i].nauxexprs > 0);
2707
2708 bndx.inf = SCIPvarGetLbLocal(terms[i].x);
2709 bndx.sup = SCIPvarGetUbLocal(terms[i].x);
2710 bndy.inf = SCIPvarGetLbLocal(terms[i].y);
2711 bndy.sup = SCIPvarGetUbLocal(terms[i].y);
2712 refpointx = SCIPgetSolVal(scip, sol, terms[i].x);
2713 refpointy = SCIPgetSolVal(scip, sol, terms[i].y);
2714
2715 /* adjust the reference points */
2716 refpointx = MIN(MAX(refpointx, bndx.inf), bndx.sup); /*lint !e666*/
2717 refpointy = MIN(MAX(refpointy, bndy.inf), bndy.sup); /*lint !e666*/
2718
2719 /* one iteration for underestimation and one for overestimation */
2720 for( j = 0; j < 2; ++j )
2721 {
2722 /* if underestimate, separate xy <= auxexpr; if !underestimate, separate xy >= auxexpr;
2723 * the cuts will be:
2724 * if underestimate: McCormick_under(xy) - auxexpr <= 0,
2725 * if !underestimate: McCormick_over(xy) - auxexpr >= 0
2726 */
2727 underestimate = j == 0;
2728 if( underestimate && bestoverestimators[i] != -1 )
2729 auxexpr = terms[i].aux.exprs[bestoverestimators[i]];
2730 else if( !underestimate && bestunderestimators[i] != -1 )
2731 auxexpr = terms[i].aux.exprs[bestunderestimators[i]];
2732 else
2733 continue;
2734 assert(!underestimate || auxexpr->overestimate);
2735 assert(underestimate || auxexpr->underestimate);
2736
2737#ifndef NDEBUG
2738 /* make sure that the term is violated */
2739 productval = SCIPgetSolVal(scip, sol, terms[i].x) * SCIPgetSolVal(scip, sol, terms[i].y);
2740 auxval = SCIPevalBilinAuxExprNonlinear(scip, terms[i].x, terms[i].y, auxexpr, sol);
2741
2742 /* if underestimate, then xy <= aux must be violated; otherwise aux <= xy must be violated */
2743 assert((underestimate && SCIPisFeasLT(scip, auxval, productval)) ||
2744 (!underestimate && SCIPisFeasLT(scip, productval, auxval)));
2745#endif
2746
2747 /* create an empty row */
2748 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "mccormick_%sestimate_implicit_%s*%s_%" SCIP_LONGINT_FORMAT,
2749 underestimate ? "under" : "over", SCIPvarGetName(terms[i].x), SCIPvarGetName(terms[i].y),
2750 SCIPgetNLPs(scip));
2751
2753 FALSE, FALSE) );
2754
2755 xcoef = 0.0;
2756 ycoef = 0.0;
2757 auxcoef = 0.0;
2758 constant = 0.0;
2759 success = TRUE;
2760
2761 /* subtract auxexpr from the cut */
2762 addAuxexprCoefs(terms[i].x, terms[i].y, auxexpr, -1.0, &auxcoef, &xcoef, &ycoef, &constant);
2763
2764 /* add McCormick terms: ask for an underestimator if relation is xy <= auxexpr, and vice versa */
2765 SCIPaddBilinMcCormick(scip, 1.0, bndx.inf, bndx.sup, refpointx, bndy.inf, bndy.sup, refpointy, !underestimate,
2766 &xcoef, &ycoef, &constant, &success);
2767
2768 if( REALABS(constant) > MAXVARBOUND )
2769 success = FALSE;
2770
2771 if( success )
2772 {
2773 assert(!SCIPisInfinity(scip, REALABS(xcoef)));
2774 assert(!SCIPisInfinity(scip, REALABS(ycoef)));
2775 assert(!SCIPisInfinity(scip, REALABS(constant)));
2776
2777 SCIP_CALL( SCIPaddVarToRow(scip, cut, terms[i].x, xcoef) );
2778 SCIP_CALL( SCIPaddVarToRow(scip, cut, terms[i].y, ycoef) );
2779 SCIP_CALL( SCIPaddVarToRow(scip, cut, auxexpr->auxvar, auxcoef) );
2780
2781 /* set side */
2782 if( underestimate )
2783 SCIP_CALL( SCIPchgRowRhs(scip, cut, -constant) );
2784 else
2785 SCIP_CALL( SCIPchgRowLhs(scip, cut, -constant) );
2786
2787 /* if the cut is violated, add it to SCIP */
2789 {
2790 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &cutoff) );
2792 }
2793 else
2794 {
2795 SCIPdebugMsg(scip, "\nMcCormick cut for hidden product <%s>*<%s> was created successfully, but is not violated",
2796 SCIPvarGetName(terms[i].x), SCIPvarGetName(terms[i].y));
2797 }
2798 }
2799
2800 /* release the cut */
2801 if( cut != NULL )
2802 {
2803 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
2804 }
2805
2806 if( cutoff )
2807 {
2809 SCIPdebugMsg(scip, "exit separator because we found a cutoff -> skip\n");
2810 return SCIP_OKAY;
2811 }
2812 }
2813 }
2814
2815 return SCIP_OKAY;
2816}
2817
2818/** builds and adds the RLT cuts */
2819static
2821 SCIP* scip, /**< SCIP data structure */
2822 SCIP_SEPA* sepa, /**< separator */
2823 SCIP_SEPADATA* sepadata, /**< separator data */
2824 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
2825 SCIP_SOL* sol, /**< the point to be separated (can be NULL) */
2826 SCIP_HASHMAP* row_to_pos, /**< hashmap linking row indices to positions in array */
2827 RLT_SIMPLEROW* projrows, /**< projected rows */
2828 SCIP_ROW** rows, /**< problem rows */
2829 int nrows, /**< number of problem rows */
2830 SCIP_Bool allowlocal, /**< are local cuts allowed? */
2831 int* bestunderestimators,/**< indices of auxiliary underestimators with largest violation in sol */
2832 int* bestoverestimators, /**< indices of auxiliary overestimators with largest violation in sol */
2833 SCIP_RESULT* result /**< buffer to store whether separation was successful */
2834 )
2835{
2836 int j;
2837 int r;
2838 int k;
2839 int nmarked;
2840 int cutssize;
2841 int ncuts;
2842 SCIP_VAR* xj;
2843 unsigned int* row_marks;
2844 int* row_idcs;
2845 SCIP_ROW* cut;
2846 SCIP_ROW** cuts;
2847 SCIP_Bool uselb[4] = {TRUE, TRUE, FALSE, FALSE};
2848 SCIP_Bool uselhs[4] = {TRUE, FALSE, TRUE, FALSE};
2849 SCIP_Bool success;
2850 SCIP_Bool infeasible;
2851 SCIP_Bool accepted;
2852 SCIP_Bool buildeqcut;
2853 SCIP_Bool iseqrow;
2854
2855 assert(!sepadata->useprojection || projrows != NULL);
2856 assert(!sepadata->detecthidden || (bestunderestimators != NULL && bestoverestimators != NULL));
2857
2858 ncuts = 0;
2859 cutssize = 0;
2860 cuts = NULL;
2862
2863 SCIP_CALL( SCIPallocCleanBufferArray(scip, &row_marks, nrows) );
2864 SCIP_CALL( SCIPallocBufferArray(scip, &row_idcs, nrows) );
2865
2866 /* loop through all variables that appear in bilinear products */
2867 for( j = 0; j < sepadata->nbilinvars && (sepadata->maxusedvars < 0 || j < sepadata->maxusedvars); ++j )
2868 {
2869 xj = sepadata->varssorted[j];
2870
2871 /* mark all rows for multiplier xj */
2872 SCIP_CALL( markRowsXj(scip, sepadata, conshdlr, sol, j, allowlocal, row_to_pos, bestunderestimators,
2873 bestoverestimators, row_marks, row_idcs, &nmarked) );
2874
2875 assert(nmarked <= nrows);
2876
2877 /* generate the projected cut and if it is violated, generate the actual cut */
2878 for( r = 0; r < nmarked; ++r )
2879 {
2880 int pos;
2881 int currentnunknown;
2882 SCIP_ROW* row;
2883
2884 assert(row_marks[r] != 0);
2885 assert(SCIPhashmapExists(row_to_pos, (void*)(size_t) row_idcs[r])); /*lint !e571 */
2886
2887 pos = SCIPhashmapGetImageInt(row_to_pos, (void*)(size_t) row_idcs[r]); /*lint !e571 */
2888 row = rows[pos];
2889 assert(SCIProwGetIndex(row) == row_idcs[r]);
2890
2891 /* check whether this row and var fulfill the conditions */
2892 SCIP_CALL( isAcceptableRow(sepadata, row, xj, &currentnunknown, &accepted) );
2893 if( !accepted )
2894 {
2895 SCIPdebugMsg(scip, "rejected row <%s> for variable <%s> (introduces too many new products)\n", SCIProwGetName(row), SCIPvarGetName(xj));
2896 row_marks[r] = 0;
2897 continue;
2898 }
2899
2900 SCIPdebugMsg(scip, "accepted row <%s> for variable <%s>\n", SCIProwGetName(rows[r]), SCIPvarGetName(xj));
2901#ifdef SCIP_DEBUG
2902 SCIP_CALL( SCIPprintRow(scip, rows[r], NULL) );
2903#endif
2904 iseqrow = SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row));
2905
2906 /* if all terms are known and it is an equality row, compute equality cut, that is, multiply row with (x-lb) and/or (ub-x) (but see also @todo at top)
2907 * otherwise, multiply row w.r.t. lhs and/or rhs with (x-lb) and/or (ub-x) and estimate product terms that have no aux.var or aux.expr
2908 */
2909 buildeqcut = (currentnunknown == 0 && iseqrow);
2910
2911 /* go over all suitable combinations of sides and bounds and compute the respective cuts */
2912 for( k = 0; k < 4; ++k )
2913 {
2914 /* if equality cuts are possible, lhs and rhs cuts are equal so skip rhs */
2915 if( buildeqcut )
2916 {
2917 if( k != 1 )
2918 continue;
2919 }
2920 /* otherwise which cuts are generated depends on the marks */
2921 else
2922 {
2923 if( row_marks[r] == 1 && uselb[k] == uselhs[k] )
2924 continue;
2925
2926 if( row_marks[r] == 2 && uselb[k] != uselhs[k] )
2927 continue;
2928 }
2929
2930 success = TRUE;
2931 cut = NULL;
2932
2933 SCIPdebugMsg(scip, "row <%s>, uselb = %u, uselhs = %u\n", SCIProwGetName(row), uselb[k], uselhs[k]);
2934
2935 if( sepadata->useprojection )
2936 {
2937 /* if no variables are left in the projected row, the RLT cut will not be violated */
2938 if( projrows[pos].nnonz == 0 )
2939 continue;
2940
2941 /* compute the rlt cut for a projected row first */
2942 SCIP_CALL( computeRltCut(scip, sepa, sepadata, &cut, NULL, &(projrows[pos]), sol, bestunderestimators,
2943 bestoverestimators, xj, &success, uselb[k], uselhs[k], allowlocal, buildeqcut, TRUE) );
2944
2945 /* if the projected cut is not violated, set success to FALSE */
2946 if( cut != NULL )
2947 {
2948 SCIPdebugMsg(scip, "proj cut viol = %g\n", -SCIPgetRowFeasibility(scip, cut));
2949 }
2950 if( cut != NULL && !SCIPisFeasPositive(scip, -SCIPgetRowFeasibility(scip, cut)) )
2951 {
2952 SCIPdebugMsg(scip, "projected cut is not violated, feasibility = %g\n", SCIPgetRowFeasibility(scip, cut));
2953 success = FALSE;
2954 }
2955
2956 /* release the projected cut */
2957 if( cut != NULL )
2958 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
2959 }
2960
2961 /* if we don't use projection or if the projected cut was generated successfully and is violated,
2962 * generate the actual cut */
2963 if( success )
2964 {
2965 SCIP_CALL( computeRltCut(scip, sepa, sepadata, &cut, row, NULL, sol, bestunderestimators,
2966 bestoverestimators, xj, &success, uselb[k], uselhs[k], allowlocal, buildeqcut, FALSE) );
2967 }
2968
2969 if( success )
2970 {
2971 success = SCIPisFeasNegative(scip, SCIPgetRowFeasibility(scip, cut)) || (sepadata->addtopool &&
2972 !SCIProwIsLocal(cut));
2973 }
2974
2975 /* if the cut was created successfully and is violated or (if addtopool == TRUE) globally valid,
2976 * it is added to the cuts array */
2977 if( success )
2978 {
2979 if( ncuts + 1 > cutssize )
2980 {
2981 int newsize;
2982
2983 newsize = SCIPcalcMemGrowSize(scip, ncuts + 1);
2984 SCIP_CALL( SCIPreallocBufferArray(scip, &cuts, newsize) );
2985 cutssize = newsize;
2986 }
2987 cuts[ncuts] = cut;
2988 (ncuts)++;
2989 }
2990 else
2991 {
2992 SCIPdebugMsg(scip, "the generation of the cut failed or cut not violated and not added to cutpool\n");
2993 /* release the cut */
2994 if( cut != NULL )
2995 {
2996 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
2997 }
2998 }
2999 }
3000
3001 /* clear row_marks[r] since it will be used for the next multiplier */
3002 row_marks[r] = 0;
3003 }
3004 }
3005
3006 /* if cuts were found, we apply an additional filtering procedure, which is similar to sepastore */
3007 if( ncuts > 0 )
3008 {
3009 int nselectedcuts;
3010 int i;
3011
3012 assert(cuts != NULL);
3013
3014 SCIP_CALL( SCIPselectCutsHybrid(scip, cuts, NULL, NULL, sepadata->goodscore, sepadata->badscore, sepadata->goodmaxparall,
3015 sepadata->maxparall, sepadata->dircutoffdistweight, sepadata->efficacyweight, sepadata->objparalweight,
3016 0.0, ncuts, 0, sepadata->maxncuts == -1 ? ncuts : sepadata->maxncuts, &nselectedcuts) );
3017
3018 for( i = 0; i < ncuts; ++i )
3019 {
3020 assert(cuts[i] != NULL);
3021
3022 if( i < nselectedcuts )
3023 {
3024 /* if selected, add global cuts to the pool and local cuts to the sepastore */
3025 if( SCIProwIsLocal(cuts[i]) || !sepadata->addtopool )
3026 {
3027 SCIP_CALL( SCIPaddRow(scip, cuts[i], FALSE, &infeasible) );
3028
3029 if( infeasible )
3030 {
3031 SCIPdebugMsg(scip, "CUTOFF! The cut <%s> revealed infeasibility\n", SCIProwGetName(cuts[i]));
3033 }
3034 else
3035 {
3036 SCIPdebugMsg(scip, "SEPARATED: added cut to scip\n");
3038 }
3039 }
3040 else
3041 {
3042 SCIP_CALL( SCIPaddPoolCut(scip, cuts[i]) );
3043 }
3044 }
3045
3046 /* release current cut */
3047 SCIP_CALL( SCIPreleaseRow(scip, &cuts[i]) );
3048 }
3049 }
3050
3051 SCIPdebugMsg(scip, "exit separator because cut calculation is finished\n");
3052
3054 SCIPfreeBufferArray(scip, &row_idcs);
3055 SCIPfreeCleanBufferArray(scip, &row_marks);
3056
3057 return SCIP_OKAY;
3058}
3059
3060/*
3061 * Callback methods of separator
3062 */
3063
3064/** copy method for separator plugins (called when SCIP copies plugins) */
3065static
3067{ /*lint --e{715}*/
3068 assert(scip != NULL);
3069 assert(sepa != NULL);
3070
3072
3073 /* call inclusion method of separator */
3075
3076 return SCIP_OKAY;
3077}
3078
3079/** destructor of separator to free user data (called when SCIP is exiting) */
3080static
3082{ /*lint --e{715}*/
3084
3086
3087 sepadata = SCIPsepaGetData(sepa);
3088 assert(sepadata != NULL);
3089
3090 /* free separator data */
3092
3093 SCIPsepaSetData(sepa, NULL);
3094
3095 return SCIP_OKAY;
3096}
3097
3098/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
3099static
3101{ /*lint --e{715}*/
3103
3105
3106 sepadata = SCIPsepaGetData(sepa);
3107 assert(sepadata != NULL);
3108
3109 if( sepadata->iscreated )
3110 {
3112 }
3113
3114 return SCIP_OKAY;
3115}
3116
3117/** LP solution separation method of separator */
3118static
3120{ /*lint --e{715}*/
3121 SCIP_ROW** prob_rows;
3122 SCIP_ROW** rows;
3124 int ncalls;
3125 int nrows;
3126 SCIP_HASHMAP* row_to_pos;
3127 RLT_SIMPLEROW* projrows;
3128
3130
3131 sepadata = SCIPsepaGetData(sepa);
3133
3134 if( sepadata->maxncuts == 0 )
3135 {
3136 SCIPdebugMsg(scip, "exit separator because maxncuts is set to 0\n");
3137 return SCIP_OKAY;
3138 }
3139
3140 /* don't run in a sub-SCIP or in probing */
3141 if( SCIPgetSubscipDepth(scip) > 0 && !sepadata->useinsubscip )
3142 {
3143 SCIPdebugMsg(scip, "exit separator because in sub-SCIP\n");
3144 return SCIP_OKAY;
3145 }
3146
3147 /* don't run in probing */
3148 if( SCIPinProbing(scip) )
3149 {
3150 SCIPdebugMsg(scip, "exit separator because in probing\n");
3151 return SCIP_OKAY;
3152 }
3153
3154 /* only call separator a given number of times at each node */
3156 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
3157 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
3158 {
3159 SCIPdebugMsg(scip, "exit separator because round limit for this node is reached\n");
3160 return SCIP_OKAY;
3161 }
3162
3163 /* if this is called for the first time, create the sepadata and start the initial separation round */
3164 if( !sepadata->iscreated )
3165 {
3168 }
3169 assert(sepadata->iscreated || (sepadata->nbilinvars == 0 && sepadata->nbilinterms == 0));
3170 assert(sepadata->nbilinterms == SCIPgetNBilinTermsNonlinear(sepadata->conshdlr));
3171
3172 /* no bilinear terms available -> skip */
3173 if( sepadata->nbilinvars == 0 )
3174 {
3175 SCIPdebugMsg(scip, "exit separator because there are no known bilinear terms\n");
3176 return SCIP_OKAY;
3177 }
3178
3179 /* only call separator, if we are not close to terminating */
3180 if( SCIPisStopped(scip) )
3181 {
3182 SCIPdebugMsg(scip, "exit separator because we are too close to terminating\n");
3183 return SCIP_OKAY;
3184 }
3185
3186 /* only call separator, if an optimal LP solution is at hand */
3188 {
3189 SCIPdebugMsg(scip, "exit separator because there is no LP solution at hand\n");
3190 return SCIP_OKAY;
3191 }
3192
3193 /* get the rows, depending on settings */
3194 if( sepadata->isinitialround || sepadata->onlyoriginal )
3195 {
3196 SCIP_CALL( getOriginalRows(scip, &prob_rows, &nrows) );
3197 }
3198 else
3199 {
3200 SCIP_CALL( SCIPgetLPRowsData(scip, &prob_rows, &nrows) );
3201 }
3202
3203 /* save the suitable rows */
3204 SCIP_CALL( SCIPallocBufferArray(scip, &rows, nrows) );
3205 SCIP_CALL( SCIPhashmapCreate(&row_to_pos, SCIPblkmem(scip), nrows) );
3206
3207 SCIP_CALL( storeSuitableRows(scip, sepa, sepadata, prob_rows, rows, &nrows, row_to_pos, allowlocal) );
3208
3209 if( nrows == 0 ) /* no suitable rows found, free memory and exit */
3210 {
3211 SCIPhashmapFree(&row_to_pos);
3212 SCIPfreeBufferArray(scip, &rows);
3213 if( sepadata->isinitialround || sepadata->onlyoriginal )
3214 {
3215 SCIPfreeBufferArray(scip, &prob_rows);
3216 sepadata->isinitialround = FALSE;
3217 }
3218 return SCIP_OKAY;
3219 }
3220
3221 /* create the projected problem */
3222 if( sepadata->useprojection )
3223 {
3224 SCIP_Bool allcst;
3225
3226 SCIP_CALL( createProjRows(scip, rows, nrows, NULL, &projrows, allowlocal, &allcst) );
3227
3228 /* if all projected rows have only constants left, quit */
3229 if( allcst )
3230 goto TERMINATE;
3231
3232#ifdef SCIP_DEBUG
3233 printProjRows(scip, projrows, nrows, NULL);
3234#endif
3235 }
3236 else
3237 {
3238 projrows = NULL;
3239 }
3240
3241 /* separate the cuts */
3242 if( sepadata->detecthidden )
3243 {
3244 int* bestunderestimators;
3245 int* bestoverestimators;
3246
3247 /* if we detect implicit products, a term might have more than one estimator in each direction;
3248 * save the indices of the most violated estimators
3249 */
3250 SCIP_CALL( SCIPallocBufferArray(scip, &bestunderestimators, sepadata->nbilinterms) );
3251 SCIP_CALL( SCIPallocBufferArray(scip, &bestoverestimators, sepadata->nbilinterms) );
3252 getBestEstimators(scip, sepadata, NULL, bestunderestimators, bestoverestimators);
3253
3254 /* also separate McCormick cuts for implicit products */
3255 SCIP_CALL( separateMcCormickImplicit(scip, sepa, sepadata, NULL, bestunderestimators, bestoverestimators,
3256 result) );
3257
3258 if( *result != SCIP_CUTOFF )
3259 {
3260 SCIP_CALL( separateRltCuts(scip, sepa, sepadata, sepadata->conshdlr, NULL, row_to_pos, projrows, rows, nrows,
3261 allowlocal, bestunderestimators, bestoverestimators, result) );
3262 }
3263
3264 SCIPfreeBufferArray(scip, &bestoverestimators);
3265 SCIPfreeBufferArray(scip, &bestunderestimators);
3266 }
3267 else
3268 {
3269 SCIP_CALL( separateRltCuts(scip, sepa, sepadata, sepadata->conshdlr, NULL, row_to_pos, projrows, rows, nrows,
3270 allowlocal, NULL, NULL, result) );
3271 }
3272
3273 TERMINATE:
3274 /* free the projected problem */
3275 if( sepadata->useprojection )
3276 {
3277 freeProjRows(scip, &projrows, nrows);
3278 }
3279
3280 SCIPhashmapFree(&row_to_pos);
3281 SCIPfreeBufferArray(scip, &rows);
3282
3283 if( sepadata->isinitialround || sepadata->onlyoriginal )
3284 {
3285 SCIPfreeBufferArray(scip, &prob_rows);
3286 sepadata->isinitialround = FALSE;
3287 }
3288
3289 return SCIP_OKAY;
3290}
3291
3292/*
3293 * separator specific interface methods
3294 */
3295
3296/** creates the RLT separator and includes it in SCIP */
3298 SCIP* scip /**< SCIP data structure */
3299 )
3300{
3302 SCIP_SEPA* sepa;
3303
3304 /* create RLT separator data */
3306 sepadata->conshdlr = SCIPfindConshdlr(scip, "nonlinear");
3307 assert(sepadata->conshdlr != NULL);
3308
3309 /* include separator */
3311 SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpRlt, NULL, sepadata) );
3312
3313 /* set non fundamental callbacks via setter functions */
3314 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyRlt) );
3315 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeRlt) );
3316 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolRlt) );
3317
3318 /* add RLT separator parameters */
3320 "separating/" SEPA_NAME "/maxncuts",
3321 "maximal number of rlt-cuts that are added per round (-1: unlimited)",
3322 &sepadata->maxncuts, FALSE, DEFAULT_MAXNCUTS, -1, INT_MAX, NULL, NULL) );
3323
3325 "separating/" SEPA_NAME "/maxunknownterms",
3326 "maximal number of unknown bilinear terms a row is still used with (-1: unlimited)",
3327 &sepadata->maxunknownterms, FALSE, DEFAULT_MAXUNKNOWNTERMS, -1, INT_MAX, NULL, NULL) );
3328
3330 "separating/" SEPA_NAME "/maxusedvars",
3331 "maximal number of variables used to compute rlt cuts (-1: unlimited)",
3332 &sepadata->maxusedvars, FALSE, DEFAULT_MAXUSEDVARS, -1, INT_MAX, NULL, NULL) );
3333
3335 "separating/" SEPA_NAME "/maxrounds",
3336 "maximal number of separation rounds per node (-1: unlimited)",
3337 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
3338
3340 "separating/" SEPA_NAME "/maxroundsroot",
3341 "maximal number of separation rounds in the root node (-1: unlimited)",
3342 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
3343
3345 "separating/" SEPA_NAME "/onlyeqrows",
3346 "if set to true, only equality rows are used for rlt cuts",
3347 &sepadata->onlyeqrows, FALSE, DEFAULT_ONLYEQROWS, NULL, NULL) );
3348
3350 "separating/" SEPA_NAME "/onlycontrows",
3351 "if set to true, only continuous rows are used for rlt cuts",
3352 &sepadata->onlycontrows, FALSE, DEFAULT_ONLYCONTROWS, NULL, NULL) );
3353
3355 "separating/" SEPA_NAME "/onlyoriginal",
3356 "if set to true, only original rows and variables are used",
3357 &sepadata->onlyoriginal, FALSE, DEFAULT_ONLYORIGINAL, NULL, NULL) );
3358
3360 "separating/" SEPA_NAME "/useinsubscip",
3361 "if set to true, rlt is also used in sub-scips",
3362 &sepadata->useinsubscip, FALSE, DEFAULT_USEINSUBSCIP, NULL, NULL) );
3363
3365 "separating/" SEPA_NAME "/useprojection",
3366 "if set to true, projected rows are checked first",
3367 &sepadata->useprojection, FALSE, DEFAULT_USEPROJECTION, NULL, NULL) );
3368
3370 "separating/" SEPA_NAME "/detecthidden",
3371 "if set to true, hidden products are detected and separated by McCormick cuts",
3372 &sepadata->detecthidden, FALSE, DEFAULT_DETECTHIDDEN, NULL, NULL) );
3373
3375 "separating/" SEPA_NAME "/hiddenrlt",
3376 "whether RLT cuts (TRUE) or only McCormick inequalities (FALSE) should be added for hidden products",
3377 &sepadata->hiddenrlt, FALSE, DEFAULT_HIDDENRLT, NULL, NULL) );
3378
3380 "separating/" SEPA_NAME "/addtopool",
3381 "if set to true, globally valid RLT cuts are added to the global cut pool",
3382 &sepadata->addtopool, FALSE, DEFAULT_ADDTOPOOL, NULL, NULL) );
3383
3385 "separating/" SEPA_NAME "/goodscore",
3386 "threshold for score of cut relative to best score to be considered good, so that less strict filtering is applied",
3387 &sepadata->goodscore, TRUE, DEFAULT_GOODSCORE, 0.0, 1.0, NULL, NULL) );
3388
3390 "separating/" SEPA_NAME "/badscore",
3391 "threshold for score of cut relative to best score to be discarded",
3392 &sepadata->badscore, TRUE, DEFAULT_BADSCORE, 0.0, 1.0, NULL, NULL) );
3393
3395 "separating/" SEPA_NAME "/objparalweight",
3396 "weight of objective parallelism in cut score calculation",
3397 &sepadata->objparalweight, TRUE, DEFAULT_OBJPARALWEIGHT, 0.0, 1.0, NULL, NULL) );
3398
3400 "separating/" SEPA_NAME "/efficacyweight",
3401 "weight of efficacy in cut score calculation",
3402 &sepadata->efficacyweight, TRUE, DEFAULT_EFFICACYWEIGHT, 0.0, 1.0, NULL, NULL) );
3403
3405 "separating/" SEPA_NAME "/dircutoffdistweight",
3406 "weight of directed cutoff distance in cut score calculation",
3407 &sepadata->dircutoffdistweight, TRUE, DEFAULT_DIRCUTOFFDISTWEIGHT, 0.0, 1.0, NULL, NULL) );
3408
3410 "separating/" SEPA_NAME "/goodmaxparall",
3411 "maximum parallelism for good cuts",
3412 &sepadata->goodmaxparall, TRUE, DEFAULT_GOODMAXPARALL, 0.0, 1.0, NULL, NULL) );
3413
3415 "separating/" SEPA_NAME "/maxparall",
3416 "maximum parallelism for non-good cuts",
3417 &sepadata->maxparall, TRUE, DEFAULT_MAXPARALL, 0.0, 1.0, NULL, NULL) );
3418
3419 return SCIP_OKAY;
3420}
#define DEFAULT_EFFICACYWEIGHT
SCIP_VAR * w
SCIP_VAR * a
SCIP_VAR ** y
SCIP_VAR ** x
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXROUNDS
constraint handler for nonlinear constraints specified by algebraic expressions
#define DEFAULT_OBJPARALWEIGHT
#define DEFAULT_DIRCUTOFFDISTWEIGHT
hybrid cut selector
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define MAX3(x, y, z)
Definition def.h:237
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define MIN3(x, y, z)
Definition def.h:241
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
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:3246
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:3314
power and signed power expression handlers
SCIP_Real SCIPevalBilinAuxExprNonlinear(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_SOL *sol)
SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, SCIP_Real coefx, SCIP_Real coefy, SCIP_Real coefaux, SCIP_Real cst, SCIP_Bool overestimate)
int SCIPgetBilinTermIdxNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
struct SCIP_ConsNonlinear_BilinTerm SCIP_CONSNONLINEAR_BILINTERM
struct SCIP_ConsNonlinear_Auxexpr SCIP_CONSNONLINEAR_AUXEXPR
SCIP_RETCODE SCIPselectCutsHybrid(SCIP *scip, SCIP_ROW **cuts, SCIP_ROW **forcedcuts, SCIP_RANDNUMGEN *randnumgen, SCIP_Real goodscorefac, SCIP_Real badscorefac, SCIP_Real goodmaxparall, SCIP_Real maxparall, SCIP_Real dircutoffdistweight, SCIP_Real efficacyweight, SCIP_Real objparalweight, SCIP_Real intsupportweight, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
int SCIPgetSubscipDepth(SCIP *scip)
Definition scip_copy.c:2589
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition scip_prob.c:3666
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
int SCIPgetNConss(SCIP *scip)
Definition scip_prob.c:3620
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition misc.c:3613
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition misc.c:3584
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition misc.c:3592
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3400
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
int SCIPhashtableGetNEntries(SCIP_HASHTABLE *hashtable)
Definition misc.c:2765
#define SCIPhashFour(a, b, c, d)
Definition pub_misc.h:573
void * SCIPhashtableGetEntry(SCIP_HASHTABLE *hashtable, int entryidx)
Definition misc.c:2773
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2596
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
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 SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition misc.c:10498
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition lp.c:17425
SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
Definition lp.c:17455
int SCIPcolGetNNonz(SCIP_COL *col)
Definition lp.c:17520
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition lp.c:17555
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition lp.c:17545
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
struct SCIP_Interval SCIP_INTERVAL
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition scip_lp.c:576
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition scip_mem.h:146
#define SCIPfreeBuffer(scip, ptr)
Definition scip_mem.h:134
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition scip_mem.h:142
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBlockMemory(scip, ptr)
Definition scip_mem.h:91
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition scip_mem.h:107
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:93
#define SCIPallocBuffer(scip, ptr)
Definition scip_mem.h:122
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition lp.c:17686
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
Definition scip_lp.c:1529
SCIP_Real SCIPgetRowFeasibility(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:2088
int SCIProwGetNNonz(SCIP_ROW *row)
Definition lp.c:17607
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition lp.c:17632
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition lp.c:17696
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition lp.c:17795
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
const char * SCIProwGetName(SCIP_ROW *row)
Definition lp.c:17745
SCIP_SEPA * SCIProwGetOriginSepa(SCIP_ROW *row)
Definition lp.c:17870
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
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:1429
int SCIProwGetIndex(SCIP_ROW *row)
Definition lp.c:17755
SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
Definition scip_lp.c:1553
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition lp.c:17652
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition lp.c:17642
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
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:173
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition sepa.c:893
SCIP_RETCODE SCIPsetSepaExitsol(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:237
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition sepa.c:636
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition sepa.c:646
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:157
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition var.c:24514
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition var.c:23715
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition var.c:24536
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24600
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
void SCIPvarGetImplicVarBounds(SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Real *lb, SCIP_Real *ub)
Definition var.c:16521
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23485
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24617
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23684
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition var.c:24546
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition var.c:24556
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24646
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24674
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Bool SCIPvarIsRelaxationOnly(SCIP_VAR *var)
Definition var.c:23632
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition var.c:24526
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24685
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17319
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition var.c:24588
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition var.c:24568
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:16852
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition var.c:24578
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24632
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
void SCIPselectDownIntPtr(int *intarray, void **ptrarray, int k, int len)
SCIP_RETCODE SCIPincludeSepaRlt(SCIP *scip)
Definition sepa_rlt.c:3297
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIP_Longint ncalls
int c
int depth
SCIP_Bool cutoff
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_VAR ** vars
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition implics.c:1141
SCIP_ROW * SCIPconsGetRow(SCIP *scip, SCIP_CONS *cons)
bilinear nonlinear handler
struct HashData HASHDATA
public methods for LP management
#define SCIPstatisticMessage
#define SEPA_PRIORITY
#define SEPA_DELAY
#define SEPA_DESC
#define SEPA_USESSUBSCIP
#define SEPA_MAXBOUNDDIST
#define SEPA_FREQ
#define SEPA_NAME
static SCIP_RETCODE extractProducts(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR **vars_xwy, SCIP_Real *coefs1, SCIP_Real *coefs2, SCIP_Real d1, SCIP_Real d2, SCIP_SIDETYPE sidetype1, SCIP_SIDETYPE sidetype2, SCIP_HASHMAP *varmap, SCIP_Bool f)
Definition sepa_rlt.c:661
#define DEFAULT_BADSCORE
Definition sepa_rlt.c:73
static SCIP_RETCODE isAcceptableRow(SCIP_SEPADATA *sepadata, SCIP_ROW *row, SCIP_VAR *var, int *currentnunknown, SCIP_Bool *acceptable)
Definition sepa_rlt.c:1783
static SCIP_RETCODE separateMcCormickImplicit(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, int *bestunderestimators, int *bestoverestimators, SCIP_RESULT *result)
Definition sepa_rlt.c:2663
struct AdjacentVarData ADJACENTVARDATA
Definition sepa_rlt.c:105
#define DEFAULT_GOODSCORE
Definition sepa_rlt.c:71
#define DEFAULT_MAXUSEDVARS
Definition sepa_rlt.c:58
static SCIP_VAR ** getAdjacentVars(SCIP_HASHMAP *adjvarmap, SCIP_VAR *var, int *nadjacentvars)
Definition sepa_rlt.c:312
#define DEFAULT_USEPROJECTION
Definition sepa_rlt.c:66
#define DEFAULT_DETECTHIDDEN
Definition sepa_rlt.c:67
static SCIP_RETCODE detectProductsClique(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *coefs1, SCIP_VAR **vars_xwy, SCIP_Real side1, SCIP_SIDETYPE sidetype1, int varpos1, int varpos2, SCIP_HASHMAP *varmap, SCIP_Bool f)
Definition sepa_rlt.c:922
static void implBndToBigM(SCIP *scip, SCIP_VAR **vars_xwy, int binvarpos, int implvarpos, SCIP_BOUNDTYPE bndtype, SCIP_Bool binval, SCIP_Real implbnd, SCIP_Real *coefs, SCIP_Real *side)
Definition sepa_rlt.c:808
#define MAXVARBOUND
Definition sepa_rlt.c:80
#define DEFAULT_HIDDENRLT
Definition sepa_rlt.c:68
static SCIP_RETCODE separateRltCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_HASHMAP *row_to_pos, RLT_SIMPLEROW *projrows, SCIP_ROW **rows, int nrows, SCIP_Bool allowlocal, int *bestunderestimators, int *bestoverestimators, SCIP_RESULT *result)
Definition sepa_rlt.c:2820
#define DEFAULT_MAXPARALL
Definition sepa_rlt.c:78
static void freeProjRow(SCIP *scip, RLT_SIMPLEROW *simplerow)
Definition sepa_rlt.c:2319
static SCIP_RETCODE addRltTerm(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, int *bestunderest, int *bestoverest, SCIP_ROW *cut, SCIP_VAR *var, SCIP_VAR *colvar, SCIP_Real coef, SCIP_Bool uselb, SCIP_Bool uselhs, SCIP_Bool local, SCIP_Bool computeEqCut, SCIP_Real *coefvar, SCIP_Real *cst, SCIP_Bool *success)
Definition sepa_rlt.c:1870
static SCIP_RETCODE detectProductsImplbnd(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *coefs1, SCIP_VAR **vars_xwy, SCIP_Real side1, SCIP_SIDETYPE sidetype1, int binvarpos, int implvarpos, SCIP_HASHMAP *varmap, SCIP_Bool f)
Definition sepa_rlt.c:856
static SCIP_RETCODE getOriginalRows(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition sepa_rlt.c:409
#define DEFAULT_ONLYORIGINAL
Definition sepa_rlt.c:64
struct RLT_SimpleRow RLT_SIMPLEROW
Definition sepa_rlt.c:164
static SCIP_RETCODE fillRelationTables(SCIP *scip, SCIP_ROW **prob_rows, int nrows, SCIP_HASHTABLE *hashtable2, SCIP_HASHTABLE *hashtable3, SCIP_HASHMAP *vars_in_2rels, int *row_list)
Definition sepa_rlt.c:1099
static SCIP_RETCODE createProjRow(SCIP *scip, RLT_SIMPLEROW *simplerow, SCIP_ROW *row, SCIP_SOL *sol, SCIP_Bool local)
Definition sepa_rlt.c:2255
static SCIP_RETCODE createProjRows(SCIP *scip, SCIP_ROW **rows, int nrows, SCIP_SOL *sol, RLT_SIMPLEROW **projrows, SCIP_Bool local, SCIP_Bool *allcst)
Definition sepa_rlt.c:2343
#define DEFAULT_MAXNCUTS
Definition sepa_rlt.c:59
static SCIP_RETCODE detectHiddenProducts(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_HASHMAP *varmap)
Definition sepa_rlt.c:1227
static SCIP_RETCODE markRowsXj(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int j, SCIP_Bool local, SCIP_HASHMAP *row_to_pos, int *bestunderest, int *bestoverest, unsigned int *row_marks, int *row_idcs, int *nmarked)
Definition sepa_rlt.c:2496
static void addAuxexprCoefs(SCIP_VAR *var1, SCIP_VAR *var2, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Real coef, SCIP_Real *coefaux, SCIP_Real *coef1, SCIP_Real *coef2, SCIP_Real *cst)
Definition sepa_rlt.c:1829
#define DEFAULT_USEINSUBSCIP
Definition sepa_rlt.c:65
static SCIP_RETCODE computeRltCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_ROW **cut, SCIP_ROW *row, RLT_SIMPLEROW *projrow, SCIP_SOL *sol, int *bestunderest, int *bestoverest, SCIP_VAR *var, SCIP_Bool *success, SCIP_Bool uselb, SCIP_Bool uselhs, SCIP_Bool local, SCIP_Bool computeEqCut, SCIP_Bool useprojrow)
Definition sepa_rlt.c:2110
#define DEFAULT_ADDTOPOOL
Definition sepa_rlt.c:69
static SCIP_RETCODE createSepaData(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition sepa_rlt.c:1591
#define DEFAULT_GOODMAXPARALL
Definition sepa_rlt.c:77
static void clearVarAdjacency(SCIP *scip, SCIP_HASHMAP *adjvarmap)
Definition sepa_rlt.c:335
static SCIP_RETCODE freeSepaData(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition sepa_rlt.c:365
static SCIP_RETCODE storeSuitableRows(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_ROW **prob_rows, SCIP_ROW **rows, int *nrows, SCIP_HASHMAP *row_to_pos, SCIP_Bool allowlocal)
Definition sepa_rlt.c:446
static SCIP_RETCODE addProductVars(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR *x, SCIP_VAR *y, SCIP_HASHMAP *varmap, int nlocks)
Definition sepa_rlt.c:545
#define DEFAULT_MAXUNKNOWNTERMS
Definition sepa_rlt.c:57
static SCIP_RETCODE addAdjacentVars(SCIP *scip, SCIP_HASHMAP *adjvarmap, SCIP_VAR **vars)
Definition sepa_rlt.c:238
static SCIP_RETCODE detectProductsUnconditional(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_ROW **rows, int *row_list, SCIP_HASHTABLE *hashtable, SCIP_Real *coefs1, SCIP_VAR **vars_xwy, SCIP_Real side1, SCIP_SIDETYPE sidetype1, int varpos1, int varpos2, SCIP_HASHMAP *varmap, SCIP_Bool f)
Definition sepa_rlt.c:995
static void addRowMark(int ridx, SCIP_Real a, SCIP_Bool violatedbelow, SCIP_Bool violatedabove, int *row_idcs, unsigned int *row_marks, int *nmarked)
Definition sepa_rlt.c:2449
static void freeProjRows(SCIP *scip, RLT_SIMPLEROW **projrows, int nrows)
Definition sepa_rlt.c:2427
static SCIP_RETCODE ensureVarsSize(SCIP *scip, SCIP_SEPADATA *sepadata, int n)
Definition sepa_rlt.c:515
#define DEFAULT_ONLYEQROWS
Definition sepa_rlt.c:62
static void getBestEstimators(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, int *bestunderestimators, int *bestoverestimators)
Definition sepa_rlt.c:1726
#define DEFAULT_ONLYCONTROWS
Definition sepa_rlt.c:63
reformulation-linearization technique separator
SCIP_VAR ** adjacentvars
Definition sepa_rlt.c:101
int nrows
Definition sepa_rlt.c:91
int firstrow
Definition sepa_rlt.c:92
SCIP_Real rhs
Definition sepa_rlt.c:158
SCIP_VAR ** vars
Definition sepa_rlt.c:157
SCIP_Real cst
Definition sepa_rlt.c:160
const char * name
Definition sepa_rlt.c:155
SCIP_Real * coefs
Definition sepa_rlt.c:156
SCIP_Real lhs
Definition sepa_rlt.c:159
SCIP_CONSNONLINEAR_AUXEXPR ** exprs
union SCIP_ConsNonlinear_BilinTerm::@055261256347130033265073212045155110332303333345 aux
SCIP_Real sup
SCIP_Real inf
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
struct SCIP_Clique SCIP_CLIQUE
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_UPPER
Definition type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
struct SCIP_Col SCIP_COL
Definition type_lp.h:99
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition type_lp.h:60
@ SCIP_SIDETYPE_RIGHT
Definition type_lp.h:66
@ SCIP_SIDETYPE_LEFT
Definition type_lp.h:65
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
enum SCIP_SideType SCIP_SIDETYPE
Definition type_lp.h:68
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
struct SCIP_HashMapEntry SCIP_HASHMAPENTRY
Definition type_misc.h:100
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
@ 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_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_SepaData SCIP_SEPADATA
Definition type_sepa.h:52
#define SCIP_DECL_SEPAEXECLP(x)
Definition type_sepa.h:136
#define SCIP_DECL_SEPAFREE(x)
Definition type_sepa.h:69
#define SCIP_DECL_SEPAEXITSOL(x)
Definition type_sepa.h:107
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
#define SCIP_DECL_SEPACOPY(x)
Definition type_sepa.h:61
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_COLUMN
Definition type_var.h:53