/** creates the rows of the subproblem */ static SCIP_RETCODE createRows( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars /**< the variables of the subproblem */ ) { SCIP_ROW** rows; /* original scip rows */ SCIP_CONS* cons; /* new constraint */ SCIP_VAR** consvars; /* new constraint's variables */ SCIP_COL** cols; /* original row's columns */ SCIP_Real constant; /* constant added to the row */ SCIP_Real lhs; /* left hand side of the row */ SCIP_Real rhs; /* left right side of the row */ SCIP_Real* vals; /* variables' coefficient values of the row */ int nrows; int nnonz; int i; int j; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert(lhs <= rhs); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); while( j < nmarkers ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); } while( marked[i] ); marked[i] = TRUE; j++; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } SCIPfreeBufferArray(scip, &marked); return SCIP_OKAY; }
/** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */ static SCIP_RETCODE sepastoreApplyBdchg( SCIP_SEPASTORE* sepastore, /**< separation storage */ BMS_BLKMEM* blkmem, /**< block memory */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< problem statistics */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp, /**< LP data */ SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_ROW* cut, /**< cut with a single variable */ SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */ ) { SCIP_COL** cols; SCIP_Real* vals; SCIP_VAR* var; SCIP_Real lhs; SCIP_Real rhs; assert(sepastore != NULL); assert(!SCIProwIsModifiable(cut)); assert(SCIProwGetNNonz(cut) == 1); assert(cutoff != NULL); *cutoff = FALSE; /* get the single variable and its coefficient of the cut */ cols = SCIProwGetCols(cut); assert(cols != NULL); var = SCIPcolGetVar(cols[0]); vals = SCIProwGetVals(cut); assert(vals != NULL); assert(!SCIPsetIsZero(set, vals[0])); /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */ if( SCIPsetIsFeasZero(set, vals[0]) ) return SCIP_OKAY; /* get the left hand side of the cut and convert it to a bound */ lhs = SCIProwGetLhs(cut); if( !SCIPsetIsInfinity(set, -lhs) ) { lhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> lhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } else { /* coefficient is negative -> lhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, lhs/vals[0], cutoff) ); } } /* get the right hand side of the cut and convert it to a bound */ rhs = SCIProwGetRhs(cut); if( !SCIPsetIsInfinity(set, rhs) ) { rhs -= SCIProwGetConstant(cut); if( vals[0] > 0.0 ) { /* coefficient is positive -> rhs corresponds to upper bound */ SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } else { /* coefficient is negative -> rhs corresponds to lower bound */ SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, var, rhs/vals[0], cutoff) ); } } /* count the bound change as applied cut */ if( !sepastore->initiallp ) sepastore->ncutsapplied++; return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ SCIP_Bool binarybounds, /**< should general integers get binary bounds [floor(.),ceil(.)] ? */ SCIP_Bool uselprows, /**< should subproblem be created out of the rows in the LP rows? */ SCIP_Bool* success /**< pointer to store whether the problem was created successfully */ ) { SCIP_VAR** vars; /* original SCIP variables */ SCIP_Real fixingrate; int nvars; int nbinvars; int nintvars; int i; int fixingcounter; assert(scip != NULL); assert(subscip != NULL); assert(subvars != NULL); assert(0.0 <= minfixingrate && minfixingrate <= 1.0); /* get required variable data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); fixingcounter = 0; /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { SCIP_Real lpsolval; SCIP_Real lb; SCIP_Real ub; /* get the current LP solution for each variable */ lpsolval = SCIPgetRelaxSolVal(scip, vars[i]); if( SCIPisFeasIntegral(scip, lpsolval) ) { /* fix variables to current LP solution if it is integral, * use exact integral value, if the variable is only integral within numerical tolerances */ lb = SCIPfloor(scip, lpsolval+0.5); ub = lb; fixingcounter++; } else if( binarybounds ) { /* if the sub problem should be a binary problem, change the bounds to nearest integers */ lb = SCIPfeasFloor(scip,lpsolval); ub = SCIPfeasCeil(scip,lpsolval); } else { /* otherwise just copy bounds */ lb = SCIPvarGetLbGlobal(vars[i]); ub = SCIPvarGetUbGlobal(vars[i]); } /* perform the bound change */ SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], lb) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], ub) ); } /* abort, if all integer variables were fixed (which should not happen for MIP) */ if( fixingcounter == nbinvars + nintvars ) { *success = FALSE; return SCIP_OKAY; } else fixingrate = fixingcounter / (SCIP_Real)(MAX(nbinvars + nintvars, 1)); SCIPdebugMessage("fixing rate: %g = %d of %d\n", fixingrate, fixingcounter, nbinvars + nintvars); /* abort, if the amount of fixed variables is insufficient */ if( fixingrate < minfixingrate ) { *success = FALSE; return SCIP_OKAY; } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; int j; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(subscip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(subscip, &consvars); } } *success = TRUE; return SCIP_OKAY; }
/** calculates the initial mean and variance of the row activity normal distribution. * * The mean value \f$ \mu \f$ is given by \f$ \mu = \sum_i=1^n c_i * (lb_i +ub_i) / 2 \f$ where * \f$n \f$ is the number of variables, and \f$ c_i, lb_i, ub_i \f$ are the variable coefficient and * bounds, respectively. With the same notation, the variance \f$ \sigma^2 \f$ is given by * \f$ \sigma^2 = \sum_i=1^n c_i^2 * \sigma^2_i \f$, with the variance being * \f$ \sigma^2_i = ((ub_i - lb_i + 1)^2 - 1) / 12 \f$ for integer variables and * \f$ \sigma^2_i = (ub_i - lb_i)^2 / 12 \f$ for continuous variables. */ static void rowCalculateGauss( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< the heuristic rule data */ SCIP_ROW* row, /**< the row for which the gaussian normal distribution has to be calculated */ SCIP_Real* mu, /**< pointer to store the mean value of the gaussian normal distribution */ SCIP_Real* sigma2, /**< pointer to store the variance value of the gaussian normal distribution */ int* rowinfinitiesdown, /**< pointer to store the number of variables with infinite bounds to DECREASE activity */ int* rowinfinitiesup /**< pointer to store the number of variables with infinite bounds to INCREASE activity */ ) { SCIP_COL** rowcols; SCIP_Real* rowvals; int nrowvals; int c; assert(scip != NULL); assert(row != NULL); assert(mu != NULL); assert(sigma2 != NULL); assert(rowinfinitiesup != NULL); assert(rowinfinitiesdown != NULL); rowcols = SCIProwGetCols(row); rowvals = SCIProwGetVals(row); nrowvals = SCIProwGetNNonz(row); assert(nrowvals == 0 || rowcols != NULL); assert(nrowvals == 0 || rowvals != NULL); *mu = SCIProwGetConstant(row); *sigma2 = 0.0; *rowinfinitiesdown = 0; *rowinfinitiesup = 0; /* loop over nonzero row coefficients and sum up the variable contributions to mu and sigma2 */ for( c = 0; c < nrowvals; ++c ) { SCIP_VAR* colvar; SCIP_Real colval; SCIP_Real colvarlb; SCIP_Real colvarub; SCIP_Real squarecoeff; SCIP_Real varvariance; SCIP_Real varmean; int varindex; assert(rowcols[c] != NULL); colvar = SCIPcolGetVar(rowcols[c]); assert(colvar != NULL); colval = rowvals[c]; colvarlb = SCIPvarGetLbLocal(colvar); colvarub = SCIPvarGetUbLocal(colvar); varmean = 0.0; varvariance = 0.0; varindex = SCIPvarGetProbindex(colvar); assert((heurdata->currentlbs[varindex] == SCIP_INVALID) == (heurdata->currentubs[varindex] == SCIP_INVALID)); /*lint !e777 doesn't like comparing floats for equality */ /* variable bounds need to be watched from now on */ if( heurdata->currentlbs[varindex] == SCIP_INVALID ) /*lint !e777 doesn't like comparing floats for equality */ heurdataUpdateCurrentBounds(scip, heurdata, colvar); assert(!SCIPisInfinity(scip, colvarlb)); assert(!SCIPisInfinity(scip, -colvarub)); assert(SCIPisFeasLE(scip, colvarlb, colvarub)); /* variables with infinite bounds are skipped for the calculation of the variance; they need to * be accounted for by the counters for infinite row activity decrease and increase and they * are used to shift the row activity mean in case they have one nonzero, but finite bound */ if( SCIPisInfinity(scip, -colvarlb) || SCIPisInfinity(scip, colvarub) ) { if( SCIPisInfinity(scip, colvarub) ) { /* an infinite upper bound gives the row an infinite maximum activity or minimum activity, if the coefficient is * positive or negative, resp. */ if( colval < 0.0 ) ++(*rowinfinitiesdown); else ++(*rowinfinitiesup); } /* an infinite lower bound gives the row an infinite maximum activity or minimum activity, if the coefficient is * negative or positive, resp. */ if( SCIPisInfinity(scip, -colvarlb) ) { if( colval > 0.0 ) ++(*rowinfinitiesdown); else ++(*rowinfinitiesup); } } SCIPvarCalcDistributionParameters(scip, colvarlb, colvarub, SCIPvarGetType(colvar), &varmean, &varvariance); /* actual values are updated; the contribution of the variable to mu is the arithmetic mean of its bounds */ *mu += colval * varmean; /* the variance contribution of a variable is c^2 * (u - l)^2 / 12.0 for continuous and c^2 * ((u - l + 1)^2 - 1) / 12.0 for integer */ squarecoeff = SQUARED(colval); *sigma2 += squarecoeff * varvariance; assert(!SCIPisFeasNegative(scip, *sigma2)); } SCIPdebug( SCIPprintRow(scip, row, NULL) ); SCIPdebugMessage(" Row %s has a mean value of %g at a sigma2 of %g \n", SCIProwGetName(row), *mu, *sigma2); }
/** computes a disjunctive cut inequality based on two simplex taubleau rows */ static SCIP_RETCODE generateDisjCutSOS1( SCIP* scip, /**< SCIP pointer */ SCIP_SEPA* sepa, /**< separator */ SCIP_ROW** rows, /**< LP rows */ int nrows, /**< number of LP rows */ SCIP_COL** cols, /**< LP columns */ int ncols, /**< number of LP columns */ int ndisjcuts, /**< number of disjunctive cuts found so far */ SCIP_Bool scale, /**< should cut be scaled */ SCIP_Bool strengthen, /**< should cut be strengthened if integer variables are present */ SCIP_Real cutlhs1, /**< left hand side of the first simplex row */ SCIP_Real cutlhs2, /**< left hand side of the second simplex row */ SCIP_Real bound1, /**< bound of first simplex row */ SCIP_Real bound2, /**< bound of second simplex row */ SCIP_Real* simplexcoefs1, /**< simplex coefficients of first row */ SCIP_Real* simplexcoefs2, /**< simplex coefficients of second row */ SCIP_Real* cutcoefs, /**< pointer to store cut coefficients (length: nscipvars) */ SCIP_ROW** row, /**< pointer to store disjunctive cut inequality */ SCIP_Bool* madeintegral /**< pointer to store whether cut has been scaled to integral values */ ) { char cutname[SCIP_MAXSTRLEN]; SCIP_COL** rowcols; SCIP_COL* col; SCIP_Real* rowvals; SCIP_Real lhsrow; SCIP_Real rhsrow; SCIP_Real cutlhs; SCIP_Real sgn; SCIP_Real lb; SCIP_Real ub; int nonbasicnumber = 0; int rownnonz; int ind; int r; int c; assert( scip != NULL ); assert( row != NULL ); assert( rows != NULL ); assert( cols != NULL ); assert( simplexcoefs1 != NULL ); assert( simplexcoefs2 != NULL ); assert( cutcoefs != NULL ); assert( sepa != NULL ); assert( madeintegral != NULL ); *madeintegral = FALSE; /* check signs */ if ( SCIPisFeasPositive(scip, cutlhs1) == SCIPisFeasPositive(scip, cutlhs2) ) sgn = 1.0; else sgn = -1.0; /* check bounds */ if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) ) strengthen = FALSE; /* compute left hand side of row (a later update is possible, see below) */ cutlhs = sgn * cutlhs1 * cutlhs2; /* add cut-coefficients of the non-basic non-slack variables */ for (c = 0; c < ncols; ++c) { col = cols[c]; assert( col != NULL ); ind = SCIPcolGetLPPos(col); assert( ind >= 0 ); if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_LOWER ) { lb = SCIPcolGetLb(col); /* for integer variables we may obtain stronger coefficients */ if ( strengthen && SCIPcolIsIntegral(col) ) { SCIP_Real mval; SCIP_Real mvalfloor; SCIP_Real mvalceil; mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2); mvalfloor = SCIPfloor(scip, mval); mvalceil = SCIPceil(scip, mval); cutcoefs[ind] = MIN(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] - mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] + mvalceil * bound2)); assert( SCIPisFeasLE(scip, cutcoefs[ind], MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) ); } else cutcoefs[ind] = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs += cutcoefs[ind] * lb; ++nonbasicnumber; } else if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_UPPER ) { ub = SCIPcolGetUb(col); /* for integer variables we may obtain stronger coefficients */ if ( strengthen && SCIPcolIsIntegral(col) ) { SCIP_Real mval; SCIP_Real mvalfloor; SCIP_Real mvalceil; mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2); mvalfloor = SCIPfloor(scip, -mval); mvalceil = SCIPceil(scip, -mval); cutcoefs[ind] = MAX(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] + mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] - mvalceil * bound2)); assert( SCIPisFeasLE(scip, -cutcoefs[ind], -MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) ); } else cutcoefs[ind] = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs += cutcoefs[ind] * ub; ++nonbasicnumber; } else { assert( SCIPcolGetBasisStatus(col) != SCIP_BASESTAT_ZERO ); cutcoefs[ind] = 0.0; } } /* add cut-coefficients of the non-basic slack variables */ for (r = 0; r < nrows; ++r) { rhsrow = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]); lhsrow = SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]); assert( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_ZERO ); assert( SCIPisFeasZero(scip, lhsrow - rhsrow) || SCIPisNegative(scip, lhsrow - rhsrow) ); assert( SCIProwIsInLP(rows[r]) ); if ( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_BASIC ) { SCIP_Real cutcoef; if ( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_UPPER ) { assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetRhs(rows[r])) ); cutcoef = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs -= cutcoef * rhsrow; ++nonbasicnumber; } else /* SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER */ { assert( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER ); assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetLhs(rows[r])) ); cutcoef = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs -= cutcoef * lhsrow; ++nonbasicnumber; } rownnonz = SCIProwGetNNonz(rows[r]); rowvals = SCIProwGetVals(rows[r]); rowcols = SCIProwGetCols(rows[r]); for (c = 0; c < rownnonz; ++c) { ind = SCIPcolGetLPPos(rowcols[c]); /* if column is not in LP, then return without generating cut */ if ( ind < 0 ) { *row = NULL; return SCIP_OKAY; } cutcoefs[ind] -= cutcoef * rowvals[c]; } } } /* create cut */ (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_%d_%d", SCIPsepaGetName(sepa), SCIPgetNLPs(scip), ndisjcuts); if ( SCIPgetDepth(scip) == 0 ) SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) ); else SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), TRUE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, *row) ); for (c = 0; c < ncols; ++c) { ind = SCIPcolGetLPPos(cols[c]); assert( ind >= 0 ); if ( ! SCIPisFeasZero(scip, cutcoefs[ind]) ) { SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPcolGetVar(cols[c]), cutcoefs[ind] ) ); } } SCIP_CALL( SCIPflushRowExtensions(scip, *row) ); /* try to scale the cut to integral values * @todo find better but still stable disjunctive cut settings */ if ( scale ) { int maxdepth; int depth; SCIP_Longint maxdnom; SCIP_Real maxscale; depth = SCIPgetDepth(scip); assert( depth >= 0 ); maxdepth = SCIPgetMaxDepth(scip); if ( depth == 0 ) { maxdnom = 1000; maxscale = 1000.0; } else if ( depth <= maxdepth/4 ) { maxdnom = 1000; maxscale = 1000.0; } else if ( depth <= maxdepth/2 ) { maxdnom = 100; maxscale = 100.0; } else { maxdnom = 10; maxscale = 10.0; } SCIP_CALL( SCIPmakeRowIntegral(scip, *row, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, TRUE, madeintegral) ); } return SCIP_OKAY; }
/** checks whether given row is valid for the debugging solution */ SCIP_RETCODE SCIPdebugCheckRow( SCIP_SET* set, /**< global SCIP settings */ SCIP_ROW* row /**< row to check for validity */ ) { SCIP_COL** cols; SCIP_Real* vals; SCIP_Real lhs; SCIP_Real rhs; int nnonz; int i; SCIP_Real minactivity; SCIP_Real maxactivity; SCIP_Real solval; assert(set != NULL); assert(row != NULL); /* check if we are in the original problem and not in a sub MIP */ if( !isSolutionInMip(set) ) return SCIP_OKAY; /* check if the incumbent solution is at least as good as the debug solution, so we can stop to check the debug solution */ if( debugSolIsAchieved(set) ) return SCIP_OKAY; /* if the row is only locally valid, check whether the debugging solution is contained in the local subproblem */ if( SCIProwIsLocal(row) ) { SCIP_Bool solcontained; SCIP_CALL( isSolutionInNode(SCIPblkmem(set->scip), set, SCIPgetCurrentNode(set->scip), &solcontained) ); if( !solcontained ) return SCIP_OKAY; } cols = SCIProwGetCols(row); vals = SCIProwGetVals(row); nnonz = SCIProwGetNNonz(row); lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* calculate row's activity on debugging solution */ minactivity = SCIProwGetConstant(row); maxactivity = minactivity; for( i = 0; i < nnonz; ++i ) { SCIP_VAR* var; /* get solution value of variable in debugging solution */ var = SCIPcolGetVar(cols[i]); SCIP_CALL( getSolutionValue(set, var, &solval) ); if( solval != SCIP_UNKNOWN ) /*lint !e777*/ { minactivity += vals[i] * solval; maxactivity += vals[i] * solval; } else if( vals[i] > 0.0 ) { minactivity += vals[i] * SCIPvarGetLbGlobal(var); maxactivity += vals[i] * SCIPvarGetUbGlobal(var); } else if( vals[i] < 0.0 ) { minactivity += vals[i] * SCIPvarGetUbGlobal(var); maxactivity += vals[i] * SCIPvarGetLbGlobal(var); } } SCIPdebugMessage("debugging solution on row <%s>: %g <= [%g,%g] <= %g\n", SCIProwGetName(row), lhs, minactivity, maxactivity, rhs); /* check row for violation */ if( SCIPsetIsFeasLT(set, maxactivity, lhs) || SCIPsetIsFeasGT(set, minactivity, rhs) ) { printf("***** debug: row <%s> violates debugging solution (lhs=%.15g, rhs=%.15g, activity=[%.15g,%.15g], local=%d)\n", SCIProwGetName(row), lhs, rhs, minactivity, maxactivity, SCIProwIsLocal(row)); SCIProwPrint(row, NULL); /* output row with solution values */ printf("\n\n"); printf("***** debug: violated row <%s>:\n", SCIProwGetName(row)); printf(" %.15g <= %.15g", lhs, SCIProwGetConstant(row)); for( i = 0; i < nnonz; ++i ) { /* get solution value of variable in debugging solution */ SCIP_CALL( getSolutionValue(set, SCIPcolGetVar(cols[i]), &solval) ); printf(" %+.15g<%s>[%.15g]", vals[i], SCIPvarGetName(SCIPcolGetVar(cols[i])), solval); } printf(" <= %.15g\n", rhs); SCIPABORT(); } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOctane) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_SOL** first_sols; /* stores the first ffirst sols in order to check for common violation of a row */ SCIP_VAR** vars; /* the variables of the problem */ SCIP_VAR** fracvars; /* variables, that are fractional in current LP solution */ SCIP_VAR** subspacevars; /* the variables on which the search is performed. Either coinciding with vars or with the * space of all fractional variables of the current LP solution */ SCIP_Real p; /* n/2 - <delta,x> ( for some facet delta ) */ SCIP_Real q; /* <delta,a> */ SCIP_Real* rayorigin; /* origin of the ray, vector x in paper */ SCIP_Real* raydirection; /* direction of the ray, vector a in paper */ SCIP_Real* negquotient; /* negated quotient of rayorigin and raydirection, vector v in paper */ SCIP_Real* lambda; /* stores the distance of the facets (s.b.) to the origin of the ray */ SCIP_Bool usefracspace; /* determines whether the search concentrates on fractional variables and fixes integer ones */ SCIP_Bool cons_viol; /* used for checking whether a linear constraint is violated by one of the possible solutions */ SCIP_Bool success; SCIP_Bool* sign; /* signature of the direction of the ray */ SCIP_Bool** facets; /* list of extended facets */ int nvars; /* number of variables */ int nbinvars; /* number of 0-1-variables */ int nfracvars; /* number of fractional variables in current LP solution */ int nsubspacevars; /* dimension of the subspace on which the search is performed */ int nfacets; /* number of facets hidden by the ray that where already found */ int i; /* counter */ int j; /* counter */ int f_max; /* {0,1}-points to be checked */ int f_first; /* {0,1}-points to be generated at first in order to check whether a restart is necessary */ int r; /* counter */ int firstrule; int* perm; /* stores the way in which the coordinates were permuted */ int* fracspace; /* maps the variables of the subspace to the original variables */ assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); /* OCTANE is for use in 0-1 programs only */ if( nvars != nbinvars ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* don't call heuristic, if it was not successful enough in the past */ /*lint --e{647}*/ if( SCIPgetNNodes(scip) % (SCIPheurGetNCalls(heur) / (100 * SCIPheurGetNBestSolsFound(heur) + 10*heurdata->nsuccess + 1) + 1) != 0 ) return SCIP_OKAY; SCIP_CALL( SCIPgetLPBranchCands(scip, &fracvars, NULL, NULL, &nfracvars, NULL) ); /* don't use integral starting points */ if( nfracvars == 0 ) return SCIP_OKAY; /* get working pointers from heurdata */ sol = heurdata->sol; assert( sol != NULL ); f_max = heurdata->f_max; f_first = heurdata->f_first; usefracspace = heurdata->usefracspace; SCIP_CALL( SCIPallocBufferArray(scip, &fracspace, nvars) ); /* determine the space one which OCTANE should work either as the whole space or as the space of fractional variables */ if( usefracspace ) { nsubspacevars = nfracvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); BMScopyMemoryArray(subspacevars, fracvars, nsubspacevars); for( i = nvars - 1; i >= 0; --i ) fracspace[i] = -1; for( i = nsubspacevars - 1; i >= 0; --i ) fracspace[SCIPvarGetProbindex(subspacevars[i])] = i; } else { int currentindex; nsubspacevars = nvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); /* only copy the variables which are in the current LP */ currentindex = 0; for( i = 0; i < nvars; ++i ) { if( SCIPcolGetLPPos(SCIPvarGetCol(vars[i])) >= 0 ) { subspacevars[currentindex] = vars[i]; fracspace[i] = currentindex; ++currentindex; } else { fracspace[i] = -1; --nsubspacevars; } } } /* nothing to do for empty search space */ if( nsubspacevars == 0 ) return SCIP_OKAY; assert(0 < nsubspacevars && nsubspacevars <= nvars); for( i = 0; i < nsubspacevars; i++) assert(fracspace[SCIPvarGetProbindex(subspacevars[i])] == i); /* at most 2^(n-1) facets can be hit */ if( nsubspacevars < 30 ) { /*lint --e{701}*/ assert(f_max > 0); f_max = MIN(f_max, 1 << (nsubspacevars - 1) ); } f_first = MIN(f_first, f_max); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &rayorigin, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &raydirection, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &negquotient, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &sign, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &perm, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &lambda, f_max + 1) ); SCIP_CALL( SCIPallocBufferArray(scip, &facets, f_max + 1) ); for( i = f_max; i >= 0; --i ) { /*lint --e{866}*/ SCIP_CALL( SCIPallocBufferArray(scip, &facets[i], nsubspacevars) ); } SCIP_CALL( SCIPallocBufferArray(scip, &first_sols, f_first) ); *result = SCIP_DIDNOTFIND; /* starting OCTANE */ SCIPdebugMessage("run Octane heuristic on %s variables, which are %d vars, generate at most %d facets, using rule number %d\n", usefracspace ? "fractional" : "all", nsubspacevars, f_max, (heurdata->lastrule+1)%5); /* generate starting point in original coordinates */ SCIP_CALL( generateStartingPoint(scip, rayorigin, subspacevars, nsubspacevars) ); for( i = nsubspacevars - 1; i >= 0; --i ) rayorigin[i] -= 0.5; firstrule = heurdata->lastrule; ++firstrule; for( r = firstrule; r <= firstrule + 10 && !SCIPisStopped(scip); r++ ) { SCIP_ROW** rows; int nrows; /* generate shooting ray in original coordinates by certain rules */ switch(r % 5) { case 1: if( heurdata->useavgnbray ) { SCIP_CALL( generateAverageNBRay(scip, raydirection, fracspace, subspacevars, nsubspacevars) ); } break; case 2: if( heurdata->useobjray ) { SCIP_CALL( generateObjectiveRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 3: if( heurdata->usediffray ) { SCIP_CALL( generateDifferenceRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 4: if( heurdata->useavgwgtray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, TRUE) ); } break; case 0: if( heurdata->useavgray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, FALSE) ); } break; default: SCIPerrorMessage("invalid ray rule identifier\n"); SCIPABORT(); } /* there must be a feasible direction for the shooting ray */ if( isZero(scip, raydirection, nsubspacevars) ) continue; /* transform coordinates such that raydirection >= 0 */ flipCoords(rayorigin, raydirection, sign, nsubspacevars); for( i = f_max - 1; i >= 0; --i) lambda[i] = SCIPinfinity(scip); /* calculate negquotient, initialize perm, facets[0], p, and q */ p = 0.5 * nsubspacevars; q = 0.0; for( i = nsubspacevars - 1; i >= 0; --i ) { /* calculate negquotient, the ratio of rayorigin and raydirection, paying special attention to the case raydirection[i] == 0 */ if( SCIPisFeasZero(scip, raydirection[i]) ) { if( rayorigin[i] < 0 ) negquotient[i] = SCIPinfinity(scip); else negquotient[i] = -SCIPinfinity(scip); } else negquotient[i] = - (rayorigin[i] / raydirection[i]); perm[i] = i; /* initialization of facets[0] to the all-one facet with p and q its characteristic values */ facets[0][i] = TRUE; p -= rayorigin[i]; q += raydirection[i]; } assert(SCIPisPositive(scip, q)); /* resort the coordinates in nonincreasing order of negquotient */ SCIPsortDownRealRealRealBoolPtr( negquotient, raydirection, rayorigin, sign, (void**) subspacevars, nsubspacevars); #ifndef NDEBUG for( i = 0; i < nsubspacevars; i++ ) assert( raydirection[i] >= 0 ); for( i = 1; i < nsubspacevars; i++ ) assert( negquotient[i - 1] >= negquotient[i] ); #endif /* finished initialization */ /* find the first facet of the octahedron hit by a ray shot from rayorigin into direction raydirection */ for( i = 0; i < nsubspacevars && negquotient[i] * q > p; ++i ) { facets[0][i] = FALSE; p += 2 * rayorigin[i]; q -= 2 * raydirection[i]; assert(SCIPisPositive(scip, p)); assert(SCIPisPositive(scip, q)); } /* avoid dividing by values close to 0.0 */ if( !SCIPisFeasPositive(scip, q) ) continue; /* assert necessary for flexelint */ assert(q > 0); lambda[0] = p / q; nfacets = 1; /* find the first facets hit by the ray */ for( i = 0; i < nfacets && i < f_first; ++i) generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); /* construct the first ffirst possible solutions */ for( i = 0; i < nfacets && i < f_first; ++i ) { SCIP_CALL( SCIPcreateSol(scip, &first_sols[i], heur) ); SCIP_CALL( getSolFromFacet(scip, facets[i], first_sols[i], sign, subspacevars, nsubspacevars) ); assert( first_sols[i] != NULL ); } /* try, whether there is a row violated by all of the first ffirst solutions */ cons_viol = FALSE; SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); for( i = nrows - 1; i >= 0; --i ) { if( !SCIProwIsLocal(rows[i]) ) { SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real rowval; SCIP_Real* coeffs; int nnonzerovars; int k; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]); rhs = SCIProwGetRhs(rows[i]); coeffs = SCIProwGetVals(rows[i]); nnonzerovars = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[0], SCIPcolGetVar(cols[j])); /* if the row's lhs is violated by the first sol, test, whether it is violated by the next ones, too */ if( lhs > rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( lhs <= rowval ) { cons_viol = FALSE; break; } } } /* dito for the right hand side */ else if( rhs < rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( rhs >= rowval ) { cons_viol = FALSE; break; } } } /* break as soon as one row is violated by all of the ffirst solutions */ if( cons_viol ) break; } } if( !cons_viol ) { /* if there was no row violated by all solutions, try whether one or more of them are feasible */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { assert(first_sols[i] != NULL); SCIP_CALL( SCIPtrySol(scip, first_sols[i], FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } /* search for further facets and construct and try solutions out of facets fixed as closest ones */ for( i = f_first; i < f_max; ++i) { if( i >= nfacets ) break; generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); SCIP_CALL( getSolFromFacet(scip, facets[i], sol, sign, subspacevars, nsubspacevars) ); SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } } /* finished OCTANE */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { SCIP_CALL( SCIPfreeSol(scip, &first_sols[i]) ); } } heurdata->lastrule = r; if( *result == SCIP_FOUNDSOL ) ++(heurdata->nsuccess); /* free temporary memory */ SCIPfreeBufferArray(scip, &first_sols); for( i = f_max; i >= 0; --i ) SCIPfreeBufferArray(scip, &facets[i]); SCIPfreeBufferArray(scip, &facets); SCIPfreeBufferArray(scip, &lambda); SCIPfreeBufferArray(scip, &perm); SCIPfreeBufferArray(scip, &sign); SCIPfreeBufferArray(scip, &negquotient); SCIPfreeBufferArray(scip, &raydirection); SCIPfreeBufferArray(scip, &rayorigin); SCIPfreeBufferArray(scip, &subspacevars); SCIPfreeBufferArray(scip, &fracspace); return SCIP_OKAY; }