Scippy

SCIP

Solving Constraint Integer Programs

presol_implint.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file presol_implint.c
26 * @ingroup DEFPLUGINS_PRESOL
27 * @brief Presolver that detects implicit integer variables
28 * @author Rolf van der Hulst
29 */
30
31/* TODO: support more constraint types: cons_nonlinear, cons_indicator and symmetry constraints */
32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33
34#include <assert.h>
35
36#include "scip/presol_implint.h"
37#include "scip/pub_cons.h"
38#include "scip/pub_message.h"
39#include "scip/pub_misc.h"
40#include "scip/pub_network.h"
41#include "scip/pub_presol.h"
42#include "scip/pub_var.h"
43
44#include "scip/scip_cons.h"
45#include "scip/scip_general.h"
46#include "scip/scip_message.h"
47#include "scip/scip_mem.h"
48#include "scip/scip_nlp.h"
49#include "scip/scip_numerics.h"
50#include "scip/scip_param.h"
51#include "scip/scip_presol.h"
52#include "scip/scip_pricer.h"
53#include "scip/scip_prob.h"
54#include "scip/scip_probing.h"
55#include "scip/scip_timing.h"
56#include "scip/scip_var.h"
57
58#include "scip/cons_and.h"
59#include "scip/cons_linear.h"
60#include "scip/cons_logicor.h"
61#include "scip/cons_knapsack.h"
62#include "scip/cons_or.h"
63#include "scip/cons_setppc.h"
64#include "scip/cons_varbound.h"
65#include "scip/cons_xor.h"
66
67#define PRESOL_NAME "implint"
68#define PRESOL_DESC "detects implicit integer variables"
69
70/* We want to run as late as possible, but before symmetry detection.
71 * The main reason for this is that symmetry detection may add linear constraints that
72 * impede the detection of implied integrality, but do not break implied integrality itself.
73 * Also, symmetry methods rely on the fact that each variable in an orbit is integral,
74 * as otherwise certain reductions may break. So it is currently not safe to run implied integrality detection
75 * after symmetry methods are applied. */
76#define PRESOL_PRIORITY -900000 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers); combined with propagators */
77#define PRESOL_MAXROUNDS 0 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
78#define PRESOL_TIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolver (fast, medium, or exhaustive) */
79
80#define DEFAULT_CONVERTINTEGERS FALSE /**< should implied integrality also be detected for enforced integral variables? */
81#define DEFAULT_COLUMNROWRATIO 50.0 /**< use the network row addition algorithm when the column to row ratio becomes larger than this threshold */
82#define DEFAULT_NUMERICSLIMIT 1e8 /**< a row that contains variables with coefficients that are greater in absolute value than this limit is not considered for implied integrality detection */
83
84/** presolver data */
85struct SCIP_PresolData
86{
87 SCIP_Bool computedimplints; /**< were implied integers already computed? */
88 SCIP_Bool convertintegers; /**< should implied integrality also be detected for enforced integral variables? */
89 SCIP_Real columnrowratio; /**< use the network row addition algorithm when the column to row ratio
90 * becomes larger than this threshold, otherwise, use column addition */
91 SCIP_Real numericslimit; /**< a row that contains variables with coefficients that are greater in
92 * absolute value than this limit is not considered for
93 * implied integrality detection */
94};
95
96/** constraint matrix data structure in column and row major format
97 * Contains only the linear terms, and marks the presence of non-linear terms.
98 */
100{
101 SCIP_Real* colmatval; /**< coefficients in column major format */
102 int* colmatind; /**< row indexes in column major format */
103 int* colmatbeg; /**< column storage offset */
104 int* colmatcnt; /**< number of row entries per column */
105 int ncols; /**< complete number of columns */
106 SCIP_Real* lb; /**< lower bound per variable */
107 SCIP_Real* ub; /**< upper bound per variable */
108 SCIP_Bool* colintegral; /**< whether column is integral */
109 SCIP_Bool* colimplintegral; /**< whether the column is implied integral */
110 SCIP_Bool* colinnonlinterm; /**< is the column involved in some nonlinear term? */
111 /* TODO: fields for more involved detection and scoring:
112 * bounds integral? number of +-1 nonzeros?
113 * ntimes operand / resultant in logical constraints?
114 * nconstraints (different from nnonz because of multiple row constraints)
115 * npmonenonzeros in integral equality rows */
116
117 SCIP_VAR** colvar; /**< variable described by column */
118
119 SCIP_Real* rowmatval; /**< coefficients in row major format */
120 int* rowmatind; /**< column indexed in row major format */
121 int* rowmatbeg; /**< row storage offset */
122 int* rowmatcnt; /**< number of column entries per row */
123
124 int nrows; /**< complete number of rows */
125 SCIP_Real* lhs; /**< left hand side per row */
126 SCIP_Real* rhs; /**< right hand side per row */
127
128 SCIP_CONS** rowcons; /**< constraint described by row */
129
130 int nnonzs; /**< sparsity counter */
131 int nnonzssize; /**< size of the nonzero arrays */
132};
134
135/** struct that contains information about the blocks/components of the submatrix given by the continuous columns */
137{
138 int nmatrixrows; /**< Number of rows in the matrix for the linear part of the problem */
139 int nmatrixcols; /**< Number of columns in the matrix for the linear part of the problem */
140
141 int* rowcomponent; /**< Maps a row to the index of the component it belongs to */
142 int* colcomponent; /**< Maps a column to the index of the component it belongs to */
143
144 int* componentrows; /**< Flattened array of arrays of rows that are in a given component. */
145 int* componentcols; /**< Flattened array of arrays of columns that are in a given component. */
146 int* componentrowend; /**< The index of componentrows where the given component ends. */
147 int* componentcolend; /**< The index of componentcols where the given component ends. */
148 int ncomponents; /**< The number of components. */
149};
151
152/** a temporary data structure that stores some statistics/data on the rows and columns */
154{
155 SCIP_Bool* rowintegral; /**< Are all row entries of non-continuous columns and the row sides integral? */
156 SCIP_Bool* rowequality; /**< Is the row an equality? */
157 SCIP_Bool* rowbadnumerics; /**< Does the row contain large entries that make numerics difficult? */
158 int* rownnonz; /**< Number of nonzeros in the row */
159 int* rowncontinuous; /**< The number of those nonzeros that are in continuous columns */
160 int* rowncontinuouspmone; /**< The number of +-1 entries in continuous columns */
161 SCIP_Bool* colintegralbounds; /**< Does the column have integral bounds? */
162};
164
165/** struct that contains some information for each integer variable that is a candidate for implied integrality detection */
167{
168 int column; /**< The candidate column to make implied integer */
169 int numContPlanarEntries; /**< The number of nonzeros that have a row in a planar component */
170 int numContNetworkEntries; /**< The number of nonzeros that have a row in a pure network component */
171 int numContTransNetworkEntries; /**< The number of nonzeroes that have a row in a pure transposed network component */
172};
174
175/** gets a pointer to the array of nonzero values for the nonzeros in the given column */
176static
178 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
179 int column /**< the column */
180 )
181{
182 assert(matrix != NULL);
183 assert(column >= 0);
184 assert(column < matrix->ncols);
185
186 return matrix->colmatval + matrix->colmatbeg[column];
187}
188
189/** gets a pointer to the array of row indices for the nonzeros in the given column */
190static
192 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
193 int column /**< the column */
194 )
195{
196 assert(matrix != NULL);
197 assert(column >= 0);
198 assert(column < matrix->ncols);
199
200 return matrix->colmatind + matrix->colmatbeg[column];
201}
202
203/** gets the number of nonzeros in the given column */
204static
206 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
207 int column /**< the column */
208 )
209{
210 assert(matrix != NULL);
211 assert(column >= 0);
212 assert(column < matrix->ncols);
213
214 return matrix->colmatcnt[column];
215}
216
217/** gets a pointer to the array of nonzero values for the nonzeros in the given row */
218static
220 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
221 int row /**< the row */
222 )
223{
224 assert(matrix != NULL);
225 assert(row >= 0);
226 assert(row < matrix->nrows);
227
228 return matrix->rowmatval + matrix->rowmatbeg[row];
229}
230
231/** gets a pointer to the array of column indices for the nonzeros in the given row */
232static
234 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
235 int row /**< the row */
236 )
237{
238 assert(matrix != NULL);
239 assert(row >= 0);
240 assert(row < matrix->nrows);
241
242 return matrix->rowmatind + matrix->rowmatbeg[row];
243}
244
245/** gets the number of nonzeros in the given row */
246static
248 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
249 int row /**< the row */
250 )
251{
252 assert(matrix != NULL);
253 assert(row >= 0);
254 assert(row < matrix->nrows);
255
256 return matrix->rowmatcnt[row];
257}
258
259/** returns the number of rows in the matrix */
260static
262 IMPLINT_MATRIX* matrix /**< the matrix data structure */
263 )
264{
265 assert(matrix != NULL);
266
267 return matrix->nrows;
268}
269
270/** returns the number of columns in the matrix */
271static
273 IMPLINT_MATRIX* matrix /**< the matrix data structure */
274 )
275{
276 assert(matrix != NULL);
277
278 return matrix->ncols;
279}
280
281/** returns the variable associated with the column */
282static
284 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
285 int column /**< the column */
286 )
287{
288 assert(matrix != NULL);
289 assert(column >= 0);
290 assert(column < matrix->ncols);
291
292 return matrix->colvar[column];
293}
294
295/** returns TRUE if the given column originates from an integral variable */
296static
298 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
299 int column /**< the column */
300 )
301{
302 assert(matrix != NULL);
303 assert(column >= 0);
304 assert(column < matrix->ncols);
305
306 return matrix->colintegral[column];
307}
308
309/** returns TRUE if the given column originates from an implied integral variable */
310static
312 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
313 int column /**< the column */
314 )
315{
316 assert(matrix != NULL);
317 assert(column >= 0);
318 assert(column < matrix->ncols);
319
320 return matrix->colimplintegral[column];
321}
322
323/** returns TRUE if the given column occurs in a nonlinear expression in some constraint */
324static
326 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
327 int column /**< the column */
328 )
329{
330 assert(matrix != NULL);
331 assert(column >= 0);
332 assert(column < matrix->ncols);
333
334 return matrix->colinnonlinterm[column];
335}
336
337/** returns the lower bound of the given column */
338static
340 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
341 int column /**< the column */
342 )
343{
344 assert(matrix != NULL);
345 assert(column >= 0);
346 assert(column < matrix->ncols);
347
348 return matrix->lb[column];
349}
350
351/** returns the upper bound of the given column */
352static
354 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
355 int column /**< the column */
356 )
357{
358 assert(matrix != NULL);
359 assert(column >= 0);
360 assert(column < matrix->ncols);
361
362 return matrix->ub[column];
363}
364
365/** returns the left hand side of the given row */
366static
368 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
369 int row /**< the row */
370 )
371{
372 assert(matrix != NULL);
373 assert(row >= 0);
374 assert(row < matrix->nrows);
375
376 return matrix->lhs[row];
377}
378
379/** returns the right hand side of the given row */
380static
382 IMPLINT_MATRIX* matrix, /**< the matrix data structure */
383 int row /**< the row */
384 )
385{
386 assert(matrix != NULL);
387 assert(row >= 0);
388 assert(row < matrix->nrows);
389
390 return matrix->rhs[row];
391}
392
393/** transforms given variables, scalars and constant to the corresponding active variables, scalars and constant */
394static
396 SCIP* scip, /**< SCIP instance */
397 SCIP_VAR*** vars, /**< vars array to get active variables for */
398 SCIP_Real** scalars, /**< scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
399 int* nvars, /**< pointer to number of variables and values in vars and vals array */
400 SCIP_Real* constant /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
401 )
402{
403 int requiredsize;
404
405 assert(scip != NULL);
406 assert(vars != NULL);
407 assert(scalars != NULL);
408 assert(*vars != NULL);
409 assert(*scalars != NULL);
410 assert(nvars != NULL);
411 assert(constant != NULL);
412
413 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) );
414
415 if( requiredsize > *nvars )
416 {
417 SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) );
418 SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) );
419
420 /* call function a second time with enough memory */
421 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) );
422 }
423 assert(requiredsize == *nvars);
424
425 return SCIP_OKAY;
426}
427
428/** add one row to the constraint matrix */
429static
431 SCIP* scip, /**< SCIP data structure */
432 IMPLINT_MATRIX* matrix, /**< constraint matrix */
433 SCIP_VAR** vars, /**< variables of this row */
434 SCIP_Real* vals, /**< coefficients of this row */
435 int nvars, /**< number of variables of this row */
436 SCIP_Real lhs, /**< left hand side */
437 SCIP_Real rhs, /**< right hand side */
438 SCIP_CONS* cons /**< constraint where the row originated from */
439 )
440{
441 int probindex;
442 int rowidx;
443 int j;
444
445 assert(vars != NULL);
446 assert(vals != NULL);
447
448 rowidx = matrix->nrows;
449
450 matrix->lhs[rowidx] = lhs;
451 matrix->rhs[rowidx] = rhs;
452 matrix->rowmatbeg[rowidx] = matrix->nnonzs;
453
454 for( j = 0; j < nvars; ++j )
455 {
456 /* ignore variables with very small coefficients */
457 if( SCIPisZero(scip, vals[j]) )
458 continue;
459
460 assert(matrix->nnonzs < matrix->nnonzssize);
461 matrix->rowmatval[matrix->nnonzs] = vals[j];
462 probindex = SCIPvarGetProbindex(vars[j]);
463 assert(0 <= probindex && probindex < matrix->ncols);
464 matrix->rowmatind[matrix->nnonzs] = probindex;
465 ++matrix->nnonzs;
466 }
467
468 matrix->rowmatcnt[rowidx] = matrix->nnonzs - matrix->rowmatbeg[rowidx];
469 matrix->rowcons[rowidx] = cons;
470
471 ++matrix->nrows;
472
473 return SCIP_OKAY;
474}
475
476/** transforms the weighted sum to active variables and then adds the given linear constraint to the matrix */
477static
479 SCIP* scip, /**< current scip instance */
480 IMPLINT_MATRIX* matrix, /**< constraint matrix */
481 SCIP_VAR** vars, /**< variables of this constraint */
482 SCIP_Real* vals, /**< variable coefficients of this constraint.
483 **< If set to NULL, all values are assumed to be equal to 1.0. */
484 int nvars, /**< number of variables */
485 SCIP_Real lhs, /**< left hand side */
486 SCIP_Real rhs, /**< right hand side */
487 SCIP_CONS* cons /**< constraint belonging to the row */
488 )
489{
490 SCIP_VAR** activevars;
491 SCIP_Real* activevals;
492 SCIP_Real activeconstant;
493 int nactivevars;
494 int v;
495
496 assert(scip != NULL);
497 assert(matrix != NULL);
498 assert(vars != NULL || nvars == 0);
499 assert(SCIPisLE(scip, lhs, rhs));
500 assert(nvars >= 1 || (!SCIPisPositive(scip, lhs) && !SCIPisNegative(scip, rhs)));
501
502 /* constraint is redundant */
503 if( nvars == 0 || ( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) ) )
504 return SCIP_OKAY;
505
506 activevars = NULL;
507 activevals = NULL;
508 nactivevars = nvars;
509 activeconstant = 0.0;
510
511 /* duplicate variable and value array */
512 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars) );
513 if( vals != NULL )
514 {
515 SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars) );
516 }
517 else
518 {
519 SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) );
520
521 for( v = 0; v < nactivevars; ++v )
522 activevals[v] = 1.0;
523 }
524
525 /* retransform given variables to active variables */
526 SCIP_CALL( getActiveVariables(scip, &activevars, &activevals, &nactivevars, &activeconstant) );
527
528 /* adapt left and right hand side */
529 if( !SCIPisInfinity(scip, -lhs) )
530 lhs -= activeconstant;
531 if( !SCIPisInfinity(scip, rhs) )
532 rhs -= activeconstant;
533
534 assert(nactivevars >= 1 || (!SCIPisPositive(scip, lhs) && !SCIPisNegative(scip, rhs)));
535
536 /* add single row to matrix */
537 if( nactivevars >= 1 )
538 {
539 /**@todo normalize by greatest common divisor of coefficients for integral columns */
540 SCIP_CALL( matrixAddRow(scip, matrix, activevars, activevals, nactivevars, lhs, rhs, cons) );
541 }
542
543 /* free buffer arrays */
544 SCIPfreeBufferArray(scip, &activevals);
545 SCIPfreeBufferArray(scip, &activevars);
546
547 return SCIP_OKAY;
548}
549
550/** adds the linearization of a given AND constraint or OR constraint to the constraint matrix */
551static
553 SCIP* scip, /**< current scip instance */
554 IMPLINT_MATRIX* matrix, /**< constraint matrix */
555 SCIP_CONS* cons, /**< The constraint that is linearized */
556 SCIP_VAR** operands, /**< variables of this constraint */
557 int noperands, /**< number of operands */
558 SCIP_VAR* resultant, /**< Resultant variable */
559 SCIP_Bool isAndCons /**< Indicates if the constraint is an AND or OR linearization */
560 )
561{
562 SCIP_Real* vals;
563 SCIP_VAR** vars;
564 SCIP_Real lhs;
565 SCIP_Real rhs;
566 int i;
567
568 SCIP_CALL( SCIPallocBufferArray(scip, &vars, noperands + 1) );
569 SCIP_CALL( SCIPallocBufferArray(scip, &vals, noperands + 1) );
570
571 /* add all the constraints of the form resultant <= operand */
572 if( isAndCons )
573 {
574 lhs = -SCIPinfinity(scip);
575 rhs = 0.0;
576 }
577 else
578 {
579 lhs = 0.0;
580 rhs = SCIPinfinity(scip);
581 }
582
583 vars[0] = resultant;
584 vals[0] = 1.0;
585 vals[1] = -1.0;
586
587 for( i = 0; i < noperands; ++i )
588 {
589 vars[1] = operands[i];
590
591 SCIP_CALL( addLinearConstraint(scip, matrix, vars, vals, 2, lhs, rhs, cons) );
592 }
593
594 /* add the constraint of the form noperands - 1 + resultant >= sum operands */
595 if( isAndCons )
596 {
597 lhs = 1.0 - noperands;
598 rhs = SCIPinfinity(scip);
599 }
600 else
601 {
602 lhs = -SCIPinfinity(scip);
603 rhs = 0.0;
604 }
605
606 for( i = 0; i < noperands; ++i )
607 {
608 vars[i + 1] = operands[i];
609 vals[i + 1] = -1.0;
610 }
611
612 SCIP_CALL( addLinearConstraint(scip, matrix, vars, vals, noperands + 1, lhs, rhs, cons) );
613
616
617 return SCIP_OKAY;
618}
619
620/** adds the linearization of a given XOR constraint to the constraint matrix */
621static
623 SCIP* scip, /**< current scip instance */
624 IMPLINT_MATRIX* matrix, /**< constraint matrix */
625 SCIP_CONS* cons, /**< The constraint that is linearized */
626 SCIP_VAR** operands, /**< variables of this constraint */
627 int noperands, /**< number of operands */
628 SCIP_VAR* intvar, /**< the intvar of the xor constraint */
629 SCIP_Real rhs /**< the right hand side of the xor constraint */
630 )
631{
632 SCIP_VAR** vars;
633 SCIP_Real* vals;
634 int i;
635 int j;
636 int k;
637
638 SCIP_CALL( SCIPallocBufferArray(scip, &vals, noperands + 1) );
639
640 if( intvar != NULL )
641 {
642 SCIP_CALL( SCIPallocBufferArray(scip, &vars, noperands + 1) );
643
644 /* add intvar constraint */
645 for( j = 0; j < noperands; ++j )
646 {
647 vars[j] = operands[j];
648 vals[j] = 1.0;
649 }
650 vars[noperands] = intvar;
651 vals[noperands] = -2.0;
652
653 SCIP_CALL( addLinearConstraint(scip, matrix, vars, vals, noperands + 1, rhs, rhs, cons) );
654
656 }
657 else if( noperands == 3 )
658 {
659 /* in the special case of 3 variables and c = 0, the following linear system is created:
660 * + x - y - z <= 0
661 * - x + y - z <= 0
662 * - x - y + z <= 0
663 * + x + y + z <= 2
664 * in the special case of 3 variables and c = 1, the following linear system is created:
665 * - x + y + z <= 1
666 * + x - y + z <= 1
667 * + x + y - z <= 1
668 * - x - y - z <= -1
669 */
670 SCIP_Real scale = rhs == 0.0 ? 1.0 : -1.0; /*lint !e777*/
671
672 for( i = 0; i < noperands; ++i )
673 {
674 for( j = 0; j < noperands; ++j )
675 vals[j] = (i == j) ? scale : -scale;
676
677 SCIP_CALL( addLinearConstraint(scip, matrix, operands, vals, noperands, -SCIPinfinity(scip), rhs, cons) );
678 }
679
680 for( j = 0; j < noperands; ++j )
681 vals[j] = scale;
682
683 SCIP_CALL( addLinearConstraint(scip, matrix, operands, vals, noperands, -SCIPinfinity(scip), 2.0 - rhs * noperands, cons) );
684 }
685 else if( noperands < 3 )
686 {
687 for( j = 0; j < noperands; ++j )
688 vals[j] = (j <= rhs) ? 1.0 : -1.0;
689
690 SCIP_CALL( addLinearConstraint(scip, matrix, operands, vals, noperands, rhs, rhs, cons) );
691 }
692 else
693 {
694 /* long XOR constraints are represented nonlinearly, so the relevant active variables are marked non-linear */
695 SCIP_VAR** aggrvars;
697 SCIP_Real constant;
698 int naggrvars;
699 int col;
700
702 SCIP_CALL( SCIPallocBufferArray(scip, &aggrvars, matrix->ncols) );
703
704 /* we can transform all variables together in the sum because the constraint can be interpreted as a nonlinear
705 * constraint of the form sum(operands) % 2 = rhs. Thus, it is okay if we have cancellations in the sum.
706 */
707 for( j = 0; j < noperands; ++j )
708 {
709 scalars[j] = 1.0;
710 aggrvars[j] = operands[j];
711 }
712
713 naggrvars = noperands;
714 SCIP_CALL( getActiveVariables(scip, &aggrvars, &scalars, &naggrvars, &constant) );
715
716 for( k = 0; k < naggrvars; ++k )
717 {
718 /* if the variable has an even coefficient, it does not contribute to the modulo constraint */
719 if( !SCIPisIntegral(scip, 0.5 * scalars[k]) )
720 {
721 col = SCIPvarGetProbindex(aggrvars[k]);
722 assert(col >= 0);
723 assert(col < matrix->ncols);
724 matrix->colinnonlinterm[col] = TRUE;
725 }
726 }
727
728 SCIPfreeBufferArray(scip, &aggrvars);
730 }
731
733
734 return SCIP_OKAY;
735}
736
737/** transform row major format into column major format */
738static
740 SCIP* scip, /**< current scip instance */
741 IMPLINT_MATRIX* matrix /**< constraint matrix */
742 )
743{
744 SCIP_Real* valpnt;
745 int* rowpnt;
746 int* rowend;
747 int* fillidx;
748 int colidx;
749 int i;
750
751 assert(scip != NULL);
752 assert(matrix != NULL);
753 assert(matrix->colmatval != NULL);
754 assert(matrix->colmatind != NULL);
755 assert(matrix->colmatbeg != NULL);
756 assert(matrix->colmatcnt != NULL);
757 assert(matrix->rowmatval != NULL);
758 assert(matrix->rowmatind != NULL);
759 assert(matrix->rowmatbeg != NULL);
760 assert(matrix->rowmatcnt != NULL);
761
762 SCIP_CALL( SCIPallocBufferArray(scip, &fillidx, matrix->ncols) );
763 BMSclearMemoryArray(fillidx, matrix->ncols);
764 BMSclearMemoryArray(matrix->colmatcnt, matrix->ncols);
765
766 for( i = 0; i < matrix->nrows; ++i )
767 {
768 rowpnt = matrix->rowmatind + matrix->rowmatbeg[i];
769 rowend = rowpnt + matrix->rowmatcnt[i];
770 for( ; rowpnt < rowend; ++rowpnt )
771 {
772 colidx = *rowpnt;
773 ++matrix->colmatcnt[colidx];
774 }
775 }
776
777 matrix->colmatbeg[0] = 0;
778 for( i = 0; i < matrix->ncols - 1; ++i )
779 matrix->colmatbeg[i+1] = matrix->colmatbeg[i] + matrix->colmatcnt[i];
780
781 for( i = 0; i < matrix->nrows; ++i )
782 {
783 rowpnt = matrix->rowmatind + matrix->rowmatbeg[i];
784 rowend = rowpnt + matrix->rowmatcnt[i];
785 valpnt = matrix->rowmatval + matrix->rowmatbeg[i];
786
787 for( ; rowpnt != rowend; ++rowpnt, ++valpnt )
788 {
789 colidx = *rowpnt;
790 assert(colidx < matrix->ncols);
791 matrix->colmatind[matrix->colmatbeg[colidx] + fillidx[colidx]] = i;
792 matrix->colmatval[matrix->colmatbeg[colidx] + fillidx[colidx]] = *valpnt;
793 ++fillidx[colidx];
794 }
795 }
796
797 SCIPfreeBufferArray(scip, &fillidx);
798
799 return SCIP_OKAY;
800}
801
802/* @todo: skip construction of integral constraints if we do not run detection on integer variables */
803/* @todo: use symmetry constraints to guide variable ordering for integral columns because
804 * symmetric variables should always all be either network or non-network
805 */
806/** create the matrix from the current transformed problem */
807static
809 SCIP* scip, /**< the scip data structure */
810 IMPLINT_MATRIX** pmatrix /**< pointer to create the matrix at */
811 )
812{
813 SCIP_CONSHDLR** conshdlrs;
814 SCIP_VAR** vars;
815 IMPLINT_MATRIX* matrix;
816 SCIP_Bool success;
817 const char* conshdlrname;
818 int nconshdlrs;
819 int nmatrixrows;
820 int nconshdlrconss;
821 int nvars;
822 int nnonzstmp;
823 int i;
824 int j;
825
826 *pmatrix = NULL;
827
828 /* return if no variables or constraints are present */
829 if( SCIPgetNVars(scip) == 0 || SCIPgetNConss(scip) == 0 )
830 return SCIP_OKAY;
831
832 assert(SCIPgetNActivePricers(scip) == 0);
833
834 /* loop over all constraint handlers and collect the number of checked constraints that contribute rows
835 * to the matrix */
836 nconshdlrs = SCIPgetNConshdlrs(scip);
837 conshdlrs = SCIPgetConshdlrs(scip);
838 nmatrixrows = 0;
839 nnonzstmp = 0;
840
841 for( i = 0; i < nconshdlrs; ++i )
842 {
843 nconshdlrconss = SCIPconshdlrGetNCheckConss(conshdlrs[i]);
844
845 if( nconshdlrconss > 0 )
846 {
847 conshdlrname = SCIPconshdlrGetName(conshdlrs[i]);
848
849 /* constraint handlers which can always be represented by a single row */
850 if( strcmp(conshdlrname, "linear") == 0 || strcmp(conshdlrname, "knapsack") == 0
851 || strcmp(conshdlrname, "setppc") == 0 || strcmp(conshdlrname, "logicor") == 0
852 || strcmp(conshdlrname, "varbound") == 0 )
853 nmatrixrows += nconshdlrconss;
854 else if( strcmp(conshdlrname, "and") == 0 )
855 {
856 /* the linearization of AND constraints is modelled using n + 1 inequalities on n + 1 variables */
857 SCIP_CONS** checked = SCIPconshdlrGetCheckConss(conshdlrs[i]);
858 for( j = 0; j < nconshdlrconss; ++j )
859 {
860 int nandvars = SCIPgetNVarsAnd(scip, checked[j]);
861 nmatrixrows += nandvars + 1;
862 if( nandvars > 1 )
863 nnonzstmp += nandvars - 1;
864 }
865 }
866 else if( strcmp(conshdlrname, "or") == 0 )
867 {
868 /* the linearization of OR constraints is modelled using n + 1 inequalities on n + 1 variables */
869 SCIP_CONS** checked = SCIPconshdlrGetCheckConss(conshdlrs[i]);
870 for( j = 0; j < nconshdlrconss; ++j )
871 {
872 int norvars = SCIPgetNVarsOr(scip, checked[j]);
873 nmatrixrows += norvars + 1;
874 if( norvars > 1 )
875 nnonzstmp += norvars - 1;
876 }
877 }
878 else if( strcmp(conshdlrname, "xor") == 0 )
879 {
880 /* the relaxation of XOR constraints is handled differently depending on the integer variable and size:
881 * with integer variable or less than three variables, the representation is a single row;
882 * without integer variable and three variables, the convex hull of the constraint is added with four rows;
883 * otherwise, the constraint is considered nonlinear because the convex hull representation is exponential
884 */
885 SCIP_CONS** checked = SCIPconshdlrGetCheckConss(conshdlrs[i]);
886 for( j = 0; j < nconshdlrconss; ++j )
887 {
888 int nxorvars = SCIPgetNVarsXor(scip, checked[j]);
889 if( SCIPgetIntVarXor(scip, checked[j]) != NULL || nxorvars < 3 )
890 nmatrixrows += 1;
891 else if( nxorvars == 3 )
892 {
893 nmatrixrows += 4;
894 nnonzstmp += 6;
895 }
896 }
897 }
898 else
899 {
900 /* @todo: support symmetry, linking, sos1, sos2, bounddisjunction, nonlinear, indicator, superindicator conshdlrs */
901 return SCIP_OKAY;
902 }
903 }
904 }
905
906 if( nmatrixrows == 0 )
907 return SCIP_OKAY;
908
909 vars = SCIPgetVars(scip);
910 nvars = SCIPgetNVars(scip);
911
912 /* approximate number of nonzeros by taking for each variable the number of down- and uplocks;
913 * this counts nonzeros in equalities twice, but can be at most two times as high as the exact number
914 */
915 for( i = 0; i < nvars; ++i )
917
918 if( nnonzstmp == 0 )
919 return SCIP_OKAY;
920
921 success = TRUE;
922
923 /* build the matrix structure */
924 SCIP_CALL( SCIPallocBuffer(scip, pmatrix) );
925 matrix = *pmatrix;
926
927 SCIP_CALL( SCIPduplicateBufferArray(scip, &matrix->colvar, vars, nvars) );
928
929 matrix->ncols = nvars;
930 matrix->nnonzssize = nnonzstmp;
931 matrix->nnonzs = 0;
932 matrix->nrows = 0;
933
934 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->colmatval, nnonzstmp) );
935 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->colmatind, nnonzstmp) );
936 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->colmatbeg, matrix->ncols) );
937 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->colmatcnt, matrix->ncols) );
938 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->lb, matrix->ncols) );
939 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->ub, matrix->ncols) );
940 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->colintegral, matrix->ncols) );
943
944 /* init bounds */
945 for( i = 0; i < matrix->ncols; ++i )
946 {
947 matrix->lb[i] = SCIPvarGetLbGlobal(vars[i]);
948 matrix->ub[i] = SCIPvarGetUbGlobal(vars[i]);
949 matrix->colintegral[i] = SCIPvarIsIntegral(vars[i]);
950 matrix->colimplintegral[i] = SCIPvarIsImpliedIntegral(vars[i]);
951 matrix->colinnonlinterm[i] = FALSE;
952 }
953
954 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rowmatval, nnonzstmp) );
955 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rowmatind, nnonzstmp) );
956 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rowmatbeg, nmatrixrows) );
957 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rowmatcnt, nmatrixrows) );
958 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->lhs, nmatrixrows) );
959 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rhs, nmatrixrows) );
960 SCIP_CALL( SCIPallocBufferArray(scip, &matrix->rowcons, nmatrixrows) );
961
962 /* loop a second time over constraints handlers and add supported constraints to the matrix */
963 for( i = 0; i < nconshdlrs; ++i )
964 {
965 SCIP_CONS** conshdlrconss;
966 int c;
967 int v;
968
969 conshdlrname = SCIPconshdlrGetName(conshdlrs[i]);
970 conshdlrconss = SCIPconshdlrGetCheckConss(conshdlrs[i]);
971 nconshdlrconss = SCIPconshdlrGetNCheckConss(conshdlrs[i]);
972
973 if( strcmp(conshdlrname, "linear") == 0 )
974 {
975 for( c = 0; c < nconshdlrconss; ++c )
976 {
977 SCIP_CONS* cons = conshdlrconss[c];
978 assert(SCIPconsIsTransformed(cons));
979
980 if( SCIPconsIsModifiable(cons) )
981 {
982 success = FALSE;
983 break;
984 }
985
987 SCIPgetNVarsLinear(scip, cons), SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons), cons) );
988 }
989 }
990 else if( strcmp(conshdlrname, "knapsack") == 0 )
991 {
992 if( nconshdlrconss > 0 )
993 {
994 SCIP_Real* consvals;
995 int nrowvars;
996
997 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars) );
998
999 for( c = 0; c < nconshdlrconss; ++c )
1000 {
1001 SCIP_Longint* weights;
1002 SCIP_Real rhs;
1003 SCIP_CONS* cons = conshdlrconss[c];
1004 assert(SCIPconsIsTransformed(cons));
1005
1006 if( SCIPconsIsModifiable(cons) )
1007 {
1008 success = FALSE;
1009 break;
1010 }
1011 weights = SCIPgetWeightsKnapsack(scip, cons);
1012 nrowvars = SCIPgetNVarsKnapsack(scip, cons);
1013 for( v = 0; v < nrowvars; ++v )
1014 consvals[v] = (SCIP_Real)weights[v];
1015
1016 rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons);
1017 SCIP_CALL( addLinearConstraint(scip, matrix, SCIPgetVarsKnapsack(scip, cons), consvals, nrowvars,
1018 -SCIPinfinity(scip), rhs, cons) );
1019 }
1020
1021 SCIPfreeBufferArray(scip, &consvals);
1022 }
1023 }
1024 else if( strcmp(conshdlrname, "setppc") == 0 )
1025 {
1026 for( c = 0; c < nconshdlrconss; ++c )
1027 {
1028 SCIP_Real lhs;
1029 SCIP_Real rhs;
1030
1031 SCIP_CONS* cons = conshdlrconss[c];
1032 assert(SCIPconsIsTransformed(cons));
1033
1034 /* do not include constraints that can be altered due to column generation */
1035 if( SCIPconsIsModifiable(cons) )
1036 {
1037 success = FALSE;
1038 break;
1039 }
1040
1041 switch( SCIPgetTypeSetppc(scip, cons) )
1042 {
1044 lhs = 1.0;
1045 rhs = 1.0;
1046 break;
1048 lhs = -SCIPinfinity(scip);
1049 rhs = 1.0;
1050 break;
1052 lhs = 1.0;
1053 rhs = SCIPinfinity(scip);
1054 break;
1055 default:
1056 SCIPABORT();
1057 return SCIP_ERROR;
1058 }
1059
1061 SCIPgetNVarsSetppc(scip, cons), lhs, rhs, cons) );
1062 }
1063 }
1064 else if( strcmp(conshdlrname, "logicor") == 0 )
1065 {
1066 for( c = 0; c < nconshdlrconss; ++c )
1067 {
1068 SCIP_CONS* cons = conshdlrconss[c];
1069 assert(SCIPconsIsTransformed(cons));
1070
1071 if( SCIPconsIsModifiable(cons) )
1072 {
1073 success = FALSE;
1074 break;
1075 }
1076
1078 SCIPgetNVarsLogicor(scip, cons), 1.0, SCIPinfinity(scip), cons) );
1079 }
1080 }
1081 else if( strcmp(conshdlrname, "varbound") == 0 )
1082 {
1083 if( nconshdlrconss > 0 )
1084 {
1085 SCIP_VAR** consvars;
1086 SCIP_Real* consvals;
1087
1088 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) );
1089 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) );
1090
1091 for( c = 0; c < nconshdlrconss; ++c )
1092 {
1093 SCIP_CONS* cons = conshdlrconss[c];
1094 assert(SCIPconsIsTransformed(cons));
1095
1096 if( SCIPconsIsModifiable(cons) )
1097 {
1098 success = FALSE;
1099 break;
1100 }
1101
1102 consvars[0] = SCIPgetVarVarbound(scip, cons);
1103 consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
1104 consvals[0] = 1.0;
1105 consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
1106
1107 SCIP_CALL( addLinearConstraint(scip, matrix, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
1108 SCIPgetRhsVarbound(scip, cons), cons) );
1109 }
1110 SCIPfreeBufferArray(scip, &consvals);
1111 SCIPfreeBufferArray(scip, &consvars);
1112 }
1113 }
1114 else if( strcmp(conshdlrname, "and") == 0 )
1115 {
1116 for( c = 0; c < nconshdlrconss; ++c )
1117 {
1118 SCIP_CONS* cons = conshdlrconss[c];
1119 assert(SCIPconsIsTransformed(cons));
1120
1121 if( SCIPconsIsModifiable(cons) )
1122 {
1123 success = FALSE;
1124 break;
1125 }
1126
1129 }
1130 }
1131 else if( strcmp(conshdlrname, "or") == 0 )
1132 {
1133 for( c = 0; c < nconshdlrconss; ++c )
1134 {
1135 SCIP_CONS* cons = conshdlrconss[c];
1136 assert(SCIPconsIsTransformed(cons));
1137
1138 if( SCIPconsIsModifiable(cons) )
1139 {
1140 success = FALSE;
1141 break;
1142 }
1143
1144 SCIP_CALL( addAndOrLinearization(scip, matrix, cons, SCIPgetVarsOr(scip, cons),
1145 SCIPgetNVarsOr(scip, cons), SCIPgetResultantOr(scip, cons), FALSE) );
1146 }
1147 }
1148 else if( strcmp(conshdlrname, "xor") == 0 )
1149 {
1150 for( c = 0; c < nconshdlrconss; ++c )
1151 {
1152 SCIP_CONS* cons = conshdlrconss[c];
1153 assert(SCIPconsIsTransformed(cons));
1154
1155 if( SCIPconsIsModifiable(cons) )
1156 {
1157 success = FALSE;
1158 break;
1159 }
1160
1162 SCIPgetIntVarXor(scip, cons), (SCIP_Real) SCIPgetRhsXor(scip, cons)) );
1163 }
1164 }
1165 }
1166
1167 if( success )
1168 {
1170 /**@todo scale continuous columns by least common multiple of coefficients */
1171 }
1172 else
1173 {
1174 SCIPfreeBufferArray(scip, &matrix->rowcons);
1175 SCIPfreeBufferArray(scip, &matrix->rhs);
1176 SCIPfreeBufferArray(scip, &matrix->lhs);
1184 SCIPfreeBufferArray(scip, &matrix->ub);
1185 SCIPfreeBufferArray(scip, &matrix->lb);
1191 SCIPfreeBuffer(scip, pmatrix);
1192 }
1193
1194 return SCIP_OKAY;
1195}
1196
1197/** frees the matrix from memory */
1198static
1200 SCIP* scip, /**< the scip data structure */
1201 IMPLINT_MATRIX** pmatrix /**< pointer to the allocated matrix */
1202 )
1203{
1204 assert(scip != NULL);
1205 assert(pmatrix != NULL);
1206
1207 IMPLINT_MATRIX* matrix = *pmatrix;
1208
1209 if( matrix != NULL )
1210 {
1211 assert(matrix->colmatval != NULL);
1212 assert(matrix->colmatind != NULL);
1213 assert(matrix->colmatbeg != NULL);
1214 assert(matrix->colmatcnt != NULL);
1215 assert(matrix->lb != NULL);
1216 assert(matrix->ub != NULL);
1217 assert(matrix->colintegral != NULL);
1218 assert(matrix->colimplintegral != NULL);
1219 assert(matrix->rowmatval != NULL);
1220 assert(matrix->rowmatind != NULL);
1221 assert(matrix->rowmatbeg != NULL);
1222 assert(matrix->rowmatcnt != NULL);
1223 assert(matrix->lhs != NULL);
1224 assert(matrix->rhs != NULL);
1225
1226 SCIPfreeBufferArray(scip, &(matrix->rowcons));
1227 SCIPfreeBufferArray(scip, &(matrix->rhs));
1228 SCIPfreeBufferArray(scip, &(matrix->lhs));
1229 SCIPfreeBufferArray(scip, &(matrix->rowmatcnt));
1230 SCIPfreeBufferArray(scip, &(matrix->rowmatbeg));
1231 SCIPfreeBufferArray(scip, &(matrix->rowmatind));
1232 SCIPfreeBufferArray(scip, &(matrix->rowmatval));
1236 SCIPfreeBufferArray(scip, &(matrix->ub));
1237 SCIPfreeBufferArray(scip, &(matrix->lb));
1238 SCIPfreeBufferArray(scip, &(matrix->colmatcnt));
1239 SCIPfreeBufferArray(scip, &(matrix->colmatbeg));
1240 SCIPfreeBufferArray(scip, &(matrix->colmatind));
1241 SCIPfreeBufferArray(scip, &(matrix->colmatval));
1242
1243 matrix->nrows = 0;
1244 matrix->ncols = 0;
1245 matrix->nnonzs = 0;
1246
1247 SCIPfreeBufferArrayNull(scip, &(matrix->colvar));
1248 SCIPfreeBuffer(scip, &matrix);
1249 }
1250}
1251
1252/** creates the matrix components data structure */
1253static
1255 SCIP* scip, /**< SCIP data structure */
1256 IMPLINT_MATRIX * matrix, /**< The constraint matrix */
1257 MATRIX_COMPONENTS** pmatrixcomponents /**< Pointer to create the matrix components data structure */
1258 )
1259{
1260 int i;
1261
1262 SCIP_CALL( SCIPallocBuffer(scip, pmatrixcomponents) );
1263 MATRIX_COMPONENTS* comp = *pmatrixcomponents;
1264
1265 int nrows = matrixGetNRows(matrix);
1266 int ncols = matrixGetNCols(matrix);
1267
1268 comp->nmatrixrows = nrows;
1269 comp->nmatrixcols = ncols;
1270
1272 for( i = 0; i < nrows; ++i )
1273 {
1274 comp->rowcomponent[i] = -1;
1275 }
1277 for( i = 0; i < ncols; ++i )
1278 {
1279 comp->colcomponent[i] = -1;
1280 }
1281
1284 /* There will be at most ncols components */
1287
1288 comp->ncomponents = 0;
1289
1290 return SCIP_OKAY;
1291}
1292
1293/** frees the matrix components data structure */
1294static
1296 SCIP* scip, /**< SCIP data structure */
1297 MATRIX_COMPONENTS** pmatrixcomponents /**< Pointer to the allocated matrix components data structure */
1298 )
1299{
1300 MATRIX_COMPONENTS* comp = *pmatrixcomponents;
1301
1302 /* Make sure to free in reverse */
1309
1310 SCIPfreeBuffer(scip, pmatrixcomponents);
1311}
1312
1313/** finds the representative of an element in the disjoint set datastructure
1314 * Afterwards compresses the path to speed up subsequent queries.
1315 */
1316static
1318 int* disjointset, /**< The array storing the disjoint set representatives */
1319 int ind /**< The index to find */
1320 )
1321{
1322 assert(disjointset != NULL);
1323
1324 int current = ind;
1325 int next;
1326 /* traverse down tree */
1327 while( (next = disjointset[current]) >= 0 )
1328 {
1329 current = next;
1330 }
1331 int root = current;
1332
1333 /* compress indices along path */
1334 current = ind;
1335 while( (next = disjointset[current]) >= 0 )
1336 {
1337 disjointset[current] = root;
1338 current = next;
1339 }
1340
1341 return root;
1342}
1343
1344/** merges two sets/elements into one set. Returns the index of the merged element
1345 * The provided elements to be merged must be representative (i.e. returned by disjointSetFind()).
1346 */
1347static
1349 int* disjointset, /**< The array storing the disjoint set representatives */
1350 int first, /**< The first index to merge */
1351 int second /**< The second index to merge */
1352 )
1353{
1354 assert(disjointset);
1355 assert(disjointset[first] <= -1);
1356 assert(disjointset[second] <= -1);
1357 assert(first != second); /* We cannot merge a node into itself */
1358
1359 /* The rank is stored as a negative number: we decrement it making the negative number larger.
1360 * The rank is an upper bound on the height of the tree. We want the new root to be the one with 'largest' rank,
1361 * so smallest number. This way, we ensure that the tree remains shallow. If they are equal, we decrement.
1362 */
1363 int firstRank = disjointset[first];
1364 int secondRank = disjointset[second];
1365 if( firstRank > secondRank )
1366 {
1367 SCIPswapInts(&first, &second);
1368 }
1369 /* first becomes representative */
1370 disjointset[second] = first;
1371 if( firstRank == secondRank )
1372 {
1373 --disjointset[first];
1374 }
1375
1376 return first;
1377}
1378
1379/** computes the connected components of the submatrix given by all continuous columns */
1380static
1382 SCIP* scip, /**< SCIP data structure */
1383 IMPLINT_MATRIX* matrix, /**< the constraint matrix to compute the components for */
1384 MATRIX_COMPONENTS* comp, /**< the connected components data structure to store the components in */
1385 SCIP_Bool includeimplints /**< should implied integral variables be treated continuous? */
1386 )
1387{
1388 int* disjointset;
1389 int* representativecomponent;
1390 int* componentnextrowindex;
1391 int* componentnextcolindex;
1392 int col;
1393 int row;
1394 int i;
1395
1396 /* let columns and rows share an index by mapping row index i to artificial column index i + nmatrixcols */
1397 SCIP_CALL( SCIPallocBufferArray(scip, &disjointset, comp->nmatrixcols + comp->nmatrixrows) );
1398 for( i = 0; i < comp->nmatrixcols + comp->nmatrixrows; ++i )
1399 disjointset[i] = -1;
1400
1401 for( col = 0; col < comp->nmatrixcols; ++col )
1402 {
1403 if( matrixColIsIntegral(matrix, col) && ( !includeimplints || !matrixColIsImpliedIntegral(matrix, col) ) )
1404 continue;
1405
1406 int* colrows = matrixGetColumnInds(matrix, col);
1407 int colnnonzs = matrixGetColumnNNonzs(matrix, col);
1408 int colrep = disjointSetFind(disjointset, col);
1409
1410 for( i = 0; i < colnnonzs; ++i )
1411 {
1412 int colrow = colrows[i];
1413 int ind = colrow + comp->nmatrixcols;
1414 int rowrep = disjointSetFind(disjointset, ind);
1415
1416 if( colrep != rowrep )
1417 colrep = disjointSetMerge(disjointset, colrep, rowrep);
1418 }
1419 }
1420
1421 /* fill in the relevant data */
1422 SCIP_CALL( SCIPallocBufferArray(scip, &representativecomponent, comp->nmatrixcols + comp->nmatrixrows) );
1423 for( i = 0; i < comp->nmatrixcols + comp->nmatrixrows; ++i )
1424 representativecomponent[i] = -1;
1425
1426 comp->ncomponents = 0;
1427
1428 for( col = 0; col < comp->nmatrixcols; ++col )
1429 {
1430 if( matrixColIsIntegral(matrix,col) && ( !includeimplints || !matrixColIsImpliedIntegral(matrix, col) ) )
1431 continue;
1432
1433 int colroot = disjointSetFind(disjointset, col);
1434 int component = representativecomponent[colroot];
1435
1436 /* add new component */
1437 if( component < 0 )
1438 {
1439 assert(component == -1);
1440 component = comp->ncomponents;
1441 representativecomponent[colroot] = component;
1442 comp->componentcolend[component] = 0;
1443 comp->componentrowend[component] = 0;
1444 ++comp->ncomponents;
1445 }
1446
1447 comp->colcomponent[col] = component;
1448 ++comp->componentcolend[component];
1449 }
1450
1451 for( row = 0; row < comp->nmatrixrows; ++row )
1452 {
1453 int rowroot = disjointSetFind(disjointset, row + comp->nmatrixcols);
1454 int component = representativecomponent[rowroot];
1455
1456 /* any unseen row can be skipped because it has no continuous column */
1457 if( component < 0 )
1458 {
1459 assert(component == -1);
1460 continue;
1461 }
1462
1463 comp->rowcomponent[row] = component;
1464 ++comp->componentrowend[component];
1465 }
1466
1467 if( comp->ncomponents >= 1 )
1468 {
1469 for( i = 1; i < comp->ncomponents; ++i )
1470 {
1471 comp->componentcolend[i] += comp->componentcolend[i - 1];
1472 comp->componentrowend[i] += comp->componentrowend[i - 1];
1473 }
1474
1475 SCIP_CALL( SCIPallocBufferArray(scip, &componentnextcolindex, comp->ncomponents) );
1476 SCIP_CALL( SCIPallocBufferArray(scip, &componentnextrowindex, comp->ncomponents) );
1477
1478 componentnextcolindex[0] = 0;
1479 componentnextrowindex[0] = 0;
1480
1481 for( i = 1; i < comp->ncomponents; ++i )
1482 {
1483 componentnextcolindex[i] = comp->componentcolend[i - 1];
1484 componentnextrowindex[i] = comp->componentrowend[i - 1];
1485 }
1486
1487 for( col = 0; col < comp->nmatrixcols; ++col )
1488 {
1489 int component = comp->colcomponent[col];
1490
1491 if( component < 0 )
1492 {
1493 assert(component == -1);
1494 continue;
1495 }
1496
1497 comp->componentcols[componentnextcolindex[component]] = col;
1498 ++componentnextcolindex[component];
1499 }
1500
1501 for( row = 0; row < comp->nmatrixrows; ++row )
1502 {
1503 int component = comp->rowcomponent[row];
1504
1505 if( component < 0 )
1506 {
1507 assert(component == -1);
1508 continue;
1509 }
1510
1511 comp->componentrows[componentnextrowindex[component]] = row;
1512 ++componentnextrowindex[component];
1513 }
1514
1515#ifndef NDEBUG
1516 for( i = 0; i < comp->ncomponents; ++i )
1517 {
1518 assert(componentnextcolindex[i] == comp->componentcolend[i]);
1519 assert(componentnextrowindex[i] == comp->componentrowend[i]);
1520 }
1521#endif
1522
1523 SCIPfreeBufferArray(scip, &componentnextrowindex);
1524 SCIPfreeBufferArray(scip, &componentnextcolindex);
1525 }
1526
1527 SCIPfreeBufferArray(scip, &representativecomponent);
1528 SCIPfreeBufferArray(scip, &disjointset);
1529
1530 return SCIP_OKAY;
1531}
1532
1533/** creates the matrix statistics data structure */
1534static
1536 SCIP* scip, /**< SCIP data structure */
1537 IMPLINT_MATRIX* matrix, /**< The constraint matrix to compute the statistics for */
1538 MATRIX_STATISTICS** pstats, /**< Pointer to allocate the statistics data structure at */
1539 SCIP_Real numericslimit /**< The limit beyond which we consider integrality of coefficients
1540 * to be unreliable */
1541 )
1542{
1543 int i;
1544 int j;
1545
1546 SCIP_CALL( SCIPallocBuffer(scip, pstats) );
1547 MATRIX_STATISTICS* stats = *pstats;
1548
1549 int nrows = matrixGetNRows(matrix);
1550 int ncols = matrixGetNCols(matrix);
1551
1552 SCIP_CALL( SCIPallocBufferArray(scip, &stats->rowintegral, nrows) );
1553 SCIP_CALL( SCIPallocBufferArray(scip, &stats->rowequality, nrows) );
1555
1556 SCIP_CALL( SCIPallocBufferArray(scip, &stats->rownnonz, nrows) );
1559
1561
1562 for( i = 0; i < nrows; ++i )
1563 {
1564 SCIP_Real lhs = matrixGetRowLhs(matrix, i);
1565 SCIP_Real rhs = matrixGetRowRhs(matrix, i);
1566 int* cols = matrixGetRowInds(matrix, i);
1567 SCIP_Real* vals = matrixGetRowVals(matrix, i);
1568 int nnonz = matrixGetRowNNonzs(matrix, i);
1569 stats->rownnonz[i] = nnonz;
1570 stats->rowequality[i] = !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && SCIPisEQ(scip, lhs, rhs);
1571
1572 SCIP_Bool integral = ( SCIPisInfinity(scip, -lhs) || SCIPisIntegral(scip, lhs) )
1573 && ( SCIPisInfinity(scip, rhs) || SCIPisIntegral(scip, rhs) );
1574 SCIP_Bool badnumerics = FALSE;
1575
1576 int ncontinuous = 0;
1577 int ncontinuouspmone = 0;
1578 for( j = 0; j < nnonz; ++j )
1579 {
1580 SCIP_Bool continuous = !matrixColIsIntegral(matrix, cols[j]);
1581 SCIP_Real value = vals[j];
1582 if( continuous )
1583 {
1584 ++ncontinuous;
1585 if( SCIPisEQ(scip, ABS(value), 1.0) )
1586 {
1587 ++ncontinuouspmone;
1588 }
1589 }
1590 else
1591 {
1592 /* @todo for exact version of plugin, adjust to tight check */
1593 integral = integral && SCIPisIntegral(scip, value);
1594 }
1595 if( ABS(value) > numericslimit )
1596 {
1597 badnumerics = TRUE;
1598 }
1599 }
1600
1601 stats->rowncontinuous[i] = ncontinuous;
1602 stats->rowncontinuouspmone[i] = ncontinuouspmone;
1603 stats->rowintegral[i] = integral;
1604 stats->rowbadnumerics[i] = badnumerics;
1605 }
1606
1607 for( i = 0; i < ncols; ++i )
1608 {
1609 SCIP_Real lb = matrixGetColLb(matrix, i);
1610 SCIP_Real ub = matrixGetColUb(matrix, i);
1611 /* @todo for exact version of plugin, adjust to tight check */
1612 stats->colintegralbounds[i] = ( SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb) )
1613 && ( SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub) );
1614
1615 /* Check that integer variables have integer bounds, as expected. */
1616 assert(!matrixColIsIntegral(matrix, i) || stats->colintegralbounds[i]);
1617 }
1618
1619 return SCIP_OKAY;
1620}
1621
1622/** frees the matrix statistics data structure */
1623static
1625 SCIP* scip, /**< SCIP data structure */
1626 MATRIX_STATISTICS** pstats /**< Pointer to the statistics data structure to be freed */
1627 )
1628{
1629 MATRIX_STATISTICS* stats= *pstats;
1630
1631 /* Make sure, for performance, that these frees occur in reverse */
1639
1640 SCIPfreeBuffer(scip, pstats);
1641}
1642
1643/** detects components of implied integral variables
1644 * Given the continuous components and statistics on the matrix, each component is checked if the associated matrix
1645 * describes either a network or a transposed network (or both, in which case it is represented by a planar graph) and
1646 * whether bounds/sides/coefficients are integral.
1647 * We choose to check if it is a (transposed) network matrix either in a row-wise or in a column-wise fashion,
1648 * depending on the size of the component. Finally, every variable that is in a network matrix or transposed network
1649 * matrix is derived to be weakly implied integral.
1650 */
1651static
1653 SCIP* scip, /**< SCIP data structure */
1654 SCIP_PRESOLDATA* presoldata, /**< data belonging to the presolver */
1655 IMPLINT_MATRIX* matrix, /**< constraint matrix to compute implied integral variables for */
1656 MATRIX_COMPONENTS* comp, /**< continuous connected components of the matrix */
1657 MATRIX_STATISTICS* stats, /**< statistics of the matrix */
1658 int* nchgvartypes /**< pointer to count the number of changed variable types */
1659 )
1660{
1661 assert(presoldata != NULL);
1662
1663 SCIP_NETMATDEC* dec = NULL;
1664 SCIP_NETMATDEC* transdec = NULL;
1665 SCIP_Real* tempValArray;
1666 SCIP_Bool* compNetworkValid;
1667 SCIP_Bool* compTransNetworkValid;
1668 SCIP_Bool runintdetection = presoldata->convertintegers && SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) >= 1;
1669 int* tempIdxArray;
1670 int component;
1671 int col;
1672 int row;
1673 int i;
1674 int j;
1675
1676 /* TODO: some checks to prevent expensive memory initialization if not necessary.
1677 * For example, make sure that there exist some +-1 candidate columns exist before performing these allocations.
1678 */
1681
1682 /* Because the rows may also contain non-continuous columns, we need to remove these from the array that we
1683 * pass to the network matrix decomposition method. We use these working arrays for this purpose.
1684 */
1685 SCIP_CALL( SCIPallocBufferArray(scip, &tempValArray, comp->nmatrixcols) );
1686 SCIP_CALL( SCIPallocBufferArray(scip, &tempIdxArray, comp->nmatrixcols) );
1687 SCIP_CALL( SCIPallocBufferArray(scip, &compNetworkValid, comp->ncomponents) );
1688 SCIP_CALL( SCIPallocBufferArray(scip, &compTransNetworkValid, comp->ncomponents) );
1689
1690 for( component = 0; component < comp->ncomponents; ++component )
1691 {
1692 int startrow = (component == 0) ? 0 : comp->componentrowend[component - 1];
1693 int nrows = comp->componentrowend[component] - startrow;
1694 SCIP_Bool componentokay = TRUE;
1695
1696 for( i = startrow; i < startrow + nrows; ++i )
1697 {
1698 row = comp->componentrows[i];
1699
1700 if( stats->rowncontinuous[row] != stats->rowncontinuouspmone[row] || !stats->rowintegral[row] || stats->rowbadnumerics[row] )
1701 {
1702 componentokay = FALSE;
1703 break;
1704 }
1705 }
1706
1707 if( !componentokay )
1708 {
1709 compNetworkValid[component] = FALSE;
1710 compTransNetworkValid[component] = FALSE;
1711 continue;
1712 }
1713
1714 int startcol = (component == 0) ? 0 : comp->componentcolend[component - 1];
1715 int ncols = comp->componentcolend[component] - startcol;
1716
1717 for( i = startcol; i < startcol + ncols; ++i )
1718 {
1719 col = comp->componentcols[i];
1720
1721 if( !stats->colintegralbounds[col] || matrixColInNonlinearTerm(matrix, col) )
1722 {
1723 componentokay = FALSE;
1724 break;
1725 }
1726 }
1727
1728 if( !componentokay )
1729 {
1730 compNetworkValid[component] = FALSE;
1731 compTransNetworkValid[component] = FALSE;
1732 continue;
1733 }
1734
1735 /* check if the component is a network matrix */
1736 SCIP_Bool componentnetwork = TRUE;
1737
1738 /* We use the row-wise algorithm only if the number of columns is much larger than the number of rows.
1739 * Generally, the column-wise algorithm will be faster, but in these extreme cases, the row algorithm is faster.
1740 * Only very few instances should use the row-wise algorithm.
1741 */
1742 if( nrows * presoldata->columnrowratio < ncols )
1743 {
1744 for( i = startrow; i < startrow + nrows && componentnetwork; ++i )
1745 {
1746 row = comp->componentrows[i];
1747 SCIP_Real* rowvals = matrixGetRowVals(matrix, row);
1748 int* rowcols = matrixGetRowInds(matrix, row);
1749 int rownnonzs = matrixGetRowNNonzs(matrix, row);
1750 int contnnonzs = 0;
1751
1752 for( j = 0; j < rownnonzs; ++j )
1753 {
1754 int rowcol = rowcols[j];
1755
1756 if( !matrixColIsIntegral(matrix, rowcol) )
1757 {
1758 tempIdxArray[contnnonzs] = rowcol;
1759 tempValArray[contnnonzs] = rowvals[j];
1760 ++contnnonzs;
1761 assert(SCIPisEQ(scip, ABS(rowvals[j]), 1.0));
1762 }
1763 }
1764
1765 SCIP_CALL( SCIPnetmatdecTryAddRow(dec, row, tempIdxArray, tempValArray, contnnonzs, &componentnetwork) );
1766 }
1767 }
1768 else
1769 {
1770 for( i = startcol; i < startcol + ncols && componentnetwork; ++i )
1771 {
1772 col = comp->componentcols[i];
1773 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
1774 int* colrows = matrixGetColumnInds(matrix, col);
1775 int colnnonzs = matrixGetColumnNNonzs(matrix, col);
1776
1777 SCIP_CALL( SCIPnetmatdecTryAddCol(dec, col, colrows, colvals, colnnonzs, &componentnetwork) );
1778 }
1779 }
1780
1781 if( !componentnetwork )
1782 SCIPnetmatdecRemoveComponent(dec, &comp->componentrows[startrow], nrows, &comp->componentcols[startcol], ncols);
1783
1784 compNetworkValid[component] = componentnetwork;
1785
1786 /* we don't need to check if component is both network and transposed network in case we do not want to extend
1787 * implied integrality to the enforced integeral variables
1788 */
1789 if( componentnetwork && !runintdetection )
1790 {
1791 compTransNetworkValid[component] = FALSE;
1792 continue;
1793 }
1794
1795 SCIP_Bool componenttransnetwork = TRUE;
1796
1797 /* for the transposed matrix, the situation is exactly reversed because the row/column algorithms are swapped */
1798 if( nrows <= ncols * presoldata->columnrowratio )
1799 {
1800 for( i = startrow; i < startrow + nrows && componenttransnetwork; ++i )
1801 {
1802 row = comp->componentrows[i];
1803 SCIP_Real* rowvals = matrixGetRowVals(matrix, row);
1804 int* rowcols = matrixGetRowInds(matrix, row);
1805 int rownnonzs = matrixGetRowNNonzs(matrix, row);
1806 int contnnonzs = 0;
1807
1808 for( j = 0; j < rownnonzs; ++j )
1809 {
1810 int rowcol = rowcols[j];
1811
1812 if( !matrixColIsIntegral(matrix, rowcol) )
1813 {
1814 tempIdxArray[contnnonzs] = rowcol;
1815 tempValArray[contnnonzs] = rowvals[j];
1816 ++contnnonzs;
1817 assert(SCIPisEQ(scip, ABS(rowvals[j]), 1.0));
1818 }
1819 }
1820
1821 SCIP_CALL( SCIPnetmatdecTryAddCol(transdec, row, tempIdxArray, tempValArray, contnnonzs, &componenttransnetwork) );
1822 }
1823 }
1824 else
1825 {
1826 for( i = startcol; i < startcol + ncols && componenttransnetwork; ++i )
1827 {
1828 col = comp->componentcols[i];
1829 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
1830 int* colrows = matrixGetColumnInds(matrix, col);
1831 int colnnonzs = matrixGetColumnNNonzs(matrix, col);
1832
1833 SCIP_CALL( SCIPnetmatdecTryAddRow(transdec, col, colrows, colvals, colnnonzs, &componenttransnetwork) );
1834 }
1835 }
1836
1837 if( !componenttransnetwork )
1838 SCIPnetmatdecRemoveComponent(transdec, &comp->componentcols[startcol], ncols, &comp->componentrows[startrow], nrows);
1839
1840 compTransNetworkValid[component] = componenttransnetwork;
1841 }
1842
1843 /* add continuous columns; here we can take both normal or transposed components */
1844 for( component = 0; component < comp->ncomponents; ++component )
1845 {
1846 if( !compNetworkValid[component] && !compTransNetworkValid[component] )
1847 continue;
1848
1849 int startcol = (component == 0) ? 0 : comp->componentcolend[component - 1];
1850 int endcol = comp->componentcolend[component];
1851
1852 for( i = startcol; i < endcol; ++i )
1853 {
1854 col = comp->componentcols[i];
1855 assert(SCIPnetmatdecContainsColumn(dec, col) || SCIPnetmatdecContainsRow(transdec, col));
1856 SCIP_VAR* var = matrixGetVar(matrix, col);
1857 assert(!SCIPvarIsIntegral(var));
1858 SCIP_Bool infeasible;
1859
1861 assert(!infeasible);
1862 ++(*nchgvartypes);
1863 }
1864 }
1865
1866 /* detect implied integrality for integer columns; first, we compute valid columns that have only +-1 entries in
1867 * rows that are integral; then, we sort these and greedily attempt to add them to the (transposed) network matrix
1868 */
1869 if( runintdetection )
1870 {
1871 MATRIX_COMPONENTS* implintcomp;
1872 SCIP_Bool* implCompNetworkValid;
1873 SCIP_Bool* implCompTransNetworkValid;
1874
1875 /**@todo avoid work when there is no implied integer variables by taking the original components instead */
1876 SCIP_CALL( createMatrixComponents(scip, matrix, &implintcomp) );
1877 SCIP_CALL( computeContinuousComponents(scip, matrix, implintcomp, TRUE) );
1878
1879 SCIP_CALL( SCIPallocBufferArray(scip, &implCompNetworkValid, implintcomp->ncomponents) );
1880 SCIP_CALL( SCIPallocBufferArray(scip, &implCompTransNetworkValid, implintcomp->ncomponents) );
1881
1882 /* extend network and transposed network decomposition by missing implied integral columns */
1883 for( component = 0; component < implintcomp->ncomponents; ++component )
1884 {
1885 SCIP_Bool componentnetwork = TRUE;
1886 SCIP_Bool componenttransnetwork = TRUE;
1887
1888 int startrow = (component == 0) ? 0 : implintcomp->componentrowend[component - 1];
1889 int endrow = implintcomp->componentrowend[component];
1890
1891 for( i = startrow; i < endrow; ++i )
1892 {
1893 row = implintcomp->componentrows[i];
1894 int contcomponent = comp->rowcomponent[row];
1895
1896 /* integrality and numerics of rows in continuous components is already checked */
1897 if( contcomponent != -1 )
1898 {
1899 componentnetwork = componentnetwork && compNetworkValid[contcomponent];
1900 componenttransnetwork = componenttransnetwork && compTransNetworkValid[contcomponent];
1901 }
1902 else if( !stats->rowintegral[row] || stats->rowbadnumerics[row] )
1903 {
1904 componentnetwork = FALSE;
1905 componenttransnetwork = FALSE;
1906 break;
1907 }
1908 }
1909
1910 if( !componentnetwork && !componenttransnetwork )
1911 {
1912 implCompNetworkValid[component] = FALSE;
1913 implCompTransNetworkValid[component] = FALSE;
1914 continue;
1915 }
1916
1917 int startcol = (component == 0) ? 0 : implintcomp->componentcolend[component - 1];
1918 int endcol = implintcomp->componentcolend[component];
1919
1920 for( i = startcol; i < endcol; ++i )
1921 {
1922 col = implintcomp->componentcols[i];
1923 int contcomponent = comp->colcomponent[col];
1924
1925 /* unity and linearity of columns in continuous components is already checked */
1926 if( contcomponent != -1 )
1927 {
1928 componentnetwork = componentnetwork && compNetworkValid[contcomponent];
1929 componenttransnetwork = componenttransnetwork && compTransNetworkValid[contcomponent];
1930 }
1931 else
1932 {
1933 assert(stats->colintegralbounds[col]);
1934
1935 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
1936 int colnnonz = matrixGetColumnNNonzs(matrix, col);
1937 SCIP_Bool implpmone = !matrixColInNonlinearTerm(matrix, col);
1938
1939 for( j = 0; j < colnnonz && implpmone; ++j )
1940 {
1941 if( !SCIPisEQ(scip, ABS(colvals[j]), 1.0) )
1942 implpmone = FALSE;
1943 }
1944
1945 if( !implpmone )
1946 {
1947 componentnetwork = FALSE;
1948 componenttransnetwork = FALSE;
1949 break;
1950 }
1951 }
1952 }
1953
1954 if( !componentnetwork && !componenttransnetwork )
1955 {
1956 implCompNetworkValid[component] = FALSE;
1957 implCompTransNetworkValid[component] = FALSE;
1958 continue;
1959 }
1960
1961 /* try extending the network and transposed network by the implied integral columns of the component */
1962 for( i = startcol; i < endcol; ++i )
1963 {
1964 col = implintcomp->componentcols[i];
1965 int contcomponent = comp->colcomponent[col];
1966
1967 if( contcomponent != -1 )
1968 {
1969 assert(!matrixColIsIntegral(matrix, col));
1970 continue;
1971 }
1972 assert(matrixColIsImpliedIntegral(matrix, col));
1973
1974 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
1975 int* colrows = matrixGetColumnInds(matrix, col);
1976 int colnnonz = matrixGetColumnNNonzs(matrix, col);
1977
1978 /* If a column can not be added, this does not invalidate implied integrality but means that the
1979 * integrality constraints of adjacent columns may be required for a differnt reason. Thus, we do not need
1980 * to remove components here altogether, like we did before.
1981 */
1982 if( componentnetwork )
1983 {
1984 assert(!SCIPnetmatdecContainsColumn(dec, col));
1985 SCIP_CALL( SCIPnetmatdecTryAddCol(dec, col, colrows, colvals, colnnonz, &componentnetwork) );
1986 }
1987
1988 if( componenttransnetwork )
1989 {
1990 assert(!SCIPnetmatdecContainsRow(transdec, col));
1991 SCIP_CALL( SCIPnetmatdecTryAddRow(transdec, col, colrows, colvals, colnnonz, &componenttransnetwork) );
1992 }
1993
1994 if( !componentnetwork && !componenttransnetwork )
1995 break;
1996 }
1997
1998 implCompNetworkValid[component] = componentnetwork;
1999 implCompTransNetworkValid[component] = componenttransnetwork;
2000 }
2001
2002 INTEGER_CANDIDATE_DATA* candidates;
2003 int numCandidates = 0;
2004
2005 SCIP_CALL( SCIPallocBufferArray(scip, &candidates, comp->nmatrixcols) );
2006
2007 /* candidates are non-implied integral columns with +- 1 entries without any nonzeros in bad rows */
2008 for( col = 0; col < comp->nmatrixcols; ++col )
2009 {
2010 if( !SCIPvarIsNonimpliedIntegral(matrixGetVar(matrix, col)) || matrixColInNonlinearTerm(matrix, col) )
2011 continue;
2012 assert(matrixColIsIntegral(matrix, col));
2013
2014 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
2015 int* colrows = matrixGetColumnInds(matrix, col);
2016 int colnnonz = matrixGetColumnNNonzs(matrix, col);
2017 INTEGER_CANDIDATE_DATA* data = candidates + numCandidates;
2018 SCIP_Bool badColumn = FALSE;
2019
2020 data->column = col;
2021 data->numContNetworkEntries = 0;
2022 data->numContPlanarEntries = 0;
2024
2025 for( i = 0; i < colnnonz; ++i )
2026 {
2027 int colrow = colrows[i];
2028
2029 if( !stats->rowintegral[colrow] || stats->rowbadnumerics[colrow]
2030 || !SCIPisEQ(scip, ABS(colvals[i]), 1.0) )
2031 {
2032 badColumn = TRUE;
2033 break;
2034 }
2035
2036 int rowcomponent = implintcomp->rowcomponent[colrow];
2037
2038 if( rowcomponent != -1 )
2039 {
2040 SCIP_Bool networkValid = implCompNetworkValid[rowcomponent];
2041 SCIP_Bool transNetworkValid = implCompTransNetworkValid[rowcomponent];
2042
2043 if( networkValid && transNetworkValid )
2044 ++data->numContPlanarEntries;
2045 else if( networkValid )
2046 ++data->numContNetworkEntries;
2047 else if( transNetworkValid )
2049 else
2050 {
2051 badColumn = TRUE;
2052 break;
2053 }
2054 }
2055 }
2056
2057 if( badColumn )
2058 continue;
2059
2060 ++numCandidates;
2061 }
2062
2063 SCIP_Real* candidateScores;
2064
2065 SCIP_CALL( SCIPallocBufferArray(scip, &candidateScores, numCandidates) );
2066
2067 /* higher score: pick this variable first */
2068 for( i = 0; i < numCandidates; ++i )
2069 {
2070 col = candidates[i].column;
2071 int nnonzs = matrixGetColumnNNonzs(matrix, col);
2072
2073 /* @TODO test different scores / alternatives */
2074 /* we generally prefer to detect implied integrality of general integer variables over binary variables */
2075 if( SCIPvarGetType(matrixGetVar(matrix, col)) == SCIP_VARTYPE_BINARY )
2076 candidateScores[i] = 10.0;
2077 else
2078 {
2079 assert(SCIPvarGetType(matrixGetVar(matrix, col)) == SCIP_VARTYPE_INTEGER);
2080 candidateScores[i] = 100.0;
2081 }
2082
2083 /* we break ties using the number of nonzeros in the column */
2084 candidateScores[i] -= 0.001 * nnonzs;
2085
2086 /* @TODO detect when all columns only extend the network / transposed components, then we can take both */
2087 }
2088
2089 int* indArray;
2090 int integerNetwork = 0;
2091 int integerTransNetwork = 0;
2092
2093 SCIP_CALL( SCIPallocBufferArray(scip, &indArray, numCandidates) );
2094
2095 for( i = 0; i < numCandidates; ++i )
2096 indArray[i] = i;
2097
2098 SCIPsortDownRealInt(candidateScores, indArray, numCandidates);
2099
2100 for( i = 0; i < numCandidates; ++i )
2101 {
2102 INTEGER_CANDIDATE_DATA* candidate = candidates + indArray[i];
2103
2104 if( candidate->numContTransNetworkEntries == 0 )
2105 {
2106 col = candidate->column;
2107 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
2108 int* colrows = matrixGetColumnInds(matrix, col);
2109 int colnnonz = matrixGetColumnNNonzs(matrix, col);
2110 SCIP_Bool success;
2111
2112 SCIP_CALL( SCIPnetmatdecTryAddCol(dec, col, colrows, colvals, colnnonz, &success) );
2113
2114 if( success )
2115 ++integerNetwork;
2116 }
2117
2118 if( candidate->numContNetworkEntries == 0 )
2119 {
2120 col = candidate->column;
2121 SCIP_Real* colvals = matrixGetColumnVals(matrix, col);
2122 int* colrows = matrixGetColumnInds(matrix, col);
2123 int colnnonz = matrixGetColumnNNonzs(matrix, col);
2124 SCIP_Bool success;
2125
2126 SCIP_CALL( SCIPnetmatdecTryAddRow(transdec, col, colrows, colvals, colnnonz, &success) );
2127
2128 if( success )
2129 ++integerTransNetwork;
2130 }
2131 }
2132
2133 /* we add all enforced integral columns from the network matrix */
2134 if( integerNetwork >= integerTransNetwork )
2135 {
2136 for( i = 0; i < numCandidates; ++i )
2137 {
2138 col = candidates[indArray[i]].column;
2139
2140 if( SCIPnetmatdecContainsColumn(dec, col) )
2141 {
2142 SCIP_VAR* var = matrixGetVar(matrix, col);
2143 assert(SCIPvarIsNonimpliedIntegral(var));
2144 SCIP_Bool infeasible;
2145
2147 assert(!infeasible);
2148 ++(*nchgvartypes);
2149 }
2150 }
2151 }
2152 /* we add all enforced integral columns from the transposed network matrix */
2153 else
2154 {
2155 for( i = 0; i < numCandidates; ++i )
2156 {
2157 col = candidates[indArray[i]].column;
2158
2159 if( SCIPnetmatdecContainsRow(transdec, col) )
2160 {
2161 SCIP_VAR* var = matrixGetVar(matrix, col);
2162 assert(SCIPvarIsNonimpliedIntegral(var));
2163 SCIP_Bool infeasible = FALSE;
2164
2166 assert(!infeasible);
2167 ++(*nchgvartypes);
2168 }
2169 }
2170 }
2171
2172 SCIPfreeBufferArray(scip, &indArray);
2173 SCIPfreeBufferArray(scip, &candidateScores);
2174 SCIPfreeBufferArray(scip, &candidates);
2175
2176 SCIPfreeBufferArray(scip, &implCompTransNetworkValid);
2177 SCIPfreeBufferArray(scip, &implCompNetworkValid);
2178 freeMatrixComponents(scip, &implintcomp);
2179 }
2180
2181 SCIPfreeBufferArray(scip, &compTransNetworkValid);
2182 SCIPfreeBufferArray(scip, &compNetworkValid);
2183 SCIPfreeBufferArray(scip, &tempIdxArray);
2184 SCIPfreeBufferArray(scip, &tempValArray);
2185 SCIPnetmatdecFree(&transdec);
2186 SCIPnetmatdecFree(&dec);
2187
2188 return SCIP_OKAY;
2189}
2190
2191/*
2192 * Callback methods of presolver
2193 */
2194
2195/** copy method for presolver plugins (called when SCIP copies plugins) */
2196static
2197SCIP_DECL_PRESOLCOPY(presolCopyImplint)
2198{ /*lint --e{715}*/
2199 SCIP_PRESOLDATA* sourcepresoldata;
2200 SCIP_PRESOLDATA* targetpresoldata;
2201
2202 assert(scip != NULL);
2203 assert(presol != NULL);
2204 assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0);
2205
2206 /* call inclusion method of presolver */
2208
2209 /* copy computedimplints flag */
2210 sourcepresoldata = SCIPpresolGetData(presol);
2211 assert(sourcepresoldata != NULL);
2212 targetpresoldata = SCIPpresolGetData(SCIPfindPresol(scip, PRESOL_NAME));
2213 assert(targetpresoldata != NULL);
2214 targetpresoldata->computedimplints = sourcepresoldata->computedimplints;
2215
2216 return SCIP_OKAY;
2217}
2218
2219/** destructor of presolver to free user data (called when SCIP is exiting) */
2220static
2221SCIP_DECL_PRESOLFREE(presolFreeImplint)
2222{
2223 SCIP_PRESOLDATA* presoldata;
2224
2225 /* free presolver data */
2226 presoldata = SCIPpresolGetData(presol);
2227 assert(presoldata != NULL);
2228
2229 SCIPfreeBlockMemory(scip, &presoldata);
2230 SCIPpresolSetData(presol, NULL);
2231
2232 return SCIP_OKAY;
2233}
2234
2235/** execution method of presolver */
2236static
2237SCIP_DECL_PRESOLEXEC(presolExecImplint)
2238{ /*lint --e{715}*/
2239 *result = SCIP_DIDNOTRUN;
2240
2241 /* TODO: check these conditions again */
2242 /* disable implied integrality detection if we are probing or in NLP context */
2244 return SCIP_OKAY;
2245
2246 /* skip implied integrality detection in branch-and-price, since it relies on rows being static */
2248 return SCIP_OKAY;
2249
2250 /* only run if we would otherwise terminate presolving */
2252 return SCIP_OKAY;
2253
2254 SCIP_PRESOLDATA* presoldata = SCIPpresolGetData(presol);
2255 assert(presoldata != NULL);
2256
2257 /* terminate if it already ran */
2258 if( presoldata->computedimplints )
2259 return SCIP_OKAY;
2260
2261 presoldata->computedimplints = TRUE;
2262
2263 *result = SCIP_DIDNOTFIND;
2264
2265 /* exit early if there are no variables to upgrade */
2266 if( SCIPgetNContVars(scip) == 0
2267 && ( !presoldata->convertintegers || SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 ) )
2268 return SCIP_OKAY;
2269
2270 SCIP_Real starttime = SCIPgetSolvingTime(scip);
2271 SCIP_Real endtime;
2272 IMPLINT_MATRIX* matrix = NULL;
2273
2274 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) implied integrality detection started\n", starttime);
2275
2276 SCIP_CALL( matrixCreate(scip, &matrix) );
2277
2278 if( matrix == NULL )
2279 {
2281 " (%.1fs) implied integrality detection stopped because problem contains unsuitable constraints\n",
2283 return SCIP_OKAY;
2284 }
2285
2286 MATRIX_COMPONENTS* comp = NULL;
2287 MATRIX_STATISTICS* stats = NULL;
2288 int beforechanged = *nchgvartypes;
2289 int afterchanged;
2290
2291 /* run implied integrality detection algorithm */
2292 SCIP_CALL( createMatrixComponents(scip, matrix, &comp) );
2293 SCIP_CALL( computeMatrixStatistics(scip, matrix, &stats, presoldata->numericslimit) );
2295 SCIP_CALL( findImpliedIntegers(scip, presoldata, matrix, comp, stats, nchgvartypes) );
2296
2297 afterchanged = *nchgvartypes;
2298 endtime = SCIPgetSolvingTime(scip);
2299
2300 if( afterchanged == beforechanged )
2301 {
2303 " (%.1fs) no implied integral variables detected (time: %.2fs)\n",
2304 endtime, endtime - starttime);
2305 }
2306 else
2307 {
2309 " (%.1fs) %d implied integral variables detected (time: %.2fs)\n",
2310 endtime, afterchanged - beforechanged, endtime - starttime);
2311
2312 *result = SCIP_SUCCESS;
2313 }
2314
2315 freeMatrixStatistics(scip, &stats);
2316 freeMatrixComponents(scip, &comp);
2317 matrixFree(scip, &matrix);
2318
2319 return SCIP_OKAY;
2320}
2321
2322/*
2323 * presolver specific interface methods
2324 */
2325
2326/** creates the implint presolver and includes it in SCIP */
2328 SCIP* scip /**< SCIP data structure */
2329 )
2330{
2331 SCIP_PRESOLDATA* presoldata;
2332 SCIP_PRESOL* presol;
2333
2334 /* create implint presolver data */
2335 SCIP_CALL( SCIPallocBlockMemory(scip, &presoldata) );
2336
2337 /* include implint presolver */
2339 PRESOL_TIMING, presolExecImplint, presoldata) );
2340
2341 assert(presol != NULL);
2342
2343 /* set non fundamental callbacks via setter functions */
2344 SCIP_CALL( SCIPsetPresolCopy(scip, presol, presolCopyImplint) );
2345 SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeImplint) );
2346
2347 presoldata->computedimplints = FALSE;
2348
2350 "presolving/implint/convertintegers",
2351 "should implied integrality also be detected for enforced integral variables?",
2352 &presoldata->convertintegers, FALSE, DEFAULT_CONVERTINTEGERS, NULL, NULL) );
2353
2355 "presolving/implint/columnrowratio",
2356 "use the network row addition algorithm when the column to row ratio becomes larger than this threshold",
2357 &presoldata->columnrowratio, TRUE, DEFAULT_COLUMNROWRATIO, 0.0, 1e98, NULL, NULL) );
2358
2360 "presolving/implint/numericslimit",
2361 "a row that contains variables with coefficients that are greater in absolute value than this limit is not considered for implied integrality detection",
2362 &presoldata->numericslimit, TRUE, DEFAULT_NUMERICSLIMIT, 1.0, 1e98, NULL, NULL) );
2363
2364 return SCIP_OKAY;
2365}
Constraint handler for AND constraints, .
Constraint handler for knapsack constraints of the form , x binary and .
Constraint handler for linear constraints in their most general form, .
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
Constraint handler for "or" constraints, .
Constraint handler for the set partitioning / packing / covering constraints .
Constraint handler for variable bound constraints .
Constraint handler for XOR constraints, .
#define NULL
Definition: def.h:248
#define SCIP_Longint
Definition: def.h:141
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIPABORT()
Definition: def.h:327
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_VAR ** SCIPgetVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2332
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetVbdcoefVarbound(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2309
int SCIPgetNVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6100
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR * SCIPgetResultantAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5248
int SCIPgetNVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5199
SCIP_VAR * SCIPgetIntVarXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6146
SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR * SCIPgetVbdvarVarbound(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9596
SCIP_VAR * SCIPgetResultantOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2355
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9619
SCIP_VAR * SCIPgetVarVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetLhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9642
SCIP_VAR ** SCIPgetVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetRhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5223
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPgetRhsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6169
SCIP_VAR ** SCIPgetVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6123
@ SCIP_SETPPCTYPE_PARTITIONING
Definition: cons_setppc.h:87
@ SCIP_SETPPCTYPE_COVERING
Definition: cons_setppc.h:89
@ SCIP_SETPPCTYPE_PACKING
Definition: cons_setppc.h:88
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:668
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2340
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
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 SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_Bool SCIPnetmatdecContainsRow(SCIP_NETMATDEC *dec, int row)
Definition: network.c:11651
void SCIPnetmatdecRemoveComponent(SCIP_NETMATDEC *dec, int *componentrows, int nrows, int *componentcols, int ncols)
Definition: network.c:11667
SCIP_Bool SCIPnetmatdecContainsColumn(SCIP_NETMATDEC *dec, int column)
Definition: network.c:11659
SCIP_RETCODE SCIPnetmatdecTryAddRow(SCIP_NETMATDEC *dec, int row, int *nonzcols, double *nonzvals, int nnonzs, SCIP_Bool *success)
Definition: network.c:11627
SCIP_RETCODE SCIPnetmatdecCreate(BMS_BLKMEM *blkmem, SCIP_NETMATDEC **pdec, int nrows, int ncols)
Definition: network.c:11566
SCIP_RETCODE SCIPnetmatdecTryAddCol(SCIP_NETMATDEC *dec, int column, int *nonzrows, double *nonzvals, int nnonzs, SCIP_Bool *success)
Definition: network.c:11603
void SCIPnetmatdecFree(SCIP_NETMATDEC **pdec)
Definition: network.c:11584
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 SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10485
SCIP_RETCODE SCIPincludePresolImplint(SCIP *scip)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4798
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4755
int SCIPgetNConshdlrs(SCIP *scip)
Definition: scip_cons.c:964
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_CONSHDLR ** SCIPgetConshdlrs(SCIP *scip)
Definition: scip_cons.c:953
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#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 SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Bool SCIPisNLPEnabled(SCIP *scip)
Definition: scip_nlp.c:74
void SCIPpresolSetData(SCIP_PRESOL *presol, SCIP_PRESOLDATA *presoldata)
Definition: presol.c:538
SCIP_PRESOLDATA * SCIPpresolGetData(SCIP_PRESOL *presol)
Definition: presol.c:528
SCIP_RETCODE SCIPsetPresolFree(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLFREE((*presolfree)))
Definition: scip_presol.c:164
SCIP_PRESOL * SCIPfindPresol(SCIP *scip, const char *name)
Definition: scip_presol.c:244
SCIP_RETCODE SCIPsetPresolCopy(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLCOPY((*presolcopy)))
Definition: scip_presol.c:148
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)
Definition: scip_presol.c:113
const char * SCIPpresolGetName(SCIP_PRESOL *presol)
Definition: presol.c:625
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
Definition: var.c:23506
SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
Definition: scip_var.c:10218
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize)
Definition: scip_var.c:2378
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:10984
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
static const SCIP_Real scalars[]
Definition: lp.c:5959
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
static SCIP_Bool matrixColInNonlinearTerm(IMPLINT_MATRIX *matrix, int column)
static SCIP_RETCODE findImpliedIntegers(SCIP *scip, SCIP_PRESOLDATA *presoldata, IMPLINT_MATRIX *matrix, MATRIX_COMPONENTS *comp, MATRIX_STATISTICS *stats, int *nchgvartypes)
static SCIP_RETCODE addXorLinearization(SCIP *scip, IMPLINT_MATRIX *matrix, SCIP_CONS *cons, SCIP_VAR **operands, int noperands, SCIP_VAR *intvar, SCIP_Real rhs)
static SCIP_RETCODE addLinearConstraint(SCIP *scip, IMPLINT_MATRIX *matrix, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real lhs, SCIP_Real rhs, SCIP_CONS *cons)
static SCIP_RETCODE createMatrixComponents(SCIP *scip, IMPLINT_MATRIX *matrix, MATRIX_COMPONENTS **pmatrixcomponents)
static SCIP_Real matrixGetRowLhs(IMPLINT_MATRIX *matrix, int row)
static int matrixGetColumnNNonzs(IMPLINT_MATRIX *matrix, int column)
static SCIP_RETCODE matrixSetColumnMajor(SCIP *scip, IMPLINT_MATRIX *matrix)
static SCIP_Real matrixGetColUb(IMPLINT_MATRIX *matrix, int column)
#define PRESOL_NAME
static int disjointSetMerge(int *disjointset, int first, int second)
static int matrixGetNCols(IMPLINT_MATRIX *matrix)
static SCIP_Real matrixGetRowRhs(IMPLINT_MATRIX *matrix, int row)
#define DEFAULT_CONVERTINTEGERS
static SCIP_RETCODE computeMatrixStatistics(SCIP *scip, IMPLINT_MATRIX *matrix, MATRIX_STATISTICS **pstats, SCIP_Real numericslimit)
static int matrixGetNRows(IMPLINT_MATRIX *matrix)
static SCIP_Bool matrixColIsImpliedIntegral(IMPLINT_MATRIX *matrix, int column)
static int * matrixGetRowInds(IMPLINT_MATRIX *matrix, int row)
static void freeMatrixComponents(SCIP *scip, MATRIX_COMPONENTS **pmatrixcomponents)
static SCIP_DECL_PRESOLCOPY(presolCopyImplint)
#define DEFAULT_NUMERICSLIMIT
static SCIP_RETCODE computeContinuousComponents(SCIP *scip, IMPLINT_MATRIX *matrix, MATRIX_COMPONENTS *comp, SCIP_Bool includeimplints)
#define PRESOL_PRIORITY
static SCIP_RETCODE matrixCreate(SCIP *scip, IMPLINT_MATRIX **pmatrix)
static void matrixFree(SCIP *scip, IMPLINT_MATRIX **pmatrix)
static SCIP_Bool matrixColIsIntegral(IMPLINT_MATRIX *matrix, int column)
static SCIP_DECL_PRESOLEXEC(presolExecImplint)
#define DEFAULT_COLUMNROWRATIO
static SCIP_Real * matrixGetRowVals(IMPLINT_MATRIX *matrix, int row)
static int matrixGetRowNNonzs(IMPLINT_MATRIX *matrix, int row)
static SCIP_RETCODE getActiveVariables(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant)
static SCIP_VAR * matrixGetVar(IMPLINT_MATRIX *matrix, int column)
static SCIP_DECL_PRESOLFREE(presolFreeImplint)
static int * matrixGetColumnInds(IMPLINT_MATRIX *matrix, int column)
#define PRESOL_MAXROUNDS
static SCIP_Real matrixGetColLb(IMPLINT_MATRIX *matrix, int column)
#define PRESOL_TIMING
static SCIP_RETCODE addAndOrLinearization(SCIP *scip, IMPLINT_MATRIX *matrix, SCIP_CONS *cons, SCIP_VAR **operands, int noperands, SCIP_VAR *resultant, SCIP_Bool isAndCons)
static SCIP_Real * matrixGetColumnVals(IMPLINT_MATRIX *matrix, int column)
static SCIP_RETCODE matrixAddRow(SCIP *scip, IMPLINT_MATRIX *matrix, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real lhs, SCIP_Real rhs, SCIP_CONS *cons)
static int disjointSetFind(int *disjointset, int ind)
static void freeMatrixStatistics(SCIP *scip, MATRIX_STATISTICS **pstats)
#define PRESOL_DESC
Presolver that detects implicit integer variables.
public methods for managing constraints
public methods for message output
public data structures and miscellaneous methods
Methods for detecting network matrices.
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 timing
public methods for SCIP variables
SCIP_Bool * colintegral
SCIP_Real * lb
SCIP_CONS ** rowcons
SCIP_Real * rowmatval
SCIP_Real * colmatval
SCIP_Bool * colinnonlinterm
SCIP_VAR ** colvar
SCIP_Real * lhs
SCIP_Real * rhs
SCIP_Real * ub
SCIP_Bool * colimplintegral
SCIP_Bool * rowbadnumerics
SCIP_Bool * colintegralbounds
SCIP_Bool * rowintegral
SCIP_Bool * rowequality
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:61
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:62
struct SCIP_PresolData SCIP_PRESOLDATA
Definition: type_presol.h:51
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PRESOLVING
Definition: type_set.h:49
@ SCIP_IMPLINTTYPE_WEAK
Definition: type_var.h:91
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141