SCIP Doxygen Documentation
Loading...
Searching...
No Matches
presol_dualsparsify.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 presol_dualsparsify.c
26 * @brief cancel nonzeros of the constraint matrix based on the columns
27 * @author Dieter Weninger
28 * @author Leona Gottwald
29 * @author Ambros Gleixner
30 * @author Weikun Chen
31 *
32 * This presolver attempts to cancel non-zero entries of the constraint
33 * matrix by adding scaled columns to other columns.
34 *
35 * In more detail, for two columns A_{j.} and A_{k.}, suppose for a given value s, we have
36 *
37 * | A_{j.} | - | A_{j.} - s*A_{k.} | > eta,
38 *
39 * where eta is an nonnegative integer. Then we introduce a new variable y := s*x_j + x_k
40 * and aggregate the variable x_k = y - s*x_j. After aggregation, the column of the variable
41 * x_j is A_{j.} + s*A_{j.} which is sparser than A_{j.}. In the case that x_k is nonimplied
42 * free variable, we need to add a new constraint l_k <= y - weight*x_j <= u_k into the problem
43 * to keep the bounds constraints of variable x_k.
44 *
45 * Further information can be found in
46 * Chen et al. "Two-row and two-column mixed-integer presolve using hasing-based pairing methods".
47 *
48 * @todo add infrastructure to SCIP for handling aggregated binary variables
49 */
50
51/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
52
54#include "scip/cons_linear.h"
55#include "scip/debug.h"
57#include "scip/pub_cons.h"
58#include "scip/pub_matrix.h"
59#include "scip/pub_message.h"
60#include "scip/pub_misc.h"
61#include "scip/pub_misc_sort.h"
62#include "scip/pub_presol.h"
63#include "scip/pub_var.h"
64#include "scip/scip_cons.h"
65#include "scip/scip_general.h"
66#include "scip/scip_mem.h"
67#include "scip/scip_message.h"
68#include "scip/scip_nlp.h"
69#include "scip/scip_numerics.h"
70#include "scip/scip_param.h"
71#include "scip/scip_presol.h"
72#include "scip/scip_pricer.h"
73#include "scip/scip_prob.h"
74#include "scip/scip_probing.h"
76#include "scip/scip_timing.h"
77#include "scip/scip_var.h"
78
79
80#define PRESOL_NAME "dualsparsify"
81#define PRESOL_DESC "eliminate non-zero coefficients"
82
83#define PRESOL_PRIORITY -240000 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers) */
84#define PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
85#define PRESOL_TIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolver (fast, medium, or exhaustive) */
86
87#define DEFAULT_ENABLECOPY TRUE /**< should dualsparsify presolver be copied to sub-SCIPs? */
88#define DEFAULT_PRESERVEINTCOEFS FALSE /**< should we forbid cancellations that destroy integer coefficients? */
89#define DEFAULT_PRESERVEGOODLOCKS FALSE /**< should we preserve good locked properties of variables (at most one lock in one direction)? */
90#define DEFAULT_MAX_CONT_FILLIN 1 /**< default value for the maximal fillin for continuous variables */
91#define DEFAULT_MAX_BIN_FILLIN 1 /**< default value for the maximal fillin for binary variables */
92#define DEFAULT_MAX_INT_FILLIN 1 /**< default value for the maximal fillin for integer variables (including binary) */
93#define DEFAULT_MAXCONSIDEREDNONZEROS 70 /**< maximal number of considered nonzeros within one column (-1: no limit) */
94#define DEFAULT_MINELIMINATEDNONZEROS 100 /**< minimal eleminated nonzeros within one column if we need to add a constraint to the problem */
95#define DEFAULT_MAXRETRIEVEFAC 100.0 /**< limit on the number of useless vs. useful hashtable retrieves as a multiple of the number of constraints */
96#define DEFAULT_WAITINGFAC 2.0 /**< number of calls to wait until next execution as a multiple of the number of useless calls */
97
98#define MAXSCALE 1000.0 /**< maximal allowed scale for cancelling nonzeros */
99
100
101/*
102 * Data structures
103 */
104
105/** presolver data */
106struct SCIP_PresolData
107{
108 int nfailures; /**< number of calls to presolver without success */
109 int nwaitingcalls; /**< number of presolver calls until next real execution */
110 int naggregated; /**< number of aggregated variables */
111 int maxcontfillin; /**< maximal fillin for continuous variables */
112 int maxintfillin; /**< maximal fillin for integer variables*/
113 int maxbinfillin; /**< maximal fillin for binary variables */
114 int maxconsiderednonzeros;/**< maximal number of considered nonzeros within one column (-1: no limit) */
115 int mineliminatednonzeros;/**< minimal eliminated nonzeros within one column if we need to add a constraint to the problem */
116 SCIP_Real maxretrievefac; /**< limit on the number of useless vs. useful hashtable retrieves as a multiple of the number of constraints */
117 SCIP_Real waitingfac; /**< number of calls to wait until next execution as a multiple of the number of useless calls */
118 SCIP_Bool enablecopy; /**< should dualsparsify presolver be copied to sub-SCIPs? */
119 SCIP_Bool preserveintcoefs; /**< should we forbid cancellations that destroy integer coefficients? */
120 SCIP_Bool preservegoodlocks; /**< should we preserve good locked properties of variables (at most one lock in one direction)? */
121};
122
123/** structure representing a pair of constraints in a column; used for lookup in a hashtable */
125{
126 int colindex; /**< index of the column */
127 int consindex1; /**< index of the first constraint */
128 int consindex2; /**< index of the second constraint */
129 SCIP_Real conscoef1; /**< coefficient of the first constraint */
130 SCIP_Real conscoef2; /**< coefficient of the second constriant */
131};
132
134
135/*
136 * Local methods
137 */
138
139/** returns TRUE iff both keys are equal */
140static
141SCIP_DECL_HASHKEYEQ(consPairsEqual)
142{ /*lint --e{715}*/
143 SCIP* scip;
144 COLCONSPAIR* conspair1;
145 COLCONSPAIR* conspair2;
146 SCIP_Real ratio1;
147 SCIP_Real ratio2;
148
149 scip = (SCIP*) userptr;
150 conspair1 = (COLCONSPAIR*) key1;
151 conspair2 = (COLCONSPAIR*) key2;
152
153 if( conspair1->consindex1 != conspair2->consindex1 )
154 return FALSE;
155
156 if( conspair1->consindex2 != conspair2->consindex2 )
157 return FALSE;
158
159 ratio1 = conspair1->conscoef2 / conspair1->conscoef1;
160 ratio2 = conspair2->conscoef2 / conspair2->conscoef1;
161
162 return SCIPisEQ(scip, ratio1, ratio2);
163}
164
165/** returns the hash value of the key */
166static
167SCIP_DECL_HASHKEYVAL(consPairHashval)
168{ /*lint --e{715}*/
169 COLCONSPAIR* conspair;
170
171 conspair = (COLCONSPAIR*) key;
172
173 return SCIPhashThree(conspair->consindex1, conspair->consindex2, SCIPrealHashCode(conspair->conscoef2 / conspair->conscoef1));
174}
175
176/** calculate maximal activity of one row without one specific column */
177static
179 SCIP* scip, /**< SCIP main data structure */
180 SCIP_MATRIX* matrix, /**< matrix containing the constraints */
181 int row, /**< row index */
182 int col /**< column index */
183 )
184{
185 SCIP_Real* valpnt;
186 int* rowpnt;
187 int* rowend;
188 SCIP_Real maxactivity;
189 SCIP_Real val;
190 SCIP_Real lb;
191 SCIP_Real ub;
192 int c;
193
194 assert(scip != NULL);
195 assert(matrix != NULL);
196
197 maxactivity = 0;
198
199 rowpnt = SCIPmatrixGetRowIdxPtr(matrix, row);
200 rowend = rowpnt + SCIPmatrixGetRowNNonzs(matrix, row);
201 valpnt = SCIPmatrixGetRowValPtr(matrix, row);
202
203 for( ; (rowpnt < rowend); rowpnt++, valpnt++ )
204 {
205 c = *rowpnt;
206 val = *valpnt;
207
208 if( c == col )
209 continue;
210
211 if( val > 0.0 )
212 {
213 ub = SCIPmatrixGetColUb(matrix, c);
215
216 maxactivity += val * ub;
217 }
218 else if( val < 0.0 )
219 {
220 lb = SCIPmatrixGetColLb(matrix, c);
221 assert(!SCIPisInfinity(scip, -lb));
222
223 maxactivity += val * lb;
224 }
225 }
226
227 return maxactivity;
228}
229
230/** calculate minimal activity of one row without one specific column */
231static
233 SCIP* scip, /**< SCIP main data structure */
234 SCIP_MATRIX* matrix, /**< matrix containing the constraints */
235 int row, /**< row index */
236 int col /**< column index */
237 )
238{
239 SCIP_Real* valpnt;
240 int* rowpnt;
241 int* rowend;
242 SCIP_Real minactivity;
243 SCIP_Real val;
244 SCIP_Real lb;
245 SCIP_Real ub;
246 int c;
247
248 assert(scip != NULL);
249 assert(matrix != NULL);
250
251 minactivity = 0;
252
253 rowpnt = SCIPmatrixGetRowIdxPtr(matrix, row);
254 rowend = rowpnt + SCIPmatrixGetRowNNonzs(matrix, row);
255 valpnt = SCIPmatrixGetRowValPtr(matrix, row);
256
257 for( ; (rowpnt < rowend); rowpnt++, valpnt++ )
258 {
259 c = *rowpnt;
260 val = *valpnt;
261
262 if( c == col )
263 continue;
264
265 if( val > 0.0 )
266 {
267 lb = SCIPmatrixGetColLb(matrix, c);
268 assert(!SCIPisInfinity(scip, -lb));
269
270 minactivity += val * lb;
271 }
272 else if( val < 0.0 )
273 {
274 ub = SCIPmatrixGetColUb(matrix, c);
276
277 minactivity += val * ub;
278 }
279 }
280
281 return minactivity;
282}
283
284/** get minimal and maximal residual activity without one specified column */
285static
287 SCIP* scip, /**< SCIP main data structure */
288 SCIP_MATRIX* matrix, /**< matrix containing the constraints */
289 int col, /**< column index */
290 int row, /**< row index */
291 SCIP_Real val, /**< coefficient of this variable in this row */
292 SCIP_Real* minresactivity, /**< minimum residual activity of this row */
293 SCIP_Real* maxresactivity, /**< maximum residual activity of this row */
294 SCIP_Bool* isminsettoinfinity, /**< flag indicating if minresactiviy is set to infinity */
295 SCIP_Bool* ismaxsettoinfinity /**< flag indicating if maxresactiviy is set to infinity */
296 )
297{
298 SCIP_Real lb;
299 SCIP_Real ub;
300 int nmaxactneginf;
301 int nmaxactposinf;
302 int nminactneginf;
303 int nminactposinf;
304 SCIP_Real maxactivity;
305 SCIP_Real minactivity;
306
307 assert(scip != NULL);
308 assert(matrix != NULL);
309 assert(minresactivity != NULL);
310 assert(maxresactivity != NULL);
311 assert(isminsettoinfinity != NULL);
312 assert(ismaxsettoinfinity != NULL);
313
314 lb = SCIPmatrixGetColLb(matrix, col);
315 ub = SCIPmatrixGetColUb(matrix, col);
316
317 *isminsettoinfinity = FALSE;
318 *ismaxsettoinfinity = FALSE;
319
320 nmaxactneginf = SCIPmatrixGetRowNMaxActNegInf(matrix, row);
321 nmaxactposinf = SCIPmatrixGetRowNMaxActPosInf(matrix, row);
322 nminactneginf = SCIPmatrixGetRowNMinActNegInf(matrix, row);
323 nminactposinf = SCIPmatrixGetRowNMinActPosInf(matrix, row);
324
325 maxactivity = SCIPmatrixGetRowMaxActivity(matrix, row);
326 minactivity = SCIPmatrixGetRowMinActivity(matrix, row);
327
328 if( val >= 0.0 )
329 {
330 if( SCIPisInfinity(scip, ub) )
331 {
332 assert(nmaxactposinf >= 1);
333 if( nmaxactposinf == 1 && nmaxactneginf == 0 )
334 *maxresactivity = getMaxActivitySingleRowWithoutCol(scip, matrix, row, col);
335 else
336 {
337 *maxresactivity = SCIPinfinity(scip);
338 *ismaxsettoinfinity = TRUE;
339 }
340 }
341 else
342 {
343 if( (nmaxactneginf + nmaxactposinf) > 0 )
344 {
345 *maxresactivity = SCIPinfinity(scip);
346 *ismaxsettoinfinity = TRUE;
347 }
348 else
349 *maxresactivity = maxactivity - val * ub;
350 }
351
352 if( SCIPisInfinity(scip, -lb) )
353 {
354 assert(nminactneginf >= 1);
355 if( nminactneginf == 1 && nminactposinf == 0 )
356 *minresactivity = getMinActivitySingleRowWithoutCol(scip, matrix, row, col);
357 else
358 {
359 *minresactivity = -SCIPinfinity(scip);
360 *isminsettoinfinity = TRUE;
361 }
362 }
363 else
364 {
365 if( (nminactneginf + nminactposinf) > 0 )
366 {
367 *minresactivity = -SCIPinfinity(scip);
368 *isminsettoinfinity = TRUE;
369 }
370 else
371 *minresactivity = minactivity - val * lb;
372 }
373 }
374 else
375 {
376 if( SCIPisInfinity(scip, -lb) )
377 {
378 assert(nmaxactneginf >= 1);
379 if( nmaxactneginf == 1 && nmaxactposinf == 0 )
380 *maxresactivity = getMaxActivitySingleRowWithoutCol(scip, matrix, row, col);
381 else
382 {
383 *maxresactivity = SCIPinfinity(scip);
384 *ismaxsettoinfinity = TRUE;
385 }
386 }
387 else
388 {
389 if( (nmaxactneginf + nmaxactposinf) > 0 )
390 {
391 *maxresactivity = SCIPinfinity(scip);
392 *ismaxsettoinfinity = TRUE;
393 }
394 else
395 *maxresactivity = maxactivity - val * lb;
396 }
397
398 if( SCIPisInfinity(scip, ub) )
399 {
400 assert(nminactposinf >= 1);
401 if( nminactposinf == 1 && nminactneginf == 0 )
402 *minresactivity = getMinActivitySingleRowWithoutCol(scip, matrix, row, col);
403 else
404 {
405 *minresactivity = -SCIPinfinity(scip);
406 *isminsettoinfinity = TRUE;
407 }
408 }
409 else
410 {
411 if( (nminactneginf + nminactposinf) > 0 )
412 {
413 *minresactivity = -SCIPinfinity(scip);
414 *isminsettoinfinity = TRUE;
415 }
416 else
417 *minresactivity = minactivity - val * ub;
418 }
419 }
420}
421
422/** calculate the upper and lower bound of one variable from one row */
423static
425 SCIP* scip, /**< SCIP main data structure */
426 SCIP_MATRIX* matrix, /**< matrix containing the constraints */
427 int col, /**< column index of variable */
428 int row, /**< row index */
429 SCIP_Real val, /**< coefficient of this column in this row */
430 SCIP_Real* rowub, /**< upper bound of row */
431 SCIP_Bool* ubfound, /**< flag indicating that an upper bound was calculated */
432 SCIP_Real* rowlb, /**< lower bound of row */
433 SCIP_Bool* lbfound /**< flag indicating that a lower bound was caluclated */
434 )
435{
436 SCIP_Bool isminsettoinfinity;
437 SCIP_Bool ismaxsettoinfinity;
438 SCIP_Real minresactivity;
439 SCIP_Real maxresactivity;
440 SCIP_Real lhs;
441 SCIP_Real rhs;
442
443 assert(rowub != NULL);
444 assert(ubfound != NULL);
445 assert(rowlb != NULL);
446 assert(lbfound != NULL);
447
448 *rowub = SCIPinfinity(scip);
449 *ubfound = FALSE;
450 *rowlb = -SCIPinfinity(scip);
451 *lbfound = FALSE;
452
453 getMinMaxActivityResiduals(scip, matrix, col, row, val,
454 &minresactivity, &maxresactivity,
455 &isminsettoinfinity, &ismaxsettoinfinity);
456
457 lhs = SCIPmatrixGetRowLhs(matrix, row);
458 rhs = SCIPmatrixGetRowRhs(matrix, row);
459
460 if( val > 0.0 )
461 {
462 if( !isminsettoinfinity && !SCIPisInfinity(scip, rhs) )
463 {
464 *rowub = (rhs - minresactivity) / val;
465 *ubfound = TRUE;
466 }
467
468 if( !ismaxsettoinfinity && !SCIPisInfinity(scip, -lhs) )
469 {
470 *rowlb = (lhs - maxresactivity) / val;
471 *lbfound = TRUE;
472 }
473 }
474 else
475 {
476 if( !ismaxsettoinfinity && !SCIPisInfinity(scip, -lhs) )
477 {
478 *rowub = (lhs - maxresactivity) / val;
479 *ubfound = TRUE;
480 }
481
482 if( !isminsettoinfinity && !SCIPisInfinity(scip, rhs) )
483 {
484 *rowlb = (rhs - minresactivity) / val;
485 *lbfound = TRUE;
486 }
487 }
488}
489
490/** detect implied variable bounds */
491static
493 SCIP* scip, /**< SCIP main data structure */
494 SCIP_MATRIX* matrix, /**< matrix containing the constraints */
495 int col, /**< column index for implied free test */
496 SCIP_Bool* ubimplied, /**< flag indicating an implied upper bound */
497 SCIP_Bool* lbimplied /**< flag indicating an implied lower bound */
498 )
499{
500 SCIP_Real* valpnt;
501 int* colpnt;
502 int* colend;
503 SCIP_Real impliedub;
504 SCIP_Real impliedlb;
505 SCIP_Real ub;
506 SCIP_Real lb;
507
508 assert(scip != NULL);
509 assert(matrix != NULL);
510 assert(ubimplied != NULL);
511 assert(lbimplied != NULL);
512
513 *ubimplied = FALSE;
514 impliedub = SCIPinfinity(scip);
515
516 *lbimplied = FALSE;
517 impliedlb = -SCIPinfinity(scip);
518
519 ub = SCIPmatrixGetColUb(matrix, col);
520 lb = SCIPmatrixGetColLb(matrix, col);
521
522 colpnt = SCIPmatrixGetColIdxPtr(matrix, col);
523 colend = colpnt + SCIPmatrixGetColNNonzs(matrix, col);
524 valpnt = SCIPmatrixGetColValPtr(matrix, col);
525 for( ; (colpnt < colend); colpnt++, valpnt++ )
526 {
527 SCIP_Real rowub;
528 SCIP_Bool ubfound;
529 SCIP_Real rowlb;
530 SCIP_Bool lbfound;
531
532 getVarBoundsOfRow(scip, matrix, col, *colpnt, *valpnt, &rowub, &ubfound, &rowlb, &lbfound);
533
534 if( ubfound && (rowub < impliedub) )
535 impliedub = rowub;
536
537 if( lbfound && (rowlb > impliedlb) )
538 impliedlb = rowlb;
539 }
540
541 /* we consider +/-inf bounds as implied bounds */
542 if( SCIPisInfinity(scip, ub) ||
543 (!SCIPisInfinity(scip, ub) && SCIPisLE(scip, impliedub, ub)) )
544 *ubimplied = TRUE;
545
546 if( SCIPisInfinity(scip, -lb) ||
547 (!SCIPisInfinity(scip, -lb) && SCIPisGE(scip, impliedlb, lb)) )
548 *lbimplied = TRUE;
549}
550
551/** y = weight1 * var[colidx1] + var[colidx2] */
552static
554 SCIP* scip, /**< SCIP datastructure */
555 SCIP_MATRIX* matrix, /**< matrix datastructure */
556 SCIP_PRESOLDATA* presoldata, /**< presolver data */
557 SCIP_VAR** vars, /**< the current variables */
558 int colidx1, /**< one of the indexes of column to try nonzero cancellation for */
559 int colidx2, /**< one of the indexes of column to try nonzero cancellation for */
560 SCIP_Bool isimpliedfree, /**< is the aggregated variable implied free? */
561 SCIP_Real weight1 /**< weight variable one in the aggregated expression */
562 )
563{
564 SCIP_VAR* tmpvars[2];
565 SCIP_Real coefs[2];
566 char newvarname[SCIP_MAXSTRLEN];
567 char newconsname[SCIP_MAXSTRLEN];
568 SCIP_CONS* newcons;
569 SCIP_VAR* aggregatedvar;
570 SCIP_VAR* newvar;
571 SCIP_VARTYPE newvartype;
572 SCIP_IMPLINTTYPE newvarimpltype;
573 SCIP_Real constant;
574 SCIP_Real newlb;
575 SCIP_Real newub;
576 SCIP_Real lhs;
577 SCIP_Real rhs;
578 SCIP_Bool infeasible;
579 SCIP_Bool aggregated;
580#ifndef NDEBUG
581 if( isimpliedfree )
582 {
583 SCIP_Bool lbimplied;
584 SCIP_Bool ubimplied;
585
586 getImpliedBounds(scip, matrix, colidx2, &ubimplied, &lbimplied);
587 assert(lbimplied && ubimplied);
588 }
589#endif
590
591 assert( !SCIPisSumZero(scip, weight1) );
592 assert( !SCIPisSumZero(scip, 1.0 / weight1) );
593
594 presoldata->naggregated += 1;
595 aggregatedvar = vars[colidx2];
596
597 /* if the variable is implied free, we make sure that the columns bounds are removed,
598 * so that subsequent checks for implied bounds do not interfere with the exploitation
599 * of this variables implied bounds
600 */
601 if( isimpliedfree )
602 {
603 SCIPdebugMsg(scip, "remove column bounds of column %d\n", colidx2);
604 SCIPmatrixRemoveColumnBounds(scip, matrix, colidx2);
605 }
606
607 assert(!SCIPdoNotMultaggrVar(scip, aggregatedvar));
608
609 (void) SCIPsnprintf(newvarname, SCIP_MAXSTRLEN, "dualsparsifyvar_%d", presoldata->naggregated);
610
611 constant = 0.0;
612
613 if( weight1 > 0.0 )
614 {
615 if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(vars[colidx1])) ||
617 newlb = -SCIPinfinity(scip);
618 else
619 newlb = weight1 * SCIPvarGetLbGlobal(vars[colidx1]) + SCIPvarGetLbGlobal(vars[colidx2]);
620
621 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(vars[colidx1])) ||
623 newub = SCIPinfinity(scip);
624 else
625 newub = weight1 * SCIPvarGetUbGlobal(vars[colidx1]) + SCIPvarGetUbGlobal(vars[colidx2]);
626 }
627 else
628 {
629 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(vars[colidx1])) ||
631 newlb = -SCIPinfinity(scip);
632 else
633 newlb = weight1 * SCIPvarGetUbGlobal(vars[colidx1]) + SCIPvarGetLbGlobal(vars[colidx2]);
634
635 if( SCIPisInfinity(scip, SCIPvarGetLbGlobal(vars[colidx1])) ||
637 newub = SCIPinfinity(scip);
638 else
639 newub = weight1 * SCIPvarGetLbGlobal(vars[colidx1]) + SCIPvarGetUbGlobal(vars[colidx2]);
640 }
641
642 newvartype = SCIPvarIsIntegral(aggregatedvar) ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS;
643 newvarimpltype = SCIPvarIsImpliedIntegral(aggregatedvar) ? SCIP_IMPLINTTYPE_WEAK : SCIP_IMPLINTTYPE_NONE;
644
645 lhs = SCIPvarGetLbGlobal(vars[colidx2]);
646 rhs = SCIPvarGetUbGlobal(vars[colidx2]);
647
648 SCIP_CALL( SCIPcreateVarImpl(scip, &newvar, newvarname, newlb, newub, 0.0, newvartype, newvarimpltype,
649 SCIPvarIsInitial(aggregatedvar), SCIPvarIsRemovable(aggregatedvar), NULL, NULL, NULL, NULL, NULL) );
650 SCIP_CALL( SCIPaddVar(scip, newvar) );
651
652 /* set the debug solution value for the new variable */
653#ifdef WITH_DEBUG_SOLUTION
654 if( SCIPdebugIsMainscip(scip) )
655 {
656 SCIP_Real val1;
657 SCIP_Real val2;
658
659 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[colidx1], &val1) );
660 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[colidx2], &val2) );
661 SCIP_CALL( SCIPdebugAddSolVal(scip, newvar, weight1 * val1 + val2) );
662
663 SCIPdebugMsg(scip, "set debug solution value of %s to %g\n", SCIPvarGetName(newvar), weight1 * val1 + val2);
664 }
665#endif
666
667 tmpvars[0] = vars[colidx1];
668 tmpvars[1] = newvar;
669 coefs[0] = -weight1;
670 coefs[1] = 1.0;
671
672 SCIP_CALL( SCIPmultiaggregateVar(scip, aggregatedvar, 2, tmpvars, coefs, constant, &infeasible, &aggregated) );
673
674 assert(!infeasible);
675 assert(aggregated);
676
677 vars[colidx2] = newvar;
678
679 /* create a linear constraint that ensures that var[colidx2].lb <= y - weight1 * var[colidx1] <= var[colidx2].ub;
680 * note that it might happen that vars[colidx2] is not implied free even though it has infinite bounds because
681 * getImpliedBounds() considers infinite bounds to be implied
682 */
683 if( !isimpliedfree && (!SCIPisInfinity(scip, rhs) || !SCIPisInfinity(scip, -lhs)) )
684 {
685 SCIPdebugMsg(scip, "create a linear constraint to ensure %g <= %g %s + %g %s <= %g\n", lhs, coefs[0], SCIPvarGetName(tmpvars[0]),
686 coefs[1], SCIPvarGetName(tmpvars[1]), rhs);
687 (void) SCIPsnprintf(newconsname, SCIP_MAXSTRLEN, "dualsparsifycons_%d", presoldata->naggregated);
688
689 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, newconsname, 2, tmpvars, coefs,
690 lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
691 SCIP_CALL( SCIPaddCons(scip, newcons) );
692
693 SCIPdebugPrintCons(scip, newcons, NULL);
694
695 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
696 }
697
698 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
699
700 return SCIP_OKAY;
701}
702
703/** try nonzero cancellation for given column */
704static
706 SCIP* scip, /**< SCIP datastructure */
707 SCIP_MATRIX* matrix, /**< the constraint matrix */
708 SCIP_PRESOLDATA* presoldata, /**< presolver data */
709 SCIP_HASHTABLE* pairtable, /**< the hashtable containing COLCONSPAIR's of equations */
710 SCIP_Bool* ishashingcols, /**< array to indicates whether it is impliedfree or not */
711 SCIP_VAR** vars, /**< array to store the current variables */
712 SCIP_Bool* isblockedvar, /**< array to indicates whether it is blocked or not */
713 int colidx, /**< index of column to try nonzero cancellation for */
714 int maxcontfillin, /**< maximal fill-in allowed for continuous variables */
715 int maxintfillin, /**< maximal fill-in allowed for integral variables */
716 int maxbinfillin, /**< maximal fill-in allowed for binary variables */
717 int maxconsiderednonzeros, /**< maximal number of nonzeros to consider for cancellation */
718 SCIP_Bool preserveintcoefs, /**< only perform nonzero cancellation if integrality of coefficients is preserved? */
719 SCIP_Longint* nuseless, /**< pointer to update number of useless hashtable retrieves */
720 int* nchgcoefs, /**< pointer to update number of changed coefficients */
721 int* ncanceled, /**< pointer to update number of canceled nonzeros */
722 int* nfillin, /**< pointer to update the produced fill-in */
723 SCIP_Bool isaddedcons /**< whether a linear constraint required to added to keep the validity */
724 )
725{
726 SCIP_VAR* cancelvar;
727 SCIP_Real* cancelcolvals;
728 SCIP_Real* colvalptr;
729 SCIP_Real* tmpvals;
730 SCIP_Real* scores;
731 int* cancelcolinds;
732 int* colidxptr;
733 int* tmpinds;
734 SCIP_Real bestcancelrate;
735 SCIP_Real bestscale;
736 SCIP_Real ncols;
737 SCIP_Bool colishashing;
738 SCIP_Bool swapped = FALSE;
739 int cancelcollen;
740 int bestnfillin;
741 int nretrieves;
742 int maxfillin;
743 int bestcand;
744 int nchgcoef;
745
746 ncols = SCIPmatrixGetNColumns(matrix);
747 colishashing = ishashingcols[colidx];
748 cancelcollen = SCIPmatrixGetColNNonzs(matrix, colidx);
749 colidxptr = SCIPmatrixGetColIdxPtr(matrix, colidx);
750 colvalptr = SCIPmatrixGetColValPtr(matrix, colidx);
751 cancelvar = vars[colidx];
752
753 if( SCIPvarIsIntegral(cancelvar) )
754 {
755 if( SCIPvarIsBinary(cancelvar) )
756 maxfillin = maxbinfillin;
757 else
758 maxfillin = maxintfillin;
759 }
760 else
761 maxfillin = maxcontfillin;
762
763 SCIP_CALL( SCIPduplicateBufferArray(scip, &cancelcolinds, colidxptr, cancelcollen) );
764 SCIP_CALL( SCIPduplicateBufferArray(scip, &cancelcolvals, colvalptr, cancelcollen) );
765 SCIP_CALL( SCIPallocBufferArray(scip, &tmpinds, cancelcollen) );
766 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvals, cancelcollen) );
767 SCIP_CALL( SCIPallocBufferArray(scip, &scores, cancelcollen) );
768
769 nchgcoef = 0;
770 nretrieves = 0;
771 while( TRUE ) /*lint !e716 */
772 {
773 COLCONSPAIR colconspair;
774 int maxlen;
775 int i;
776 int j;
777
778 bestcand = -1;
779 bestnfillin = 0;
780 bestscale = 1.0;
781 bestcancelrate = 0.0;
782
783 /* sort the rows non-decreasingly by number of nonzeros
784 * if the number of nonzeros, we use the colindex as tie-breaker
785 */
786 for( i = 0; i < cancelcollen; ++i )
787 {
788 tmpinds[i] = i;
789 scores[i] = -SCIPmatrixGetRowNNonzs(matrix, cancelcolinds[i]) - 1.0 * cancelcolinds[i] / (ncols);
790 }
791 SCIPsortRealInt(scores, tmpinds, cancelcollen);
792
793 maxlen = cancelcollen;
794 if( maxconsiderednonzeros >= 0 )
795 maxlen = MIN(cancelcollen, maxconsiderednonzeros);
796
797 for( i = 0; i < maxlen; ++i )
798 {
799 for( j = i + 1; j < maxlen; ++j )
800 {
801 COLCONSPAIR* hashingcolconspair;
802 SCIP_VAR* hashingcolvar;
803 SCIP_Real* hashingcolvals;
804 int* hashingcolinds;
805 SCIP_Real cancelrate;
806 SCIP_Real rowlhs;
807 SCIP_Real rowrhs;
808 SCIP_Real scale;
809 SCIP_Bool hashingcolisbin;
810 SCIP_Bool abortpair;
811 int hashingcollen;
812 int ntotfillin;
813 int ncancel;
814 int a,b;
815 int i1,i2;
816
817 i1 = tmpinds[i];
818 i2 = tmpinds[j];
819
820 assert(cancelcolinds[i] < cancelcolinds[j]);
821
822 if( cancelcolinds[i1] < cancelcolinds[i2] )
823 {
824 colconspair.consindex1 = cancelcolinds[i1];
825 colconspair.consindex2 = cancelcolinds[i2];
826 colconspair.conscoef1 = cancelcolvals[i1];
827 colconspair.conscoef2 = cancelcolvals[i2];
828 }
829 else
830 {
831 colconspair.consindex1 = cancelcolinds[i2];
832 colconspair.consindex2 = cancelcolinds[i1];
833 colconspair.conscoef1 = cancelcolvals[i2];
834 colconspair.conscoef2 = cancelcolvals[i1];
835 }
836
837 hashingcolconspair = (COLCONSPAIR*)SCIPhashtableRetrieve(pairtable, (void*) &colconspair);
838 nretrieves++;
839
840 if( hashingcolconspair == NULL ||
841 hashingcolconspair->colindex == colidx || isblockedvar[hashingcolconspair->colindex] )
842 continue;
843
844 /* if the column we want to cancel is a hashing column (which we stored for canceling other columns),
845 * we will only use the hashing columns for canceling with less nonzeros and if the number of nonzeros
846 * is equal we use the colindex as tie-breaker to avoid cyclic nonzero cancellation
847 */
848 hashingcollen = SCIPmatrixGetColNNonzs(matrix, hashingcolconspair->colindex);
849 if( colishashing && (cancelcollen < hashingcollen ||
850 (cancelcollen == hashingcollen && colidx < hashingcolconspair->colindex)) )
851 continue;
852
853 hashingcolvals = SCIPmatrixGetColValPtr(matrix, hashingcolconspair->colindex);
854 hashingcolinds = SCIPmatrixGetColIdxPtr(matrix, hashingcolconspair->colindex);
855 hashingcolvar = vars[hashingcolconspair->colindex];
856 hashingcolisbin = SCIPvarIsBinary(hashingcolvar);
857
858 /* @todo do more reduction if knapsack constraint handler supports downgrading constraint,
859 * i.e., converting into a linear constraint
860 */
861 if( hashingcolisbin )
862 continue;
863
864 scale = -colconspair.conscoef1 / hashingcolconspair->conscoef1;
865 assert(scale != 0.0); /*lint !e777*/
866
867 if( REALABS(scale) > MAXSCALE )
868 continue;
869
870 if( !SCIPisVarAggrCoefAcceptable(scip, hashingcolvar, scale) )
871 continue;
872
873 if( SCIPvarIsIntegral(hashingcolvar) )
874 {
875 if( SCIPvarIsIntegral(cancelvar) )
876 {
877 /* skip if the hashing variable is an integer variable and
878 * the canceled variable is an implicit integer variable
879 */
880 if( !SCIPvarIsImpliedIntegral(hashingcolvar) && SCIPvarIsImpliedIntegral(cancelvar) )
881 continue;
882
883 /* skip if the scale is non-integral */
884 if( !SCIPisIntegral(scip, scale) )
885 continue;
886
887 /* round scale to be exactly integral */
888 scale = floor(scale + 0.5);
889 }
890 /* skip if the canceled variable is a continuous variable */
891 else
892 continue;
893 }
894
895 a = 0;
896 b = 0;
897 ncancel = 0;
898 ntotfillin = 0;
899 abortpair = FALSE;
900
901 while( a < cancelcollen && b < hashingcollen )
902 {
903 if( cancelcolinds[a] == hashingcolinds[b] )
904 {
905 SCIP_Real newcoef;
906
907 newcoef = cancelcolvals[a] + scale * hashingcolvals[b];
908
909 /* check if coefficient is canceled */
910 if( SCIPisZero(scip, newcoef) )
911 {
912 ++ncancel;
913 }
914 /* otherwise, check if integral coefficients are preserved if the column is integral */
915 else if( (preserveintcoefs && SCIPvarIsIntegral(cancelvar) &&
916 SCIPisIntegral(scip, cancelcolvals[a]) && !SCIPisIntegral(scip, newcoef)) )
917 {
918 abortpair = TRUE;
919 break;
920 }
921 /* finally, check if locks could be modified in a bad way due to flipped signs */
922 else if( COPYSIGN(1.0, newcoef) != COPYSIGN(1.0, cancelcolvals[a]) ) /*lint !e777*/
923 {
924 /* do not flip signs for non-canceled coefficients if this adds a lock to a variable that
925 * had at most one lock in that direction before, except if the other direction gets unlocked
926 */
927 rowrhs = SCIPmatrixGetRowRhs(matrix, cancelcolinds[a]);
928 rowlhs = SCIPmatrixGetRowLhs(matrix, cancelcolinds[a]);
929 if( (cancelcolvals[a] > 0.0 && ! SCIPisInfinity(scip, rowrhs)) ||
930 (cancelcolvals[a] < 0.0 && ! SCIPisInfinity(scip, -rowlhs)) )
931 {
932 /* if we get into this case the variable had a positive coefficient in a <= constraint or
933 * a negative coefficient in a >= constraint, e.g. an uplock. If this was the only uplock
934 * we do not abort their cancelling, otherwise we abort if we had a single or no downlock
935 * and add one
936 */
937 if( presoldata->preservegoodlocks && (SCIPmatrixGetColNUplocks(matrix, colidx) > 1 &&
938 SCIPmatrixGetColNDownlocks(matrix, colidx) <= 1) )
939 {
940 abortpair = TRUE;
941 break;
942 }
943 }
944
945 if( (cancelcolvals[a] < 0.0 && ! SCIPisInfinity(scip, rowrhs)) ||
946 (cancelcolvals[a] > 0.0 && ! SCIPisInfinity(scip, -rowlhs)) )
947 {
948 /* symmetric case where the variable had a downlock */
949 if( presoldata->preservegoodlocks && (SCIPmatrixGetColNDownlocks(matrix, colidx) > 1 &&
950 SCIPmatrixGetColNUplocks(matrix, colidx) <= 1) )
951 {
952 abortpair = TRUE;
953 break;
954 }
955 }
956 }
957
958 ++a;
959 ++b;
960 }
961 else if( cancelcolinds[a] < hashingcolinds[b] )
962 {
963 ++a;
964 }
965 else
966 {
967 SCIP_Real newcoef;
968
969 newcoef = scale * hashingcolvals[b];
970 rowrhs = SCIPmatrixGetRowRhs(matrix, hashingcolinds[b]);
971 rowlhs = SCIPmatrixGetRowLhs(matrix, hashingcolinds[b]);
972
973 if( (newcoef > 0.0 && ! SCIPisInfinity(scip, rowrhs)) ||
974 (newcoef < 0.0 && ! SCIPisInfinity(scip, -rowlhs)) )
975 {
976 if( presoldata->preservegoodlocks && SCIPmatrixGetColNUplocks(matrix, colidx) <= 1 )
977 {
978 abortpair = TRUE;
979 ++b;
980 break;
981 }
982 }
983
984 if( (newcoef < 0.0 && ! SCIPisInfinity(scip, rowrhs)) ||
985 (newcoef > 0.0 && ! SCIPisInfinity(scip, -rowlhs)) )
986 {
987 if( presoldata->preservegoodlocks && SCIPmatrixGetColNDownlocks(matrix, colidx) <= 1 )
988 {
989 abortpair = TRUE;
990 ++b;
991 break;
992 }
993 }
994
995 ++b;
996
997 if( ++ntotfillin > maxfillin )
998 {
999 abortpair = TRUE;
1000 break;
1001 }
1002 }
1003 }
1004
1005 if( abortpair )
1006 continue;
1007
1008 while( b < hashingcollen )
1009 {
1010 ++b;
1011
1012 if( ++ntotfillin > maxfillin )
1013 break;
1014 }
1015CHECKFILLINAGAIN:
1016 if( ntotfillin > maxfillin || ntotfillin >= ncancel )
1017 continue;
1018
1019 cancelrate = (ncancel - ntotfillin) / (SCIP_Real) cancelcollen;
1020
1021 /* if a linear constraint is needed to keep the validity, we require a large nonzero cancellation */
1022 if( isaddedcons && (ncancel - ntotfillin < presoldata->mineliminatednonzeros) )
1023 continue;
1024
1025 if( cancelrate > bestcancelrate )
1026 {
1027 if( ishashingcols[hashingcolconspair->colindex] )
1028 {
1029 SCIP_Bool lbimplied;
1030 SCIP_Bool ubimplied;
1031
1032 /* recompute whether a variable is still implied free; after some previous multi-aggregations of
1033 * some variables, it might be that other variables that are contained in the same linear rows of the
1034 * matrix are not implied free anymore (see #2971)
1035 */
1036 getImpliedBounds(scip, matrix, hashingcolconspair->colindex, &ubimplied, &lbimplied);
1037
1038 if( !lbimplied || !ubimplied )
1039 {
1040 ishashingcols[hashingcolconspair->colindex] = FALSE;
1041 ntotfillin += 2;
1042 goto CHECKFILLINAGAIN;
1043 }
1044 }
1045
1046 bestnfillin = ntotfillin;
1047 bestcand = hashingcolconspair->colindex;
1048 bestscale = scale;
1049 bestcancelrate = cancelrate;
1050
1051 /* stop looking if the current candidate does not create any fill-in or alter coefficients */
1052 if( cancelrate == 1.0 )
1053 break;
1054 }
1055
1056 /* we accept the best candidate immediately if it does not create any fill-in or alter coefficients */
1057 if( bestcand != -1 && bestcancelrate == 1.0 )
1058 break;
1059 }
1060 }
1061
1062 if( bestcand != -1 )
1063 {
1064 SCIP_Real* hashingcolvals;
1065 int* hashingcolinds;
1066 int hashingcollen;
1067 int tmpcollen;
1068 int a;
1069 int b;
1070
1071 SCIPdebugMsg(scip, "cancelcol %d (%s) candidate column %d (%s) (bestcancelrate = %g, bestscale = %g)\n",
1072 colidx, SCIPvarGetName(cancelvar), bestcand, SCIPvarGetName(vars[bestcand]), bestcancelrate, bestscale);
1073
1074 hashingcolvals = SCIPmatrixGetColValPtr(matrix, bestcand);
1075 hashingcolinds = SCIPmatrixGetColIdxPtr(matrix, bestcand);
1076 hashingcollen = SCIPmatrixGetColNNonzs(matrix, bestcand);
1077
1078 a = 0;
1079 b = 0;
1080 tmpcollen = 0;
1081
1082 while( a < cancelcollen && b < hashingcollen )
1083 {
1084 if( cancelcolinds[a] == hashingcolinds[b] )
1085 {
1086 SCIP_Real val = cancelcolvals[a] + bestscale * hashingcolvals[b];
1087
1088 if( !SCIPisZero(scip, val) )
1089 {
1090 tmpinds[tmpcollen] = cancelcolinds[a];
1091 tmpvals[tmpcollen] = val;
1092 ++tmpcollen;
1093 }
1094 ++nchgcoef;
1095
1096 ++a;
1097 ++b;
1098 }
1099 else if( cancelcolinds[a] < hashingcolinds[b] )
1100 {
1101 tmpinds[tmpcollen] = cancelcolinds[a];
1102 tmpvals[tmpcollen] = cancelcolvals[a];
1103 ++tmpcollen;
1104 ++a;
1105 }
1106 else
1107 {
1108 tmpinds[tmpcollen] = hashingcolinds[b];
1109 tmpvals[tmpcollen] = hashingcolvals[b] * bestscale;
1110 ++nchgcoef;
1111 ++tmpcollen;
1112 ++b;
1113 }
1114 }
1115
1116 while( a < cancelcollen )
1117 {
1118 tmpinds[tmpcollen] = cancelcolinds[a];
1119 tmpvals[tmpcollen] = cancelcolvals[a];
1120 ++tmpcollen;
1121 ++a;
1122 }
1123
1124 while( b < hashingcollen )
1125 {
1126 tmpinds[tmpcollen] = hashingcolinds[b];
1127 tmpvals[tmpcollen] = hashingcolvals[b] * bestscale;
1128 ++nchgcoef;
1129 ++tmpcollen;
1130 ++b;
1131 }
1132
1133 /* update fill-in counter */
1134 *nfillin += bestnfillin;
1135
1136 /* swap the temporary arrays so that the cancelcolinds and cancelcolvals arrays, contain the new
1137 * changed column, and the tmpinds and tmpvals arrays can be overwritten in the next iteration
1138 */
1139 SCIPswapPointers((void**) &tmpinds, (void**) &cancelcolinds);
1140 SCIPswapPointers((void**) &tmpvals, (void**) &cancelcolvals);
1141 swapped = ! swapped;
1142 cancelcollen = tmpcollen;
1143 SCIP_CALL( aggregation(scip, matrix, presoldata, vars, colidx, bestcand, ishashingcols[bestcand], -bestscale) );
1144
1145 /* the newly created variable is now at the position bestcand and is assumed to have the same coefficients.
1146 * this is not the case if the variable is not implied free since then a new constraint was added and the
1147 * nonzero fillin would not be counted correctly if we do not block this variable
1148 */
1149 if( !ishashingcols[bestcand] )
1150 isblockedvar[bestcand] = TRUE;
1151 }
1152 else
1153 break;
1154 }
1155
1156 if( nchgcoef != 0 )
1157 {
1158 /* update counters */
1159 *nchgcoefs += nchgcoef;
1160 *ncanceled += SCIPmatrixGetColNNonzs(matrix, colidx) - cancelcollen;
1161
1162 isblockedvar[colidx] = TRUE;
1163
1164 /* if successful, decrease the useless hashtable retrieves counter; the rationale here is that we want to keep
1165 * going if, after many useless calls that almost exceeded the budget, we finally reach a useful section; but we
1166 * don't allow a negative build-up for the case that the useful section is all at the beginning and we just want
1167 * to quit quickly afterwards
1168 */
1169 *nuseless -= nretrieves;
1170 *nuseless = MAX(*nuseless, 0);
1171 }
1172 else
1173 {
1174 /* if not successful, increase useless hashtable retrieves counter */
1175 *nuseless += nretrieves;
1176 }
1177
1178 SCIPfreeBufferArray(scip, &scores);
1179 if( swapped )
1180 {
1181 SCIPfreeBufferArray(scip, &cancelcolvals);
1182 SCIPfreeBufferArray(scip, &cancelcolinds);
1183 SCIPfreeBufferArray(scip, &tmpvals);
1184 SCIPfreeBufferArray(scip, &tmpinds);
1185 }
1186 else
1187 {
1188 SCIPfreeBufferArray(scip, &tmpvals);
1189 SCIPfreeBufferArray(scip, &tmpinds);
1190 SCIPfreeBufferArray(scip, &cancelcolvals);
1191 SCIPfreeBufferArray(scip, &cancelcolinds);
1192 }
1193
1194 return SCIP_OKAY;
1195}
1196
1197/** updates failure counter after one execution */
1198static
1200 SCIP_PRESOLDATA* presoldata, /**< presolver data */
1201 SCIP_Bool success /**< was this execution successful? */
1202 )
1203{
1204 assert(presoldata != NULL);
1205
1206 if( success )
1207 {
1208 presoldata->nfailures = 0;
1209 presoldata->nwaitingcalls = 0;
1210 }
1211 else
1212 {
1213 presoldata->nfailures++;
1214 presoldata->nwaitingcalls = (int)(presoldata->waitingfac*(SCIP_Real)presoldata->nfailures);
1215 }
1216}
1217
1218/*
1219 * Callback methods of presolver
1220 */
1221
1222/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1223static
1224SCIP_DECL_PRESOLCOPY(presolCopyDualsparsify)
1225{
1226 SCIP_PRESOLDATA* presoldata;
1227
1228 assert(scip != NULL);
1229 assert(presol != NULL);
1230
1232
1233 /* call inclusion method of presolver if copying is enabled */
1234 presoldata = SCIPpresolGetData(presol);
1235 assert(presoldata != NULL);
1236 if( presoldata->enablecopy )
1237 {
1239 }
1240
1241 return SCIP_OKAY;
1242}
1243
1244
1245/** execution method of presolver */
1246static
1247SCIP_DECL_PRESOLEXEC(presolExecDualsparsify)
1248{ /*lint --e{715}*/
1249 SCIP_MATRIX* matrix;
1250 int* perm;
1251 int* colidxsorted;
1252 int* colsparsity;
1253 SCIP_Real* scores;
1254 COLCONSPAIR* conspairs;
1255 SCIP_HASHTABLE* pairtable;
1256 SCIP_PRESOLDATA* presoldata;
1257 SCIP_Bool* ishashingcols;
1258 SCIP_Bool* isblockedvar;
1259 SCIP_VAR** vars;
1260 SCIP_Longint maxuseless;
1261 SCIP_Longint nuseless;
1262 SCIP_Bool initialized;
1263 SCIP_Bool complete;
1264 SCIP_Bool infeasible;
1265 int ncols;
1266 int c;
1267 int i;
1268 int j;
1269 int conspairssize;
1270 int nconspairs;
1271 int numcancel;
1272 int nfillin;
1273
1274 assert(result != NULL);
1275
1277
1278 if( SCIPdoNotAggr(scip) )
1279 return SCIP_OKAY;
1280
1281 /* If restart is performed, some cuts will be tranformed into linear constraints.
1282 * However, SCIPmatrixCreate() only collects the original constraints (not the constraints transformed from cuts)
1283 * For this reason, we only perform this method in the first run of branch-and-cut.
1284 * */
1285 if( SCIPgetNRuns(scip) > 1 )
1286 return SCIP_OKAY;
1287
1288 presoldata = SCIPpresolGetData(presol);
1289
1290 if( presoldata->nwaitingcalls > 0 )
1291 {
1292 presoldata->nwaitingcalls--;
1293 SCIPdebugMsg(scip, "skipping dualsparsify: nfailures=%d, nwaitingcalls=%d\n", presoldata->nfailures,
1294 presoldata->nwaitingcalls);
1295 return SCIP_OKAY;
1296 }
1297
1298 SCIPdebugMsg(scip, "starting dualsparsify. . .\n");
1300
1301 matrix = NULL;
1302 SCIP_CALL( SCIPmatrixCreate(scip, &matrix, TRUE, &initialized, &complete, &infeasible,
1303 naddconss, ndelconss, nchgcoefs, nchgbds, nfixedvars) );
1304
1305 /* if infeasibility was detected during matrix creation or
1306 * matrix creation is incomplete, return here.
1307 */
1308 if( infeasible || !complete )
1309 {
1310 if( initialized )
1311 SCIPmatrixFree(scip, &matrix);
1312
1313 if( infeasible )
1315
1316 return SCIP_OKAY;
1317 }
1318
1319 if( !initialized )
1320 return SCIP_OKAY;
1321
1322 ncols = SCIPmatrixGetNColumns(matrix);
1323
1324 /* sort columns by row indices */
1325 for( i = 0; i < ncols; i++ )
1326 {
1327 int* colpnt = SCIPmatrixGetColIdxPtr(matrix, i);
1328 SCIP_Real* valpnt = SCIPmatrixGetColValPtr(matrix, i);
1329 SCIPsortIntReal(colpnt, valpnt, SCIPmatrixGetColNNonzs(matrix, i));
1330 }
1331
1334 SCIP_CALL( SCIPallocBufferArray(scip, &ishashingcols, SCIPmatrixGetNColumns(matrix)) );
1336 SCIP_CALL( SCIPallocBufferArray(scip, &isblockedvar, SCIPmatrixGetNColumns(matrix)) );
1337
1338 /* loop over all columns and create cons pairs */
1339 conspairssize = 0;
1340 nconspairs = 0;
1341 conspairs = NULL;
1343 SCIPhashGetKeyStandard, consPairsEqual, consPairHashval, (void*) scip) );
1344
1345 /* collect implied free variables and their number of nonzeros */
1346 for( c = 0; c < ncols; c++ )
1347 {
1348 SCIP_Bool lbimplied;
1349 SCIP_Bool ubimplied;
1350 int nnonz;
1351
1352 vars[c] = SCIPmatrixGetVar(matrix, c);
1353
1354 /* if the locks do not match do not consider the column for sparsification */
1355 if( SCIPmatrixDownlockConflict(matrix, c) || SCIPmatrixUplockConflict(matrix, c) )
1356 {
1357 isblockedvar[c] = TRUE;
1358 ishashingcols[c] = FALSE;
1359 continue;
1360 }
1361
1362 /* skip if the variable is not allowed to be multi-aggregated */
1364 {
1365 isblockedvar[c] = TRUE;
1366 ishashingcols[c] = FALSE;
1367 continue;
1368 }
1369
1370 nnonz = SCIPmatrixGetColNNonzs(matrix, c);
1371
1372 getImpliedBounds(scip, matrix, c, &ubimplied, &lbimplied);
1373
1374 ishashingcols[c] = FALSE;
1375
1376 if( lbimplied && ubimplied )
1377 ishashingcols[c] = TRUE;
1378
1379 isblockedvar[c] = FALSE;
1380
1381 /* only consider implied free variables
1382 * skip singleton variables, because either the constraint is redundant
1383 * or the variables can be canceled by variable substitution
1384 */
1385 if( nnonz >= 2 && (lbimplied && ubimplied) )
1386 {
1387 SCIP_Real* colvals;
1388 int* colinds;
1389 int failshift;
1390 int npairs;
1391
1392 colinds = SCIPmatrixGetColIdxPtr(matrix, c);
1393 colvals = SCIPmatrixGetColValPtr(matrix, c);
1394
1395 /* sort the rows non-decreasingly by number of nonzeros
1396 * if the number of nonzeros is equal, we use the colindex as tie-breaker
1397 */
1398 for( i = 0; i < nnonz; ++i )
1399 {
1400 perm[i] = i;
1401 scores[i] = -SCIPmatrixGetRowNNonzs(matrix, colinds[i]) - 1.0 *colinds[i] / ncols;
1402 }
1403 SCIPsortRealInt(scores, perm, nnonz);
1404
1405 if( presoldata->maxconsiderednonzeros >= 0 )
1406 nnonz = MIN(nnonz, presoldata->maxconsiderednonzeros);
1407
1408 npairs = (nnonz * (nnonz - 1)) / 2;
1409 if( nconspairs + npairs > conspairssize )
1410 {
1411 int newsize = SCIPcalcMemGrowSize(scip, nconspairs + npairs);
1412 SCIP_CALL( SCIPreallocBufferArray(scip, &conspairs, newsize) );
1413 conspairssize = newsize;
1414 }
1415
1416 /* if we are called after one or more failures, i.e., executions without finding cancellations, then we
1417 * shift the section of nonzeros considered; in the case that the maxconsiderednonzeros limit is hit, this
1418 * results in different constraint pairs being tried and avoids trying the same useless cancellations
1419 * repeatedly
1420 */
1421 failshift = presoldata->nfailures*presoldata->maxconsiderednonzeros;
1422
1423 for( i = 0; i < nnonz; ++i )
1424 {
1425 for( j = i + 1; j < nnonz; ++j )
1426 {
1427 int i1;
1428 int i2;
1429
1430 assert(nconspairs < conspairssize);
1431 assert(conspairs != NULL);
1432
1433 i1 = perm[(i + failshift) % nnonz];
1434 i2 = perm[(j + failshift) % nnonz];
1435 /* coverity[var_deref_op] */
1436 conspairs[nconspairs].colindex = c;
1437
1438 if( colinds[i1] < colinds[i2])
1439 {
1440 conspairs[nconspairs].consindex1 = colinds[i1];
1441 conspairs[nconspairs].consindex2 = colinds[i2];
1442 conspairs[nconspairs].conscoef1 = colvals[i1];
1443 conspairs[nconspairs].conscoef2 = colvals[i2];
1444 }
1445 else
1446 {
1447 conspairs[nconspairs].consindex1 = colinds[i2];
1448 conspairs[nconspairs].consindex2 = colinds[i1];
1449 conspairs[nconspairs].conscoef1 = colvals[i2];
1450 conspairs[nconspairs].conscoef2 = colvals[i1];
1451 }
1452 ++nconspairs;
1453 }
1454 }
1455 }
1456 }
1457
1458 /* insert conspairs into hash table */
1459 for( c = 0; c < nconspairs; ++c )
1460 {
1461 COLCONSPAIR* otherconspair;
1462 SCIP_Bool insert;
1463
1464 assert(conspairs != NULL);
1465
1466 insert = TRUE;
1467
1468 /* check if this pair is already contained in the hash table;
1469 * The loop is required due to the non-transitivity of the hash functions
1470 */
1471 while( (otherconspair = (COLCONSPAIR*)SCIPhashtableRetrieve(pairtable, (void*) &conspairs[c])) != NULL )
1472 {
1473 /* if the previous constraint pair has fewer or the same number of nonzeros in the attached column
1474 * we keep that pair and skip this one
1475 */
1476 if( SCIPmatrixGetColNNonzs(matrix, otherconspair->colindex) <=
1477 SCIPmatrixGetColNNonzs(matrix, conspairs[c].colindex) )
1478 {
1479 insert = FALSE;
1480 break;
1481 }
1482
1483 /* this pairs column has fewer nonzeros, so remove the other pair from the hash table and loop */
1484 SCIP_CALL( SCIPhashtableRemove(pairtable, (void*) otherconspair) );
1485 }
1486
1487 if( insert )
1488 {
1489 SCIP_CALL( SCIPhashtableInsert(pairtable, (void*) &conspairs[c]) );
1490 }
1491 }
1492
1493 /* sort cols according to decreasing sparsity */
1494 SCIP_CALL( SCIPallocBufferArray(scip, &colidxsorted, ncols) );
1495 SCIP_CALL( SCIPallocBufferArray(scip, &colsparsity, ncols) );
1496 for( c = 0; c < ncols; ++c )
1497 {
1498 colidxsorted[c] = c;
1499 colsparsity[c] = -SCIPmatrixGetColNNonzs(matrix, c);
1500 }
1501 SCIPsortIntInt(colsparsity, colidxsorted, ncols);
1502
1503 /* loop over the columns and cancel nonzeros until maximum number of retrieves is reached */
1504 maxuseless = (SCIP_Longint)(presoldata->maxretrievefac * (SCIP_Real)ncols);
1505 nuseless = 0;
1506 numcancel = 0;
1507 nfillin = 0;
1508 for( c = 0; c < ncols && nuseless <= maxuseless && !SCIPisStopped(scip); c++ )
1509 {
1510 int colidx;
1511
1512 colidx = colidxsorted[c];
1513
1514 if( isblockedvar[colidx] )
1515 continue;
1516
1517 /* since the function parameters for the max fillin are unsigned we do not need to handle the
1518 * unlimited (-1) case due to implicit conversion rules */
1519 SCIP_CALL( cancelCol(scip, matrix, presoldata, pairtable, ishashingcols, vars, isblockedvar, colidx, \
1520 presoldata->maxcontfillin == -1 ? INT_MAX : presoldata->maxcontfillin, \
1521 presoldata->maxintfillin == -1 ? INT_MAX : presoldata->maxintfillin, \
1522 presoldata->maxbinfillin == -1 ? INT_MAX : presoldata->maxbinfillin, \
1523 presoldata->maxconsiderednonzeros, presoldata->preserveintcoefs, \
1524 &nuseless, nchgcoefs, &numcancel, &nfillin, FALSE) );
1525 }
1526
1527 if( numcancel > 0 )
1528 {
1530 " (%.1fs) dualsparsify: %d nonzeros canceled\n", SCIPgetSolvingTime(scip), numcancel);
1532 }
1533 else /* do reductions on variables that contain larger nonzero entries */
1534 {
1535 SCIPhashtableRemoveAll(pairtable);
1536 nconspairs = 0;
1537
1538 /* collect large nonzero entries variables and their number of nonzeros */
1539 for( c = 0; c < ncols; c++ )
1540 {
1541 int nnonz;
1542
1543 nnonz = SCIPmatrixGetColNNonzs(matrix, c);
1544 vars[c] = SCIPmatrixGetVar(matrix, c);
1545
1546 /* if the locks do not match do not consider the column for sparsification
1547 * also skip if the variable is not allowed to be multi-aggregated
1548 */
1550 {
1551 isblockedvar[c] = TRUE;
1552 ishashingcols[c] = FALSE;
1553 continue;
1554 }
1555
1556 isblockedvar[c] = FALSE;
1557
1558 /* only consider nonimplied free variables, i.e., non-hashing columns in the previous step,
1559 * with large nonzero entries
1560 * skip singleton variables, because either the constraint is redundant
1561 * or the variables can be canceled by variables substitution
1562 */
1563 if( nnonz >= presoldata->mineliminatednonzeros && !ishashingcols[c] )
1564 {
1565 int* colinds;
1566 SCIP_Real* colvals;
1567 int npairs;
1568 int failshift;
1569
1570 ishashingcols[c] = TRUE;
1571 colinds = SCIPmatrixGetColIdxPtr(matrix, c);
1572 colvals = SCIPmatrixGetColValPtr(matrix, c);
1573
1574 /* sort the rows non-decreasingly by number of nonzeros
1575 * if the number of nonzeros, we use the colindex as tie-breaker
1576 */
1577 for( i = 0; i < nnonz; ++i )
1578 {
1579 perm[i] = i;
1580 scores[i] = -SCIPmatrixGetRowNNonzs(matrix, colinds[i]) - 1.0 * colinds[i] / ncols;
1581 }
1582 SCIPsortRealInt(scores, perm, nnonz);
1583
1584 if( presoldata->maxconsiderednonzeros >= 0 )
1585 nnonz = MIN(nnonz, presoldata->maxconsiderednonzeros);
1586
1587 npairs = (nnonz * (nnonz - 1)) / 2;
1588 if( nconspairs + npairs > conspairssize )
1589 {
1590 int newsize = SCIPcalcMemGrowSize(scip, nconspairs + npairs);
1591 SCIP_CALL( SCIPreallocBufferArray(scip, &conspairs, newsize) );
1592 conspairssize = newsize;
1593 }
1594
1595 /* if we are called after one or more failures, i.e., executions without finding cancellations, then we
1596 * shift the section of nonzeros considered; in the case that the maxconsiderednonzeros limit is hit,
1597 * this results in different constraint pairs being tried and avoids trying the same useless
1598 * cancellations repeatedly
1599 */
1600 failshift = presoldata->nfailures*presoldata->maxconsiderednonzeros;
1601
1602 for( i = 0; i < nnonz; ++i )
1603 {
1604 for( j = i + 1; j < nnonz; ++j )
1605 {
1606 int i1;
1607 int i2;
1608
1609 assert(nconspairs < conspairssize);
1610 assert(conspairs != NULL);
1611
1612 i1 = perm[(i + failshift) % nnonz];
1613 i2 = perm[(j + failshift) % nnonz];
1614 conspairs[nconspairs].colindex = c;
1615
1616 if( colinds[i1] < colinds[i2])
1617 {
1618 conspairs[nconspairs].consindex1 = colinds[i1];
1619 conspairs[nconspairs].consindex2 = colinds[i2];
1620 conspairs[nconspairs].conscoef1 = colvals[i1];
1621 conspairs[nconspairs].conscoef2 = colvals[i2];
1622 }
1623 else
1624 {
1625 conspairs[nconspairs].consindex1 = colinds[i2];
1626 conspairs[nconspairs].consindex2 = colinds[i1];
1627 conspairs[nconspairs].conscoef1 = colvals[i2];
1628 conspairs[nconspairs].conscoef2 = colvals[i1];
1629 }
1630 ++nconspairs;
1631 }
1632 }
1633 }
1634 else
1635 {
1636 ishashingcols[c] = FALSE;
1637 }
1638 }
1639
1640 /* insert conspairs into hash table */
1641 for( c = 0; c < nconspairs; ++c )
1642 {
1643 SCIP_Bool insert;
1644 COLCONSPAIR* otherconspair;
1645
1646 assert(conspairs != NULL);
1647
1648 insert = TRUE;
1649
1650 /* check if this pair is already contained in the hash table;
1651 * The loop is required due to the non-transitivity of the hash functions
1652 */
1653 while( (otherconspair = (COLCONSPAIR*)SCIPhashtableRetrieve(pairtable, (void*) &conspairs[c])) != NULL )
1654 {
1655 /* if the previous constraint pair has fewer or the same number of nonzeros in the attached column
1656 * we keep that pair and skip this one
1657 */
1658 if( SCIPmatrixGetColNNonzs(matrix, otherconspair->colindex) <=
1659 SCIPmatrixGetColNNonzs(matrix, conspairs[c].colindex) )
1660 {
1661 insert = FALSE;
1662 break;
1663 }
1664
1665 /* this pairs column has fewer nonzeros, so remove the other pair from the hash table and loop */
1666 SCIP_CALL( SCIPhashtableRemove(pairtable, (void*) otherconspair) );
1667 }
1668
1669 if( insert )
1670 {
1671 SCIP_CALL( SCIPhashtableInsert(pairtable, (void*) &conspairs[c]) );
1672 }
1673 }
1674
1675 /* sort rows according to decreasingly sparsity */
1676 assert(colidxsorted != NULL);
1677 assert(colsparsity != NULL);
1678 for( c = 0; c < ncols; ++c )
1679 {
1680 colidxsorted[c] = c;
1681 colsparsity[c] = -SCIPmatrixGetColNNonzs(matrix, c);
1682 }
1683 SCIPsortIntInt(colsparsity, colidxsorted, ncols);
1684
1685 /* loop over the columns and cancel nonzeros until maximum number of retrieves is reached */
1686 maxuseless = (SCIP_Longint)(presoldata->maxretrievefac * (SCIP_Real)ncols);
1687 nuseless = 0;
1688 for( c = 0; c < ncols && nuseless <= maxuseless; c++ )
1689 {
1690 int colidx;
1691 int nnonz;
1692
1693 colidx = colidxsorted[c];
1694 nnonz = SCIPmatrixGetColNNonzs(matrix, colidx);
1695
1696 if( isblockedvar[colidx] || nnonz < presoldata->mineliminatednonzeros )
1697 continue;
1698
1699 /* since the function parameters for the max fillin are unsigned we do not need to handle the
1700 * unlimited (-1) case due to implicit conversion rules */
1701 SCIP_CALL( cancelCol(scip, matrix, presoldata, pairtable, ishashingcols, vars, isblockedvar, colidx, \
1702 presoldata->maxcontfillin == -1 ? INT_MAX : presoldata->maxcontfillin, \
1703 presoldata->maxintfillin == -1 ? INT_MAX : presoldata->maxintfillin, \
1704 presoldata->maxbinfillin == -1 ? INT_MAX : presoldata->maxbinfillin, \
1705 presoldata->maxconsiderednonzeros, presoldata->preserveintcoefs, \
1706 &nuseless, nchgcoefs, &numcancel, &nfillin, TRUE) );
1707 }
1708
1709 if( numcancel > 0 )
1710 {
1712 " (%.1fs) dualsparsify: %d nonzeros canceled\n", SCIPgetSolvingTime(scip), numcancel);
1714 }
1715 }
1716
1717 updateFailureStatistic(presoldata, numcancel > 0);
1718
1719 SCIPfreeBufferArrayNull(scip, &conspairs);
1720 SCIPfreeBufferArray(scip, &colsparsity);
1721 SCIPfreeBufferArray(scip, &colidxsorted);
1722
1723 SCIPhashtableFree(&pairtable);
1724
1725 SCIPfreeBufferArray(scip, &isblockedvar);
1727 SCIPfreeBufferArray(scip, &ishashingcols);
1728 SCIPfreeBufferArray(scip, &perm);
1729 SCIPfreeBufferArray(scip, &scores);
1730
1731 SCIPmatrixFree(scip, &matrix);
1732
1733 return SCIP_OKAY;
1734}
1735
1736/*
1737 * presolver specific interface methods
1738 */
1739
1740/** destructor of presolver to free user data (called when SCIP is exiting) */
1741static
1742SCIP_DECL_PRESOLFREE(presolFreeDualsparsify)
1743{ /*lint --e{715}*/
1744 SCIP_PRESOLDATA* presoldata;
1745
1746 /* free presolver data */
1747 presoldata = SCIPpresolGetData(presol);
1748 assert(presoldata != NULL);
1749
1750 SCIPfreeBlockMemory(scip, &presoldata);
1751 SCIPpresolSetData(presol, NULL);
1752
1753 return SCIP_OKAY;
1754}
1755
1756/** initialization method of presolver (called after problem was transformed) */
1757static
1758SCIP_DECL_PRESOLINIT(presolInitDualsparsify)
1759{
1760 SCIP_PRESOLDATA* presoldata;
1761
1762 /* set the counters in the init (and not in the initpre) callback such that they persist across restarts */
1763 presoldata = SCIPpresolGetData(presol);
1764 presoldata->nfailures = 0;
1765 presoldata->nwaitingcalls = 0;
1766 presoldata->naggregated = 0;
1767
1768 return SCIP_OKAY;
1769}
1770
1771/** creates the dualsparsify presolver and includes it in SCIP */
1773 SCIP* scip /**< SCIP data structure */
1774 )
1775{
1776 SCIP_PRESOLDATA* presoldata;
1777 SCIP_PRESOL* presol;
1778
1779 /* create dualsparsify presolver data */
1780 SCIP_CALL( SCIPallocBlockMemory(scip, &presoldata) );
1781
1782 /* include presolver */
1784 PRESOL_TIMING, presolExecDualsparsify, presoldata) );
1785
1786 SCIP_CALL( SCIPsetPresolCopy(scip, presol, presolCopyDualsparsify) );
1787 SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeDualsparsify) );
1788 SCIP_CALL( SCIPsetPresolInit(scip, presol, presolInitDualsparsify) );
1789
1791 "presolving/dualsparsify/enablecopy",
1792 "should dualsparsify presolver be copied to sub-SCIPs?",
1793 &presoldata->enablecopy, TRUE, DEFAULT_ENABLECOPY, NULL, NULL) );
1794
1796 "presolving/dualsparsify/preserveintcoefs",
1797 "should we forbid cancellations that destroy integer coefficients?",
1798 &presoldata->preserveintcoefs, TRUE, DEFAULT_PRESERVEINTCOEFS, NULL, NULL) );
1799
1801 "presolving/dualsparsify/preservegoodlocks",
1802 "should we preserve good locked properties of variables (at most one lock in one direction)?",
1803 &presoldata->preservegoodlocks, TRUE, DEFAULT_PRESERVEGOODLOCKS, NULL, NULL) );
1804
1806 "presolving/dualsparsify/maxcontfillin",
1807 "maximal fillin for continuous variables (-1: unlimited)",
1808 &presoldata->maxcontfillin, FALSE, DEFAULT_MAX_CONT_FILLIN, -1, INT_MAX, NULL, NULL) );
1809
1811 "presolving/dualsparsify/maxbinfillin",
1812 "maximal fillin for binary variables (-1: unlimited)",
1813 &presoldata->maxbinfillin, FALSE, DEFAULT_MAX_BIN_FILLIN, -1, INT_MAX, NULL, NULL) );
1814
1816 "presolving/dualsparsify/maxintfillin",
1817 "maximal fillin for integer variables including binaries (-1: unlimited)",
1818 &presoldata->maxintfillin, FALSE, DEFAULT_MAX_INT_FILLIN, -1, INT_MAX, NULL, NULL) );
1819
1821 "presolving/dualsparsify/maxconsiderednonzeros",
1822 "maximal number of considered nonzeros within one column (-1: no limit)",
1823 &presoldata->maxconsiderednonzeros, TRUE, DEFAULT_MAXCONSIDEREDNONZEROS, -1, INT_MAX, NULL, NULL) );
1824
1826 "presolving/dualsparsify/mineliminatednonzeros",
1827 "minimal eliminated nonzeros within one column if we need to add a constraint to the problem",
1828 &presoldata->mineliminatednonzeros, FALSE, DEFAULT_MINELIMINATEDNONZEROS, 0, INT_MAX, NULL, NULL) );
1829
1831 "presolving/dualsparsify/maxretrievefac",
1832 "limit on the number of useless vs. useful hashtable retrieves as a multiple of the number of constraints",
1833 &presoldata->maxretrievefac, TRUE, DEFAULT_MAXRETRIEVEFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1834
1836 "presolving/dualsparsify/waitingfac",
1837 "number of calls to wait until next execution as a multiple of the number of useless calls",
1838 &presoldata->waitingfac, TRUE, DEFAULT_WAITINGFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1839
1840 return SCIP_OKAY;
1841}
SCIP_VAR * a
SCIP_VAR ** b
Constraint handler for linear constraints in their most general form, .
methods for debugging
#define SCIPdebugGetSolVal(scip, var, val)
Definition debug.h:313
#define SCIPdebugAddSolVal(scip, var, val)
Definition debug.h:312
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define COPYSIGN
Definition def.h:248
#define SCIP_Longint
Definition def.h:150
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#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 REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
#define SCIPhashThree(a, b, c)
Definition pub_misc.h:570
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
void SCIPhashtableRemoveAll(SCIP_HASHTABLE *hashtable)
Definition misc.c:2743
static INLINE uint32_t SCIPrealHashCode(double x)
Definition pub_misc.h:593
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2665
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
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 SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10511
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
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 SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_RETCODE SCIPsetPresolFree(SCIP *scip, SCIP_PRESOL *presol,)
void SCIPpresolSetData(SCIP_PRESOL *presol, SCIP_PRESOLDATA *presoldata)
Definition presol.c:538
SCIP_PRESOLDATA * SCIPpresolGetData(SCIP_PRESOL *presol)
Definition presol.c:528
SCIP_RETCODE SCIPsetPresolCopy(SCIP *scip, SCIP_PRESOL *presol,)
SCIP_RETCODE SCIPincludePresolBasic(SCIP *scip, SCIP_PRESOL **presolptr, const char *name, const char *desc, int priority, int maxrounds, SCIP_PRESOLTIMING timing, SCIP_DECL_PRESOLEXEC((*presolexec)), SCIP_PRESOLDATA *presoldata)
SCIP_RETCODE SCIPsetPresolInit(SCIP *scip, SCIP_PRESOL *presol,)
const char * SCIPpresolGetName(SCIP_PRESOL *presol)
Definition presol.c:625
int SCIPgetNRuns(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisSumZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition var.c:23546
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_Bool SCIPdoNotAggr(SCIP *scip)
Definition scip_var.c:10909
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23530
SCIP_Bool SCIPdoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:10942
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:225
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPmultiaggregateVar(SCIP *scip, SCIP_VAR *var, int naggvars, SCIP_VAR **aggvars, SCIP_Real *scalars, SCIP_Real constant, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition scip_var.c:10834
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition var.c:23556
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_Bool SCIPisVarAggrCoefAcceptable(SCIP *scip, SCIP_VAR *var, SCIP_Real scalar)
Definition scip_var.c:10962
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
int c
assert(minobj< SCIPgetCutoffbound(scip))
int bestcand
static SCIP_VAR ** vars
SCIP_Bool SCIPmatrixUplockConflict(SCIP_MATRIX *matrix, int col)
Definition matrix.c:2201
int SCIPmatrixGetRowNMinActNegInf(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2141
int * SCIPmatrixGetColIdxPtr(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1873
int SCIPmatrixGetRowNNonzs(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2013
int SCIPmatrixGetColNDownlocks(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1941
int SCIPmatrixGetColNNonzs(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1885
int SCIPmatrixGetColNUplocks(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1929
SCIP_Real SCIPmatrixGetRowMaxActivity(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2129
SCIP_Real SCIPmatrixGetColLb(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1918
SCIP_Real SCIPmatrixGetRowLhs(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2047
SCIP_Real * SCIPmatrixGetRowValPtr(SCIP_MATRIX *matrix, int row)
Definition matrix.c:1977
SCIP_Bool SCIPmatrixDownlockConflict(SCIP_MATRIX *matrix, int col)
Definition matrix.c:2213
SCIP_Real SCIPmatrixGetRowRhs(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2059
SCIP_Real * SCIPmatrixGetColValPtr(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1861
int SCIPmatrixGetRowNMinActPosInf(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2153
SCIP_RETCODE SCIPmatrixCreate(SCIP *scip, SCIP_MATRIX **matrixptr, SCIP_Bool onlyifcomplete, SCIP_Bool *initialized, SCIP_Bool *complete, SCIP_Bool *infeasible, int *naddconss, int *ndelconss, int *nchgcoefs, int *nchgbds, int *nfixedvars)
Definition matrix.c:703
int SCIPmatrixGetNColumns(SCIP_MATRIX *matrix)
Definition matrix.c:1897
SCIP_Real SCIPmatrixGetRowMinActivity(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2117
void SCIPmatrixFree(SCIP *scip, SCIP_MATRIX **matrix)
Definition matrix.c:1348
int SCIPmatrixGetRowNMaxActPosInf(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2177
int SCIPmatrixGetRowNMaxActNegInf(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2165
SCIP_VAR * SCIPmatrixGetVar(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1953
int * SCIPmatrixGetRowIdxPtr(SCIP_MATRIX *matrix, int row)
Definition matrix.c:2001
int SCIPmatrixGetNRows(SCIP_MATRIX *matrix)
Definition matrix.c:2037
void SCIPmatrixRemoveColumnBounds(SCIP *scip, SCIP_MATRIX *matrix, int col)
Definition matrix.c:1459
SCIP_Real SCIPmatrixGetColUb(SCIP_MATRIX *matrix, int col)
Definition matrix.c:1907
memory allocation routines
#define PRESOL_NAME
#define PRESOL_PRIORITY
#define PRESOL_MAXROUNDS
#define PRESOL_TIMING
#define PRESOL_DESC
#define DEFAULT_MAXCONSIDEREDNONZEROS
static SCIP_RETCODE cancelCol(SCIP *scip, SCIP_MATRIX *matrix, SCIP_PRESOLDATA *presoldata, SCIP_HASHTABLE *pairtable, SCIP_Bool *ishashingcols, SCIP_VAR **vars, SCIP_Bool *isblockedvar, int colidx, int maxcontfillin, int maxintfillin, int maxbinfillin, int maxconsiderednonzeros, SCIP_Bool preserveintcoefs, SCIP_Longint *nuseless, int *nchgcoefs, int *ncanceled, int *nfillin, SCIP_Bool isaddedcons)
SCIP_RETCODE SCIPincludePresolDualsparsify(SCIP *scip)
struct ColConsPair COLCONSPAIR
#define MAXSCALE
#define DEFAULT_MAX_INT_FILLIN
static void getVarBoundsOfRow(SCIP *scip, SCIP_MATRIX *matrix, int col, int row, SCIP_Real val, SCIP_Real *rowub, SCIP_Bool *ubfound, SCIP_Real *rowlb, SCIP_Bool *lbfound)
static SCIP_RETCODE aggregation(SCIP *scip, SCIP_MATRIX *matrix, SCIP_PRESOLDATA *presoldata, SCIP_VAR **vars, int colidx1, int colidx2, SCIP_Bool isimpliedfree, SCIP_Real weight1)
static void updateFailureStatistic(SCIP_PRESOLDATA *presoldata, SCIP_Bool success)
#define DEFAULT_PRESERVEGOODLOCKS
#define DEFAULT_MINELIMINATEDNONZEROS
static SCIP_Real getMinActivitySingleRowWithoutCol(SCIP *scip, SCIP_MATRIX *matrix, int row, int col)
#define DEFAULT_ENABLECOPY
#define DEFAULT_MAX_CONT_FILLIN
#define DEFAULT_WAITINGFAC
static void getImpliedBounds(SCIP *scip, SCIP_MATRIX *matrix, int col, SCIP_Bool *ubimplied, SCIP_Bool *lbimplied)
#define DEFAULT_MAXRETRIEVEFAC
#define DEFAULT_MAX_BIN_FILLIN
static SCIP_Real getMaxActivitySingleRowWithoutCol(SCIP *scip, SCIP_MATRIX *matrix, int row, int col)
static void getMinMaxActivityResiduals(SCIP *scip, SCIP_MATRIX *matrix, int col, int row, SCIP_Real val, SCIP_Real *minresactivity, SCIP_Real *maxresactivity, SCIP_Bool *isminsettoinfinity, SCIP_Bool *ismaxsettoinfinity)
#define DEFAULT_PRESERVEINTCOEFS
cancel nonzeros of the constraint matrix based on the columns
public methods for managing constraints
public methods for matrix
public methods for message output
#define SCIPdebugPrintCons(x, y, z)
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for presolvers
public methods for problem variables
public methods for constraint handler plugins and constraints
general public methods
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for presolving plugins
public methods for variable pricer plugins
public methods for global and local (sub)problems
public methods for the probing mode
public methods for querying solving statistics
public methods for timing
public methods for SCIP variables
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
struct SCIP_Matrix SCIP_MATRIX
Definition type_matrix.h:42
@ SCIP_VERBLEVEL_HIGH
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
#define SCIP_DECL_PRESOLCOPY(x)
Definition type_presol.h:60
struct SCIP_PresolData SCIP_PRESOLDATA
Definition type_presol.h:51
#define SCIP_DECL_PRESOLFREE(x)
Definition type_presol.h:68
struct SCIP_Presol SCIP_PRESOL
Definition type_presol.h:50
#define SCIP_DECL_PRESOLINIT(x)
Definition type_presol.h:76
#define SCIP_DECL_PRESOLEXEC(x)
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
enum SCIP_ImplintType SCIP_IMPLINTTYPE
Definition type_var.h:117
@ SCIP_IMPLINTTYPE_NONE
Definition type_var.h:90
@ SCIP_IMPLINTTYPE_WEAK
Definition type_var.h:91
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
enum SCIP_Vartype SCIP_VARTYPE
Definition type_var.h:73