/** update row activities after a variable's solution value changed */ static SCIP_RETCODE updateRowActivities( SCIP* scip, /**< SCIP data structure */ SCIP_Real* activities, /**< LP row activities */ SCIP_VAR* var, /**< variable that has been changed */ SCIP_Real shiftval /**< value that is added to variable */ ) { SCIP_Real* colvals; SCIP_ROW** colrows; SCIP_COL* col; int ncolrows; int i; assert(activities != NULL); /* get data of column associated to variable */ col = SCIPvarGetCol(var); colrows = SCIPcolGetRows(col); colvals = SCIPcolGetVals(col); ncolrows = SCIPcolGetNLPNonz(col); assert(ncolrows == 0 || (colrows != NULL && colvals != NULL)); /* enumerate all rows with nonzero entry in this column */ for( i = 0; i < ncolrows; ++i ) { SCIP_ROW* row; int rowpos; row = colrows[i]; rowpos = SCIProwGetLPPos(row); assert(-1 <= rowpos && rowpos < SCIPgetNLPRows(scip) ); /* update row activity, only regard global rows in the LP */ if( rowpos >= 0 && !SCIProwIsLocal(row) ) { activities[rowpos] += shiftval * colvals[i]; if( SCIPisInfinity(scip, activities[rowpos]) ) activities[rowpos] = SCIPinfinity(scip); else if( SCIPisInfinity(scip, -activities[rowpos]) ) activities[rowpos] = -SCIPinfinity(scip); } } return SCIP_OKAY; }
/** returns a score value for the given variable based on the active constraints that the variable appears in */ static SCIP_Real getNActiveConsScore( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< variable to get the score value for */ SCIP_Real* downscore, /**< pointer to store the score for branching downwards */ SCIP_Real* upscore /**< pointer to store the score for branching upwards */ ) { SCIP_COL* col; SCIP_ROW** rows; SCIP_Real* vals; int nrows; int r; int nactrows; SCIP_Real downcoefsum; SCIP_Real upcoefsum; SCIP_Real score; assert(downscore != NULL); assert(upscore != NULL); *downscore = 0.0; *upscore = 0.0; if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN ) return 0.0; col = SCIPvarGetCol(var); assert(col != NULL); rows = SCIPcolGetRows(col); vals = SCIPcolGetVals(col); nrows = SCIPcolGetNLPNonz(col); nactrows = 0; downcoefsum = 0.0; upcoefsum = 0.0; for( r = 0; r < nrows; ++r ) { SCIP_Real activity; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real dualsol; /* calculate number of active constraint sides, i.e., count equations as two */ lhs = SCIProwGetLhs(rows[r]); rhs = SCIProwGetRhs(rows[r]); activity = SCIPgetRowLPActivity(scip, rows[r]); dualsol = SCIProwGetDualsol(rows[r]); if( SCIPisFeasEQ(scip, activity, lhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(rows[r]); if( SCIPisFeasPositive(scip, dualsol) ) { if( coef > 0.0 ) downcoefsum += coef; else upcoefsum -= coef; } } else if( SCIPisFeasEQ(scip, activity, rhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(rows[r]); if( SCIPisFeasNegative(scip, dualsol) ) { if( coef > 0.0 ) upcoefsum += coef; else downcoefsum -= coef; } } } score = 1e-3*nactrows + (downcoefsum + 1e-6) * (upcoefsum + 1e-6); *downscore = -downcoefsum; *upscore = -upcoefsum; return score; }
/** determines shifting bounds for variable */ static void calculateBounds( SCIP* scip, /**< pointer to current SCIP data structure */ SCIP_VAR* var, /**< the variable for which lb and ub have to be calculated */ SCIP_Real currentvalue, /**< the current value of var in the working solution */ SCIP_Real* upperbound, /**< pointer to store the calculated upper bound on the variable shift */ SCIP_Real* lowerbound, /**< pointer to store the calculated lower bound on the variable shift */ SCIP_Real* upslacks, /**< array that contains the slacks between row activities and the right hand sides of the rows */ SCIP_Real* downslacks, /**< array that contains lhs slacks */ int nslacks, /**< current number of slacks */ SCIP_Bool* numericalerror /**< flag to determine whether a numerical error occurred */ ) { SCIP_COL* col; SCIP_ROW** colrows; SCIP_Real* colvals; int ncolvals; int i; assert(scip != NULL); assert(var != NULL); assert(upslacks != NULL); assert(downslacks != NULL); assert(upperbound != NULL); assert(lowerbound != NULL); /* get the column associated to the variable, the nonzero rows and the nonzero coefficients */ col = SCIPvarGetCol(var); colrows = SCIPcolGetRows(col); colvals = SCIPcolGetVals(col); ncolvals = SCIPcolGetNLPNonz(col); /* only proceed, when variable has nonzero coefficients */ if( ncolvals == 0 ) return; assert(colvals != NULL); assert(colrows != NULL); /* initialize the bounds on the shift to be the gap of the current solution value to the bounds of the variable */ if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) ) *upperbound = SCIPinfinity(scip); else *upperbound = SCIPvarGetUbGlobal(var) - currentvalue; if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) ) *lowerbound = SCIPinfinity(scip); else *lowerbound = currentvalue - SCIPvarGetLbGlobal(var); /* go through every nonzero row coefficient corresponding to var to determine bounds for shifting * in such a way that shifting maintains feasibility in every LP row. * a lower or upper bound as it is calculated in zirounding always has to be >= 0.0. * if one of these values is significantly < 0.0, this will cause the abort of execution of the heuristic so that * infeasible solutions are avoided */ for( i = 0; i < ncolvals && (*lowerbound > 0.0 || *upperbound > 0.0); ++i ) { SCIP_ROW* row; int rowpos; row = colrows[i]; rowpos = SCIProwGetLPPos(row); /* the row might currently not be in the LP, ignore it! */ if( rowpos == -1 ) continue; assert(0 <= rowpos && rowpos < nslacks); /* all bounds and slacks as they are calculated in zirounding always have to be greater equal zero. * It might however be due to numerical issues, e.g. with scaling, that they are not. Better abort in this case. */ if( SCIPisFeasLT(scip, *lowerbound, 0.0) || SCIPisFeasLT(scip, *upperbound, 0.0) || SCIPisFeasLT(scip, upslacks[rowpos], 0.0) || SCIPisFeasLT(scip, downslacks[rowpos] , 0.0) ) { *numericalerror = TRUE; return; } SCIPdebugMessage("colval: %15.8g, downslack: %15.8g, upslack: %5.2g, lb: %5.2g, ub: %5.2g\n", colvals[i], downslacks[rowpos], upslacks[rowpos], *lowerbound, *upperbound); /* if coefficient > 0, rounding up might violate up slack and rounding down might violate down slack * thus search for the minimum so that no constraint is violated; vice versa for coefficient < 0 */ if( colvals[i] > 0 ) { if( !SCIPisInfinity(scip, upslacks[rowpos]) ) { SCIP_Real upslack; upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */ *upperbound = MIN(*upperbound, upslack/colvals[i]); } if( !SCIPisInfinity(scip, downslacks[rowpos]) ) { SCIP_Real downslack; downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */ *lowerbound = MIN(*lowerbound, downslack/colvals[i]); } } else { assert(colvals[i] != 0.0); if( !SCIPisInfinity(scip, upslacks[rowpos]) ) { SCIP_Real upslack; upslack = MAX(upslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */ *lowerbound = MIN(*lowerbound, -upslack/colvals[i]); } if( !SCIPisInfinity(scip, downslacks[rowpos]) ) { SCIP_Real downslack; downslack = MAX(downslacks[rowpos], 0.0); /* avoid errors due to numerically slightly infeasible rows */ *upperbound = MIN(*upperbound, -downslack/colvals[i]); } } } }
/** when a variable is shifted, the activities and slacks of all rows it appears in have to be updated */ static SCIP_RETCODE updateSlacks( SCIP* scip, /**< pointer to current SCIP data structure */ SCIP_SOL* sol, /**< working solution */ SCIP_VAR* var, /**< pointer to variable to be modified */ SCIP_Real shiftvalue, /**< the value by which the variable is shifted */ SCIP_Real* upslacks, /**< upslacks of all rows the variable appears in */ SCIP_Real* downslacks, /**< downslacks of all rows the variable appears in */ SCIP_Real* activities, /**< activities of the LP rows */ SCIP_VAR** slackvars, /**< the slack variables for equality rows */ SCIP_Real* slackcoeffs, /**< the slack variable coefficients */ int nslacks /**< size of the arrays */ ) { SCIP_COL* col; /* the corresponding column of variable var */ SCIP_ROW** rows; /* pointer to the nonzero coefficient rows for variable var */ int nrows; /* the number of nonzeros */ SCIP_Real* colvals; /* array to store the nonzero coefficients */ int i; assert(scip != NULL); assert(sol != NULL); assert(var != NULL); assert(upslacks != NULL); assert(downslacks != NULL); assert(activities != NULL); assert(nslacks >= 0); col = SCIPvarGetCol(var); assert(col != NULL); rows = SCIPcolGetRows(col); nrows = SCIPcolGetNLPNonz(col); colvals = SCIPcolGetVals(col); assert(nrows == 0 || (rows != NULL && colvals != NULL)); /* go through all rows the shifted variable appears in */ for( i = 0; i < nrows; ++i ) { int rowpos; rowpos = SCIProwGetLPPos(rows[i]); assert(-1 <= rowpos && rowpos < nslacks); /* if the row is in the LP, update its activity, up and down slack */ if( rowpos >= 0 ) { SCIP_Real val; val = colvals[i] * shiftvalue; /* if the row is an equation, we update its slack variable instead of its activities */ if( SCIPisFeasEQ(scip, SCIProwGetLhs(rows[i]), SCIProwGetRhs(rows[i])) ) { SCIP_Real slackvarshiftval; SCIP_Real slackvarsolval; assert(slackvars[rowpos] != NULL); assert(!SCIPisFeasZero(scip, slackcoeffs[rowpos])); slackvarsolval = SCIPgetSolVal(scip, sol, slackvars[rowpos]); slackvarshiftval = -val / slackcoeffs[rowpos]; assert(SCIPisFeasGE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetLbGlobal(slackvars[rowpos]))); assert(SCIPisFeasLE(scip, slackvarsolval + slackvarshiftval, SCIPvarGetUbGlobal(slackvars[rowpos]))); SCIP_CALL( SCIPsetSolVal(scip, sol, slackvars[rowpos], slackvarsolval + slackvarshiftval) ); } else if( !SCIPisInfinity(scip, -activities[rowpos]) && !SCIPisInfinity(scip, activities[rowpos]) ) activities[rowpos] += val; /* the slacks of the row now can be updated independently of its type */ if( !SCIPisInfinity(scip, upslacks[rowpos]) ) upslacks[rowpos] -= val; if( !SCIPisInfinity(scip, -downslacks[rowpos]) ) downslacks[rowpos] += val; assert(!SCIPisFeasNegative(scip, upslacks[rowpos])); assert(!SCIPisFeasNegative(scip, downslacks[rowpos])); } } return SCIP_OKAY; }
/** compute value by which the solution of variable @p var can be shifted */ static SCIP_Real calcShiftVal( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< variable that should be shifted */ SCIP_Real solval, /**< current solution value */ SCIP_Real* activities /**< LP row activities */ ) { SCIP_Real lb; SCIP_Real ub; SCIP_Real obj; SCIP_Real shiftval; SCIP_COL* col; SCIP_ROW** colrows; SCIP_Real* colvals; SCIP_Bool shiftdown; int ncolrows; int i; /* get variable's solution value, global bounds and objective coefficient */ lb = SCIPvarGetLbGlobal(var); ub = SCIPvarGetUbGlobal(var); obj = SCIPvarGetObj(var); shiftval = 0.0; shiftdown = TRUE; /* determine shifting direction and maximal possible shifting w.r.t. corresponding bound */ if( obj > 0.0 && SCIPisFeasGE(scip, solval - 1.0, lb) ) shiftval = SCIPfeasFloor(scip, solval - lb); else if( obj < 0.0 && SCIPisFeasLE(scip, solval + 1.0, ub) ) { shiftval = SCIPfeasFloor(scip, ub - solval); shiftdown = FALSE; } else return 0.0; SCIPdebugMessage("Try to shift %s variable <%s> with\n", shiftdown ? "down" : "up", SCIPvarGetName(var) ); SCIPdebugMessage(" lb:<%g> <= val:<%g> <= ub:<%g> and obj:<%g> by at most: <%g>\n", lb, solval, ub, obj, shiftval); /* get data of LP column */ col = SCIPvarGetCol(var); colrows = SCIPcolGetRows(col); colvals = SCIPcolGetVals(col); ncolrows = SCIPcolGetNLPNonz(col); assert(ncolrows == 0 || (colrows != NULL && colvals != NULL)); /* find minimal shift value, st. all rows stay valid */ for( i = 0; i < ncolrows && shiftval > 0.0; ++i ) { SCIP_ROW* row; int rowpos; row = colrows[i]; rowpos = SCIProwGetLPPos(row); assert(-1 <= rowpos && rowpos < SCIPgetNLPRows(scip) ); /* only global rows need to be valid */ if( rowpos >= 0 && !SCIProwIsLocal(row) ) { SCIP_Real shiftvalrow; assert(SCIProwIsInLP(row)); if( shiftdown == (colvals[i] > 0) ) shiftvalrow = SCIPfeasFloor(scip, (activities[rowpos] - SCIProwGetLhs(row)) / ABS(colvals[i])); else shiftvalrow = SCIPfeasFloor(scip, (SCIProwGetRhs(row) - activities[rowpos]) / ABS(colvals[i])); #ifdef SCIP_DEBUG if( shiftvalrow < shiftval ) { SCIPdebugMessage(" -> The shift value had to be reduced to <%g>, because of row <%s>.\n", shiftvalrow, SCIProwGetName(row)); SCIPdebugMessage(" lhs:<%g> <= act:<%g> <= rhs:<%g>, colval:<%g>\n", SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row), colvals[i]); } #endif shiftval = MIN(shiftval, shiftvalrow); /* shiftvalrow might be negative, if we detected infeasibility -> make sure that shiftval is >= 0 */ shiftval = MAX(shiftval, 0.0); } } if( shiftdown ) shiftval *= -1.0; /* we must not shift variables to infinity */ if( SCIPisInfinity(scip, solval + shiftval) ) shiftval = 0.0; return shiftval; }
/** returns a score value for the given variable based on the active constraints that the variable appears in */ static SCIP_Real getNActiveConsScore( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* sol, /**< working solution */ SCIP_VAR* var, /**< variable to get the score value for */ SCIP_Real* downscore, /**< pointer to store the score for branching downwards */ SCIP_Real* upscore /**< pointer to store the score for branching upwards */ ) { SCIP_COL* col; SCIP_ROW** rows; SCIP_Real* vals; int nrows; int r; int nactrows; SCIP_Real nlprows; SCIP_Real downcoefsum; SCIP_Real upcoefsum; SCIP_Real score; assert(downscore != NULL); assert(upscore != NULL); *downscore = 0.0; *upscore = 0.0; if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN ) return 0.0; col = SCIPvarGetCol(var); assert(col != NULL); rows = SCIPcolGetRows(col); vals = SCIPcolGetVals(col); nrows = SCIPcolGetNLPNonz(col); nactrows = 0; downcoefsum = 0.0; upcoefsum = 0.0; for( r = 0; r < nrows; ++r ) { SCIP_ROW* row; SCIP_Real activity; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real dualsol; row = rows[r]; /* calculate number of active constraint sides, i.e., count equations as two */ lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* @todo this is suboptimal because activity is calculated by looping over all nonzeros of this row, need to * store LP activities instead (which cannot be retrieved if no LP was solved at this node) */ activity = SCIPgetRowSolActivity(scip, row, sol); dualsol = SCIProwGetDualsol(row); if( SCIPisFeasEQ(scip, activity, lhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(row); if( SCIPisFeasPositive(scip, dualsol) ) { if( coef > 0.0 ) downcoefsum += coef; else upcoefsum -= coef; } } else if( SCIPisFeasEQ(scip, activity, rhs) ) { SCIP_Real coef; nactrows++; coef = vals[r] / SCIProwGetNorm(row); if( SCIPisFeasNegative(scip, dualsol) ) { if( coef > 0.0 ) upcoefsum += coef; else downcoefsum -= coef; } } } /* use the number of LP rows for normalization */ nlprows = (SCIP_Real)SCIPgetNLPRows(scip); upcoefsum /= nlprows; downcoefsum /= nlprows; /* calculate the score using SCIP's branch score. Pass NULL as variable to not have the var branch factor influence * the result */ score = nactrows / nlprows + SCIPgetBranchScore(scip, NULL, downcoefsum, upcoefsum); assert(score <= 3.0); assert(score >= 0.0); *downscore = downcoefsum; *upscore = upcoefsum; return score; }
/** process a variable from the queue of changed variables */ static SCIP_RETCODE varProcessBoundChanges( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_VAR* var /**< the variable whose bound changes need to be processed */ ) { SCIP_ROW** colrows; SCIP_COL* varcol; SCIP_Real* colvals; SCIP_Real oldmean; SCIP_Real newmean; SCIP_Real oldvariance; SCIP_Real newvariance; SCIP_Real oldlb; SCIP_Real newlb; SCIP_Real oldub; SCIP_Real newub; SCIP_VARTYPE vartype; int ncolrows; int r; int varindex; /* ensure that this is a probing bound change */ assert(SCIPinProbing(scip)); assert(var != NULL); varcol = SCIPvarGetCol(var); assert(varcol != NULL); colrows = SCIPcolGetRows(varcol); colvals = SCIPcolGetVals(varcol); ncolrows = SCIPcolGetNNonz(varcol); varindex = SCIPvarGetProbindex(var); oldlb = heurdata->currentlbs[varindex]; oldub = heurdata->currentubs[varindex]; /* skip update if the variable has never been subject of previously calculated row activities */ assert((oldlb == SCIP_INVALID) == (oldub == SCIP_INVALID)); /*lint !e777 doesn't like comparing floats for equality */ if( oldlb == SCIP_INVALID ) /*lint !e777 */ return SCIP_OKAY; newlb = SCIPvarGetLbLocal(var); newub = SCIPvarGetUbLocal(var); /* skip update if the bound change events have cancelled out */ if( SCIPisFeasEQ(scip, oldlb, newlb) && SCIPisFeasEQ(scip, oldub, newub) ) return SCIP_OKAY; /* calculate old and new variable distribution mean and variance */ oldvariance = 0.0; newvariance = 0.0; oldmean = 0.0; newmean = 0.0; vartype = SCIPvarGetType(var); SCIPvarCalcDistributionParameters(scip, oldlb, oldub, vartype, &oldmean, &oldvariance); SCIPvarCalcDistributionParameters(scip, newlb, newub, vartype, &newmean, &newvariance); /* loop over all rows of this variable and update activity distribution */ for( r = 0; r < ncolrows; ++r ) { int rowpos; assert(colrows[r] != NULL); rowpos = SCIProwGetIndex(colrows[r]); assert(rowpos >= 0); SCIP_CALL( heurdataEnsureArraySize(scip, heurdata, rowpos) ); /* only consider rows for which activity distribution was already calculated */ if( heurdata->rowmeans[rowpos] != SCIP_INVALID ) /*lint !e777 doesn't like comparing floats for equality */ { SCIP_Real coeff; SCIP_Real coeffsquared; assert(heurdata->rowvariances[rowpos] != SCIP_INVALID && SCIPisFeasGE(scip, heurdata->rowvariances[rowpos], 0.0)); /*lint !e777 */ coeff = colvals[r]; coeffsquared = SQUARED(coeff); /* update variable contribution to row activity distribution */ heurdata->rowmeans[rowpos] += coeff * (newmean - oldmean); heurdata->rowvariances[rowpos] += coeffsquared * (newvariance - oldvariance); heurdata->rowvariances[rowpos] = MAX(0.0, heurdata->rowvariances[rowpos]); /* account for changes of the infinite contributions to row activities */ if( coeff > 0.0 ) { /* if the coefficient is positive, upper bounds affect activity up */ if( SCIPisInfinity(scip, newub) && !SCIPisInfinity(scip, oldub) ) ++heurdata->rowinfinitiesup[rowpos]; else if( !SCIPisInfinity(scip, newub) && SCIPisInfinity(scip, oldub) ) --heurdata->rowinfinitiesup[rowpos]; if( SCIPisInfinity(scip, newlb) && !SCIPisInfinity(scip, oldlb) ) ++heurdata->rowinfinitiesdown[rowpos]; else if( !SCIPisInfinity(scip, newlb) && SCIPisInfinity(scip, oldlb) ) --heurdata->rowinfinitiesdown[rowpos]; } else if( coeff < 0.0 ) { if( SCIPisInfinity(scip, newub) && !SCIPisInfinity(scip, oldub) ) ++heurdata->rowinfinitiesdown[rowpos]; else if( !SCIPisInfinity(scip, newub) && SCIPisInfinity(scip, oldub) ) --heurdata->rowinfinitiesdown[rowpos]; if( SCIPisInfinity(scip, newlb) && !SCIPisInfinity(scip, oldlb) ) ++heurdata->rowinfinitiesup[rowpos]; else if( !SCIPisInfinity(scip, newlb) && SCIPisInfinity(scip, oldlb) ) --heurdata->rowinfinitiesup[rowpos]; } assert(heurdata->rowinfinitiesdown[rowpos] >= 0); assert(heurdata->rowinfinitiesup[rowpos] >= 0); } } /* store the new local bounds in the data */ heurdataUpdateCurrentBounds(scip, heurdata, var); return SCIP_OKAY; }
/** calculate the branching score of a variable, depending on the chosen score parameter */ static SCIP_RETCODE calcBranchScore( SCIP* scip, /**< current SCIP */ SCIP_HEURDATA* heurdata, /**< branch rule data */ SCIP_VAR* var, /**< candidate variable */ SCIP_Real lpsolval, /**< current fractional LP-relaxation solution value */ SCIP_Real* upscore, /**< pointer to store the variable score when branching on it in upward direction */ SCIP_Real* downscore, /**< pointer to store the variable score when branching on it in downward direction */ char scoreparam /**< the score parameter of this heuristic */ ) { SCIP_COL* varcol; SCIP_ROW** colrows; SCIP_Real* rowvals; SCIP_Real varlb; SCIP_Real varub; SCIP_Real squaredbounddiff; /* current squared difference of variable bounds (ub - lb)^2 */ SCIP_Real newub; /* new upper bound if branching downwards */ SCIP_Real newlb; /* new lower bound if branching upwards */ SCIP_Real squaredbounddiffup; /* squared difference after branching upwards (ub - lb')^2 */ SCIP_Real squaredbounddiffdown; /* squared difference after branching downwards (ub' - lb)^2 */ SCIP_Real currentmean; /* current mean value of variable uniform distribution */ SCIP_Real meanup; /* mean value of variable uniform distribution after branching up */ SCIP_Real meandown; /* mean value of variable uniform distribution after branching down*/ SCIP_VARTYPE vartype; int ncolrows; int i; SCIP_Bool onlyactiverows; /* should only rows which are active at the current node be considered? */ assert(scip != NULL); assert(var != NULL); assert(upscore != NULL); assert(downscore != NULL); assert(!SCIPisIntegral(scip, lpsolval) || SCIPvarIsBinary(var)); assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); varcol = SCIPvarGetCol(var); assert(varcol != NULL); colrows = SCIPcolGetRows(varcol); rowvals = SCIPcolGetVals(varcol); ncolrows = SCIPcolGetNNonz(varcol); varlb = SCIPvarGetLbLocal(var); varub = SCIPvarGetUbLocal(var); assert(SCIPisFeasLT(scip, varlb, varub)); vartype = SCIPvarGetType(var); /* calculate mean and variance of variable uniform distribution before and after branching */ currentmean = 0.0; squaredbounddiff = 0.0; SCIPvarCalcDistributionParameters(scip, varlb, varub, vartype, ¤tmean, &squaredbounddiff); /* unfixed binary variables may have an integer solution value in the LP solution, eg, at the presence of indicator constraints */ if( !SCIPvarIsBinary(var) ) { newlb = SCIPfeasCeil(scip, lpsolval); newub = SCIPfeasFloor(scip, lpsolval); } else { newlb = 1.0; newub = 0.0; } /* calculate the variable's uniform distribution after branching up and down, respectively. */ squaredbounddiffup = 0.0; meanup = 0.0; SCIPvarCalcDistributionParameters(scip, newlb, varub, vartype, &meanup, &squaredbounddiffup); /* calculate the distribution mean and variance for a variable with finite lower bound */ squaredbounddiffdown = 0.0; meandown = 0.0; SCIPvarCalcDistributionParameters(scip, varlb, newub, vartype, &meandown, &squaredbounddiffdown); /* initialize the variable's up and down score */ *upscore = 0.0; *downscore = 0.0; onlyactiverows = FALSE; /* loop over the variable rows and calculate the up and down score */ for( i = 0; i < ncolrows; ++i ) { SCIP_ROW* row; SCIP_Real changedrowmean; SCIP_Real rowmean; SCIP_Real rowvariance; SCIP_Real changedrowvariance; SCIP_Real currentrowprob; SCIP_Real newrowprobup; SCIP_Real newrowprobdown; SCIP_Real squaredcoeff; SCIP_Real rowval; int rowinfinitiesdown; int rowinfinitiesup; int rowpos; row = colrows[i]; rowval = rowvals[i]; assert(row != NULL); /* we access the rows by their index */ rowpos = SCIProwGetIndex(row); /* skip non-active rows if the user parameter was set this way */ if( onlyactiverows && SCIPisSumPositive(scip, SCIPgetRowLPFeasibility(scip, row)) ) continue; /* call method to ensure sufficient data capacity */ SCIP_CALL( heurdataEnsureArraySize(scip, heurdata, rowpos) ); /* calculate row activity distribution if this is the first candidate to appear in this row */ if( heurdata->rowmeans[rowpos] == SCIP_INVALID ) /*lint !e777 doesn't like comparing floats for equality */ { rowCalculateGauss(scip, heurdata, row, &heurdata->rowmeans[rowpos], &heurdata->rowvariances[rowpos], &heurdata->rowinfinitiesdown[rowpos], &heurdata->rowinfinitiesup[rowpos]); } /* retrieve the row distribution parameters from the branch rule data */ rowmean = heurdata->rowmeans[rowpos]; rowvariance = heurdata->rowvariances[rowpos]; rowinfinitiesdown = heurdata->rowinfinitiesdown[rowpos]; rowinfinitiesup = heurdata->rowinfinitiesup[rowpos]; assert(!SCIPisNegative(scip, rowvariance)); currentrowprob = SCIProwCalcProbability(scip, row, rowmean, rowvariance, rowinfinitiesdown, rowinfinitiesup); /* get variable's current expected contribution to row activity */ squaredcoeff = SQUARED(rowval); /* first, get the probability change for the row if the variable is branched on upwards. The probability * can only be affected if the variable upper bound is finite */ if( !SCIPisInfinity(scip, varub) ) { int rowinftiesdownafterbranch; int rowinftiesupafterbranch; /* calculate how branching would affect the row parameters */ changedrowmean = rowmean + rowval * (meanup - currentmean); changedrowvariance = rowvariance + squaredcoeff * (squaredbounddiffup - squaredbounddiff); changedrowvariance = MAX(0.0, changedrowvariance); rowinftiesdownafterbranch = rowinfinitiesdown; rowinftiesupafterbranch = rowinfinitiesup; /* account for changes of the row's infinite bound contributions */ if( SCIPisInfinity(scip, -varlb) && rowval < 0.0 ) rowinftiesupafterbranch--; if( SCIPisInfinity(scip, -varlb) && rowval > 0.0 ) rowinftiesdownafterbranch--; assert(rowinftiesupafterbranch >= 0); assert(rowinftiesdownafterbranch >= 0); newrowprobup = SCIProwCalcProbability(scip, row, changedrowmean, changedrowvariance, rowinftiesdownafterbranch, rowinftiesupafterbranch); } else newrowprobup = currentrowprob; /* do the same for the other branching direction */ if( !SCIPisInfinity(scip, varlb) ) { int rowinftiesdownafterbranch; int rowinftiesupafterbranch; changedrowmean = rowmean + rowval * (meandown - currentmean); changedrowvariance = rowvariance + squaredcoeff * (squaredbounddiffdown - squaredbounddiff); changedrowvariance = MAX(0.0, changedrowvariance); rowinftiesdownafterbranch = rowinfinitiesdown; rowinftiesupafterbranch = rowinfinitiesup; /* account for changes of the row's infinite bound contributions */ if( SCIPisInfinity(scip, varub) && rowval > 0.0 ) rowinftiesupafterbranch -= 1; if( SCIPisInfinity(scip, varub) && rowval < 0.0 ) rowinftiesdownafterbranch -= 1; assert(rowinftiesdownafterbranch >= 0); assert(rowinftiesupafterbranch >= 0); newrowprobdown = SCIProwCalcProbability(scip, row, changedrowmean, changedrowvariance, rowinftiesdownafterbranch, rowinftiesupafterbranch); } else newrowprobdown = currentrowprob; /* update the up and down score depending on the chosen scoring parameter */ SCIP_CALL( SCIPupdateDistributionScore(scip, currentrowprob, newrowprobup, newrowprobdown, upscore, downscore, scoreparam) ); SCIPdebugMessage(" Variable %s changes probability of row %s from %g to %g (branch up) or %g;\n", SCIPvarGetName(var), SCIProwGetName(row), currentrowprob, newrowprobup, newrowprobdown); SCIPdebugMessage(" --> new variable score: %g (for branching up), %g (for branching down)\n", *upscore, *downscore); } return SCIP_OKAY; }
/** update row activities after a variable's solution value changed */ static SCIP_RETCODE updateActivities( SCIP* scip, /**< SCIP data structure */ SCIP_Real* activities, /**< LP row activities */ SCIP_ROW** violrows, /**< array with currently violated rows */ int* violrowpos, /**< position of LP rows in violrows array */ int* nviolrows, /**< pointer to the number of currently violated rows */ int nlprows, /**< number of rows in current LP */ SCIP_VAR* var, /**< variable that has been changed */ SCIP_Real oldsolval, /**< old solution value of variable */ SCIP_Real newsolval /**< new solution value of variable */ ) { SCIP_COL* col; SCIP_ROW** colrows; SCIP_Real* colvals; SCIP_Real delta; int ncolrows; int r; assert(activities != NULL); assert(nviolrows != NULL); assert(0 <= *nviolrows && *nviolrows <= nlprows); delta = newsolval - oldsolval; col = SCIPvarGetCol(var); colrows = SCIPcolGetRows(col); colvals = SCIPcolGetVals(col); ncolrows = SCIPcolGetNLPNonz(col); assert(ncolrows == 0 || (colrows != NULL && colvals != NULL)); for( r = 0; r < ncolrows; ++r ) { SCIP_ROW* row; int rowpos; row = colrows[r]; rowpos = SCIProwGetLPPos(row); assert(-1 <= rowpos && rowpos < nlprows); if( rowpos >= 0 && !SCIProwIsLocal(row) ) { SCIP_Real oldactivity; SCIP_Real newactivity; assert(SCIProwIsInLP(row)); /* update row activity */ oldactivity = activities[rowpos]; if( !SCIPisInfinity(scip, -oldactivity) && !SCIPisInfinity(scip, oldactivity) ) { newactivity = oldactivity + delta * colvals[r]; if( SCIPisInfinity(scip, newactivity) ) newactivity = SCIPinfinity(scip); else if( SCIPisInfinity(scip, -newactivity) ) newactivity = -SCIPinfinity(scip); activities[rowpos] = newactivity; /* update row violation arrays */ updateViolations(scip, row, violrows, violrowpos, nviolrows, oldactivity, newactivity); } } } return SCIP_OKAY; }