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-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);
    182 assert(column < matrix->ncols);
    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);
    196 assert(column < matrix->ncols);
    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);
    210 assert(column < matrix->ncols);
    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);
    288 assert(column < matrix->ncols);
    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);
    302 assert(column < matrix->ncols);
    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);
    316 assert(column < matrix->ncols);
    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);
    330 assert(column < matrix->ncols);
    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);
    344 assert(column < matrix->ncols);
    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);
    358 assert(column < matrix->ncols);
    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
    830 assert(SCIPgetNActivePricers(scip) == 0);
    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
    907 vars = SCIPgetVars(scip);
    908 nvars = SCIPgetNVars(scip);
    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
    925 SCIP_CALL( SCIPduplicateBufferArray(scip, &matrix->colvar, vars, nvars) );
    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]);
    948 matrix->colimplintegral[i] = SCIPvarIsImpliedIntegral(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];
    976 assert(SCIPconsIsTransformed(cons));
    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
    995 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nvars) );
    996
    997 for( c = 0; c < nconshdlrconss; ++c )
    998 {
    999 SCIP_Longint* weights;
    1000 SCIP_Real rhs;
    1001 SCIP_CONS* cons = conshdlrconss[c];
    1002 assert(SCIPconsIsTransformed(cons));
    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];
    1030 assert(SCIPconsIsTransformed(cons));
    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];
    1067 assert(SCIPconsIsTransformed(cons));
    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];
    1092 assert(SCIPconsIsTransformed(cons));
    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];
    1117 assert(SCIPconsIsTransformed(cons));
    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];
    1134 assert(SCIPconsIsTransformed(cons));
    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];
    1151 assert(SCIPconsIsTransformed(cons));
    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);
    1855 assert(!SCIPvarIsIntegral(var));
    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 {
    1982 assert(!SCIPnetmatdecContainsColumn(dec, col));
    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 {
    2077 assert(SCIPvarGetType(matrixGetVar(matrix, col)) == SCIP_VARTYPE_INTEGER);
    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);
    2141 assert(SCIPvarIsNonimpliedIntegral(var));
    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);
    2160 assert(SCIPvarIsNonimpliedIntegral(var));
    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}*/
    2238 *result = SCIP_DIDNOTRUN;
    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
    2262 *result = SCIP_DIDNOTFIND;
    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
    2311 *result = SCIP_SUCCESS;
    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)
    Definition: cons_setppc.c:9683
    SCIP_VAR * SCIPgetResultantOr(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_or.c:2345
    SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9701
    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:9719
    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)
    Definition: scip_general.c:676
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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: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
    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: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)
    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_INVALIDCALL
    Definition: type_retcode.h:51
    @ 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