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