/** finds a continuous slack variable for an equation row, NULL if none exists */ static void rowFindSlackVar( SCIP* scip, /**< pointer to current SCIP data structure */ SCIP_ROW* row, /**< the row for which a slack variable is searched */ SCIP_VAR** varpointer, /**< pointer to store the slack variable */ SCIP_Real* coeffpointer /**< pointer to store the coefficient of the slack variable */ ) { int v; SCIP_COL** rowcols; SCIP_Real* rowvals; int nrowvals; assert(row != NULL); assert(varpointer != NULL); assert(coeffpointer != NULL); rowcols = SCIProwGetCols(row); rowvals = SCIProwGetVals(row); nrowvals = SCIProwGetNNonz(row); assert(nrowvals == 0 || rowvals != NULL); assert(nrowvals == 0 || rowcols != NULL); /* iterate over the row variables. Stop after the first unfixed continuous variable was found. */ for( v = nrowvals - 1; v >= 0; --v ) { SCIP_VAR* colvar; assert(rowcols[v] != NULL); if( SCIPcolGetLPPos(rowcols[v]) == -1 ) continue; colvar = SCIPcolGetVar(rowcols[v]); if( SCIPvarGetType(colvar) == SCIP_VARTYPE_CONTINUOUS && !SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(colvar), SCIPvarGetUbGlobal(colvar)) && SCIPcolGetNLPNonz(rowcols[v]) == 1 ) { SCIPdebugMessage(" slack variable for row %s found: %s\n", SCIProwGetName(row), SCIPvarGetName(colvar)); *coeffpointer = rowvals[v]; *varpointer = colvar; return; } } *varpointer = NULL; *coeffpointer = 0.0; SCIPdebugMessage("No slack variable for row %s found. \n", SCIProwGetName(row)); }
/** propagate the given none binary variable/column using the reduced cost */ static SCIP_RETCODE propagateRedcostVar( SCIP* scip, /**< SCIP data structure */ SCIP_VAR* var, /**< variable to use for propagation */ SCIP_COL* col, /**< LP column of the variable */ SCIP_Real lpobjval, /**< objective value of the current LP */ SCIP_Real cutoffbound, /**< the current cutoff bound */ int* nchgbds /**< pointer to count the number of bound changes */ ) { SCIP_Real redcost; switch( SCIPcolGetBasisStatus(col) ) { case SCIP_BASESTAT_LOWER: redcost = SCIPgetColRedcost(scip, col); assert(!SCIPisFeasNegative(scip, redcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( SCIPisFeasPositive(scip, redcost) ) { SCIP_Real oldlb; SCIP_Real oldub; oldlb = SCIPvarGetLbLocal(var); oldub = SCIPvarGetUbLocal(var); assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col))); assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col))); if( SCIPisFeasLT(scip, oldlb, oldub) ) { SCIP_Real newub; SCIP_Bool strengthen; /* calculate reduced cost based bound */ newub = (cutoffbound - lpobjval) / redcost + oldlb; /* check, if new bound is good enough: * - integer variables: take all possible strengthenings * - continuous variables: strengthening must cut part of the variable's dynamic range, and * at least 20% of the current domain */ if( SCIPvarIsIntegral(var) ) { newub = SCIPadjustedVarUb(scip, var, newub); strengthen = (newub < oldub - 0.5); } else strengthen = (newub < SCIPcolGetMaxPrimsol(col) && newub <= 0.2 * oldlb + 0.8 * oldub); if( strengthen ) { /* strengthen upper bound */ SCIPdebugMessage("redcost strengthening upper bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n", SCIPvarGetName(var), oldlb, oldub, oldlb, newub, cutoffbound, lpobjval, redcost); SCIP_CALL( SCIPchgVarUb(scip, var, newub) ); (*nchgbds)++; } } } break; case SCIP_BASESTAT_BASIC: break; case SCIP_BASESTAT_UPPER: redcost = SCIPgetColRedcost(scip, col); assert(!SCIPisFeasPositive(scip, redcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( SCIPisFeasNegative(scip, redcost) ) { SCIP_Real oldlb; SCIP_Real oldub; oldlb = SCIPvarGetLbLocal(var); oldub = SCIPvarGetUbLocal(var); assert(SCIPisEQ(scip, oldlb, SCIPcolGetLb(col))); assert(SCIPisEQ(scip, oldub, SCIPcolGetUb(col))); if( SCIPisFeasLT(scip, oldlb, oldub) ) { SCIP_Real newlb; SCIP_Bool strengthen; /* calculate reduced cost based bound */ newlb = (cutoffbound - lpobjval) / redcost + oldub; /* check, if new bound is good enough: * - integer variables: take all possible strengthenings * - continuous variables: strengthening must cut part of the variable's dynamic range, and * at least 20% of the current domain */ if( SCIPvarIsIntegral(var) ) { newlb = SCIPadjustedVarLb(scip, var, newlb); strengthen = (newlb > oldlb + 0.5); } else strengthen = (newlb > SCIPcolGetMinPrimsol(col) && newlb >= 0.8 * oldlb + 0.2 * oldub); /* check, if new bound is good enough: at least 20% strengthening for continuous variables */ if( strengthen ) { /* strengthen lower bound */ SCIPdebugMessage("redcost strengthening lower bound: <%s> [%g,%g] -> [%g,%g] (ub=%g, lb=%g, redcost=%g)\n", SCIPvarGetName(var), oldlb, oldub, newlb, oldub, cutoffbound, lpobjval, redcost); SCIP_CALL( SCIPchgVarLb(scip, var, newlb) ); (*nchgbds)++; } } } break; case SCIP_BASESTAT_ZERO: assert(SCIPisFeasZero(scip, SCIPgetColRedcost(scip, col))); break; default: SCIPerrorMessage("invalid basis state\n"); return SCIP_INVALIDDATA; } return SCIP_OKAY; }
/** propagate the given binary variable/column using the reduced cost */ static SCIP_RETCODE propagateRedcostBinvar( SCIP* scip, /**< SCIP data structure */ SCIP_PROPDATA* propdata, /**< propagator data structure */ SCIP_VAR* var, /**< variable to use for propagation */ SCIP_COL* col, /**< LP column of the variable */ SCIP_Real requiredredcost, /**< required reduset cost to be able to fix a binary variable */ int* nchgbds, /**< pointer to count the number of bound changes */ SCIP_Bool* cutoff /**< pointer to store if an cutoff was detected */ ) { SCIP_Real lbredcost; SCIP_Real ubredcost; SCIP_Real redcost; /* skip binary variable if it is locally fixed */ if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 ) return SCIP_OKAY; /* first use the redcost cost to fix the binary variable */ switch( SCIPcolGetBasisStatus(col) ) { case SCIP_BASESTAT_LOWER: redcost = SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasNegative(scip, redcost)); if( redcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost); SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) ); (*nchgbds)++; return SCIP_OKAY; } break; case SCIP_BASESTAT_UPPER: redcost = SCIPgetVarRedcost(scip, var); assert(!SCIPisFeasPositive(scip, redcost)); if( -redcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost); SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) ); (*nchgbds)++; return SCIP_OKAY; } break; case SCIP_BASESTAT_BASIC: return SCIP_OKAY; case SCIP_BASESTAT_ZERO: assert(SCIPisFeasZero(scip, SCIPgetColRedcost(scip, col))); return SCIP_OKAY; default: SCIPerrorMessage("invalid basis state\n"); return SCIP_INVALIDDATA; } /* second, if the implications should be used and if the implications are seen to be promising used the implied * reduced costs to fix the binary variable */ if( propdata->useimplics && propdata->usefullimplics ) { /* collect implied reduced costs if the variable would be fixed to its lower bound */ lbredcost = SCIPgetVarImplRedcost(scip, var, FALSE); assert(!SCIPisFeasPositive(scip, lbredcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); /* collect implied reduced costs if the variable would be fixed to its upper bound */ ubredcost = SCIPgetVarImplRedcost(scip, var, TRUE); assert(!SCIPisFeasNegative(scip, ubredcost) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ); if( -lbredcost > requiredredcost && ubredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: cutoff (requiredredcost <%g>, lbredcost <%g>, ubredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, lbredcost, ubredcost); (*cutoff) = TRUE; } else if( -lbredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 1.0 (requiredredcost <%g>, redcost <%g>, lbredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost, lbredcost); SCIP_CALL( SCIPchgVarLb(scip, var, 1.0) ); (*nchgbds)++; } else if( ubredcost > requiredredcost ) { SCIPdebugMessage("variable <%s>: fixed 0.0 (requiredredcost <%g>, redcost <%g>, ubredcost <%g>)\n", SCIPvarGetName(var), requiredredcost, redcost, ubredcost); SCIP_CALL( SCIPchgVarUb(scip, var, 0.0) ); (*nchgbds)++; } /* update maximum reduced cost of a single binary variable */ propdata->maxredcost = MAX3(propdata->maxredcost, -lbredcost, ubredcost); } return SCIP_OKAY; }
/** perform randomized rounding of the given solution. Domain propagation is optionally applied after every rounding * step */ static SCIP_RETCODE performRandRounding( SCIP* scip, /**< SCIP main data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_SOL* sol, /**< solution to round */ SCIP_VAR** cands, /**< candidate variables */ int ncands, /**< number of candidates */ SCIP_Bool propagate, /**< should the rounding be propagated? */ SCIP_RESULT* result /**< pointer to store the result of the heuristic call */ ) { int c; SCIP_Bool stored; SCIP_VAR** permutedcands; SCIP_Bool cutoff; assert(heurdata != NULL); /* start probing tree before rounding begins */ if( propagate ) { SCIP_CALL( SCIPstartProbing(scip) ); SCIPenableVarHistory(scip); } /* copy and permute the candidate array */ SCIP_CALL( SCIPduplicateBufferArray(scip, &permutedcands, cands, ncands) ); assert(permutedcands != NULL); SCIPpermuteArray((void **)permutedcands, 0, ncands, &heurdata->randseed); cutoff = FALSE; /* loop over candidates and perform randomized rounding and optionally probing. */ for (c = 0; c < ncands && !cutoff; ++c) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Longint ndomreds; SCIP_Real lb; SCIP_Real ub; SCIP_Real ceilval; SCIP_Real floorval; /* get next variable from permuted candidate array */ var = permutedcands[c]; oldsolval = SCIPgetSolVal(scip, sol, var); lb = SCIPvarGetLbLocal(var); ub = SCIPvarGetUbLocal(var); assert( ! SCIPisFeasIntegral(scip, oldsolval) ); assert( SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ); mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); ceilval = SCIPfeasCeil(scip, oldsolval); floorval = SCIPfeasFloor(scip, oldsolval); SCIPdebugMessage("rand rounding heuristic: var <%s>, val=%g, rounddown=%u, roundup=%u\n", SCIPvarGetName(var), oldsolval, mayrounddown, mayroundup); /* abort if rounded ceil and floor value lie outside the variable domain. Otherwise, check if * bounds allow only one rounding direction, anyway */ if( lb > ceilval + 0.5 || ub < floorval - 0.5 ) { cutoff = TRUE; break; } else if( SCIPisFeasEQ(scip, lb, ceilval) ) { /* only rounding up possible */ assert(SCIPisFeasGE(scip, ub, ceilval)); newsolval = ceilval; } else if( SCIPisFeasEQ(scip, ub, floorval) ) { /* only rounding down possible */ assert(SCIPisFeasLE(scip,lb, floorval)); newsolval = floorval; } else if( !heurdata->usesimplerounding || !(mayroundup || mayrounddown) ) { /* the standard randomized rounding */ SCIP_Real randnumber; randnumber = SCIPgetRandomReal(0.0, 1.0, &heurdata->randseed); if( randnumber <= oldsolval - floorval ) newsolval = ceilval; else newsolval = floorval; } /* choose rounding direction, if possible, or use the only direction guaranteed to be feasible */ else if( mayrounddown && mayroundup ) { /* we can round in both directions: round in objective function direction */ if ( SCIPvarGetObj(var) >= 0.0 ) newsolval = floorval; else newsolval = ceilval; } else if( mayrounddown ) newsolval = floorval; else { assert(mayroundup); newsolval = ceilval; } assert(SCIPisFeasLE(scip, lb, newsolval)); assert(SCIPisFeasGE(scip, ub, newsolval)); /* if propagation is enabled, fix the candidate variable to its rounded value and propagate the solution */ if( propagate ) { SCIP_Bool lbadjust; SCIP_Bool ubadjust; lbadjust = SCIPisGT(scip, newsolval, lb); ubadjust = SCIPisLT(scip, newsolval, ub); assert( lbadjust || ubadjust || SCIPisFeasEQ(scip, lb, ub)); /* enter a new probing node if the variable was not already fixed before */ if( lbadjust || ubadjust ) { SCIP_RETCODE retcode; if( SCIPisStopped(scip) ) break; retcode = SCIPnewProbingNode(scip); if( retcode == SCIP_MAXDEPTHLEVEL ) break; SCIP_CALL( retcode ); /* tighten the bounds to fix the variable for the probing node */ if( lbadjust ) { SCIP_CALL( SCIPchgVarLbProbing(scip, var, newsolval) ); } if( ubadjust ) { SCIP_CALL( SCIPchgVarUbProbing(scip, var, newsolval) ); } /* call propagation routines for the reduced problem */ SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) ); } } /* store new solution value */ SCIP_CALL( SCIPsetSolVal(scip, sol, var, newsolval) ); } /* if no cutoff was detected, the solution is a candidate to be checked for feasibility */ if( !cutoff && ! SCIPisStopped(scip) ) { if( SCIPallColsInLP(scip) ) { /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because all fractional * variables were already moved in feasible direction to the next integer */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) ); } else { /* if there are variables which are not present in the LP, e.g., for * column generation, we need to check their bounds */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &stored) ); } if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif *result = SCIP_FOUNDSOL; } } assert( !propagate || SCIPinProbing(scip) ); /* exit probing mode and free locally allocated memory */ if( propagate ) { SCIP_CALL( SCIPendProbing(scip) ); } SCIPfreeBufferArray(scip, &permutedcands); 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; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecZirounding) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_VAR** zilpcands; SCIP_VAR** slackvars; SCIP_Real* upslacks; SCIP_Real* downslacks; SCIP_Real* activities; SCIP_Real* slackvarcoeffs; SCIP_Bool* rowneedsslackvar; SCIP_ROW** rows; SCIP_Real* lpcandssol; SCIP_Real* solarray; SCIP_Longint nlps; int currentlpcands; int nlpcands; int nimplfracs; int i; int c; int nslacks; int nroundings; SCIP_RETCODE retcode; SCIP_Bool improvementfound; SCIP_Bool numericalerror; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic if an optimal LP-solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation * to number of calls falls below heurdata->stoppercentage */ if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage ) return SCIP_OKAY; /* assure that heuristic has not already been called after the last LP had been solved */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* get fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) ); nlpcands = nlpcands + nimplfracs; /* make sure that there is at least one fractional variable that should be integral */ if( nlpcands == 0 ) return SCIP_OKAY; assert(nlpcands > 0); assert(lpcands != NULL); assert(lpcandssol != NULL); /* get LP rows data */ rows = SCIPgetLPRows(scip); nslacks = SCIPgetNLPRows(scip); /* cannot do anything if LP is empty */ if( nslacks == 0 ) return SCIP_OKAY; assert(rows != NULL); assert(nslacks > 0); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); *result = SCIP_DIDNOTFIND; solarray = NULL; zilpcands = NULL; retcode = SCIP_OKAY; /* copy the current LP solution to the working solution and allocate memory for local data */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &solarray, nlpcands), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &zilpcands, nlpcands), TERMINATE); /* copy necessary data to local arrays */ BMScopyMemoryArray(solarray, lpcandssol, nlpcands); BMScopyMemoryArray(zilpcands, lpcands, nlpcands); /* allocate buffer data arrays */ SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvars, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &upslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &downslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &activities, nslacks), TERMINATE); BMSclearMemoryArray(slackvars, nslacks); BMSclearMemoryArray(slackvarcoeffs, nslacks); BMSclearMemoryArray(rowneedsslackvar, nslacks); numericalerror = FALSE; nroundings = 0; /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */ for( c = 0; c < nlpcands; ++c ) { SCIP_VAR* cand; SCIP_ROW** candrows; int r; int ncandrows; cand = zilpcands[c]; assert(cand != NULL); assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0); candrows = SCIPcolGetRows(SCIPvarGetCol(cand)); ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand)); assert(candrows == NULL || ncandrows > 0); for( r = 0; r < ncandrows; ++r ) { int rowpos; assert(candrows != NULL); /* to please flexelint */ assert(candrows[r] != NULL); rowpos = SCIProwGetLPPos(candrows[r]); if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) ) { rowneedsslackvar[rowpos] = TRUE; SCIPdebugMessage(" Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand)); } } } /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero, * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering */ for( i = 0; i < nslacks; ++i ) { SCIP_ROW* row; SCIP_Real lhs; SCIP_Real rhs; row = rows[i]; assert(row != NULL); lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* get row activity */ activities[i] = SCIPgetRowActivity(scip, row); assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs)); /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */ if( SCIPisInfinity(scip, -lhs) ) downslacks[i] = SCIPinfinity(scip); else downslacks[i] = activities[i] - lhs; if( SCIPisInfinity(scip, rhs) ) upslacks[i] = SCIPinfinity(scip); else upslacks[i] = rhs - activities[i]; SCIPdebugMessage("lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]); /* row is an equation. Try to find a slack variable in the row, i.e., * a continuous variable which occurs only in this row. If no such variable exists, * there is no hope for an IP-feasible solution in this round */ if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] ) { /* @todo: This is only necessary for rows containing fractional variables. */ rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i])); if( slackvars[i] == NULL ) { SCIPdebugMessage("No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row)); goto TERMINATE; } else { SCIP_Real ubslackvar; SCIP_Real lbslackvar; SCIP_Real solvalslackvar; SCIP_Real coeffslackvar; SCIP_Real ubgap; SCIP_Real lbgap; assert(SCIPvarGetType(slackvars[i]) == SCIP_VARTYPE_CONTINUOUS); solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]); ubslackvar = SCIPvarGetUbGlobal(slackvars[i]); lbslackvar = SCIPvarGetLbGlobal(slackvars[i]); coeffslackvar = slackvarcoeffs[i]; assert(!SCIPisFeasZero(scip, coeffslackvar)); ubgap = ubslackvar - solvalslackvar; lbgap = solvalslackvar - lbslackvar; if( SCIPisFeasZero(scip, ubgap) ) ubgap = 0.0; if( SCIPisFeasZero(scip, lbgap) ) lbgap = 0.0; if( SCIPisFeasPositive(scip, coeffslackvar) ) { if( !SCIPisInfinity(scip, lbslackvar) ) upslacks[i] += coeffslackvar * lbgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, ubslackvar) ) downslacks[i] += coeffslackvar * ubgap; else downslacks[i] = SCIPinfinity(scip); } else { if( !SCIPisInfinity(scip, ubslackvar) ) upslacks[i] -= coeffslackvar * ubgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, lbslackvar) ) downslacks[i] -= coeffslackvar * lbgap; else downslacks[i] = SCIPinfinity(scip); } SCIPdebugMessage(" Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n", SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar, upslacks[i], downslacks[i]); } } /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are * significantly smaller than zero -> terminate */ if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) ) goto TERMINATE; } assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL)); /* initialize number of remaining variables and flag to enter the main loop */ currentlpcands = nlpcands; improvementfound = TRUE; /* iterate over variables as long as there are fractional variables left */ while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) ) { /*lint --e{850}*/ improvementfound = FALSE; nroundings++; SCIPdebugMessage("zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands); /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */ for( c = 0; c < currentlpcands; ++c ) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real upperbound; SCIP_Real lowerbound; SCIP_Real up; SCIP_Real down; SCIP_Real ziup; SCIP_Real zidown; SCIP_Real zicurrent; SCIP_Real shiftval; DIRECTION direction; /* get values from local data */ oldsolval = solarray[c]; var = zilpcands[c]; assert(!SCIPisFeasIntegral(scip, oldsolval)); assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); /* calculate bounds for variable and make sure that there are no numerical inconsistencies */ upperbound = SCIPinfinity(scip); lowerbound = SCIPinfinity(scip); calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror); if( numericalerror ) goto TERMINATE; /* calculate the possible values after shifting */ up = oldsolval + upperbound; down = oldsolval - lowerbound; /* if the variable is integer or implicit binary, do not shift further than the nearest integer */ if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY) { SCIP_Real ceilx; SCIP_Real floorx; ceilx = SCIPfeasCeil(scip, oldsolval); floorx = SCIPfeasFloor(scip, oldsolval); up = MIN(up, ceilx); down = MAX(down, floorx); } /* calculate necessary values */ ziup = getZiValue(scip, up); zidown = getZiValue(scip, down); zicurrent = getZiValue(scip, oldsolval); /* calculate the shifting direction that reduces ZI-value the most, * if both directions improve ZI-value equally, take the direction which improves the objective */ if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) ) { if( SCIPisFeasEQ(scip,ziup, zidown) ) direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP; else if( SCIPisFeasLT(scip, zidown, ziup) ) direction = DIRECTION_DOWN; else direction = DIRECTION_UP; /* once a possible shifting direction and value have been found, variable value is updated */ shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval); /* this improves numerical stability in some cases */ if( direction == DIRECTION_UP ) shiftval = MIN(shiftval, upperbound); else shiftval = MIN(shiftval, lowerbound); /* update the solution */ solarray[c] = direction == DIRECTION_UP ? up : down; SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) ); /* update the rows activities and slacks */ SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks, downslacks, activities, slackvars, slackvarcoeffs, nslacks) ); SCIPdebugMessage("zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n", SCIPvarGetIndex(var), oldsolval, shiftval); /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement * might affect many LP rows and their current slacks and thus make further rounding steps possible */ improvementfound = TRUE; } /* if solution value of variable has become feasibly integral due to rounding step, * variable is put at the end of remaining candidates array so as not to be considered in future loops */ if( SCIPisFeasIntegral(scip, solarray[c]) ) { zilpcands[c] = zilpcands[currentlpcands - 1]; solarray[c] = solarray[currentlpcands - 1]; currentlpcands--; /* counter is decreased if end of candidates array has not been reached yet */ if( c < currentlpcands ) c--; } else if( nroundings == heurdata->maxroundingloops - 1 ) goto TERMINATE; } } /* in case that no candidate is left for rounding after the final main loop * the found solution has to be checked for feasibility in the original problem */ if( currentlpcands == 0 ) { SCIP_Bool stored; SCIP_CALL(SCIPtrySol(scip, sol, FALSE, FALSE, TRUE, FALSE, &stored)); if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol)); *result = SCIP_FOUNDSOL; } } /* free memory for all locally allocated data */ TERMINATE: SCIPfreeBufferArrayNull(scip, &activities); SCIPfreeBufferArrayNull(scip, &rowneedsslackvar); SCIPfreeBufferArrayNull(scip, &slackvarcoeffs); SCIPfreeBufferArrayNull(scip, &downslacks); SCIPfreeBufferArrayNull(scip, &upslacks); SCIPfreeBufferArrayNull(scip, &slackvars); SCIPfreeBufferArrayNull(scip, &zilpcands); SCIPfreeBufferArrayNull(scip, &solarray); return retcode; }
/** generates all facets, from which facet i could be obtained by a decreasing + to - flip * or a nonincreasing - to + flip and tests whether they are among the fmax nearest ones */ static void generateNeighborFacets( SCIP* scip, /**< SCIP data structure */ SCIP_Bool** facets, /**< facets got so far */ SCIP_Real* lambda, /**< distances of the facets */ SCIP_Real* rayorigin, /**< origin of the shooting ray */ SCIP_Real* raydirection, /**< direction of the shooting ray */ SCIP_Real* negquotient, /**< array by which coordinates are sorted */ int nsubspacevars, /**< dimension of fractional space */ int f_max, /**< maximal number of facets to create */ int i, /**< current facet */ int* nfacets /**< number of facets */ ) { SCIP_Real p; SCIP_Real q; SCIP_Real lam; int minplus; int j; assert(scip != NULL); assert(facets != NULL); assert(facets[i] != NULL); assert(lambda != NULL); assert(rayorigin != NULL); assert(raydirection != NULL); assert(negquotient != NULL); assert(nfacets != NULL); assert(0 <= i && i < f_max); /* determine the p and q values of the next facet to fix as a closest one */ p = 0.5 * nsubspacevars; q = 0.0; for( j = nsubspacevars - 1; j >= 0; --j ) { if( facets[i][j] ) { p -= rayorigin[j]; q += raydirection[j]; } else { p += rayorigin[j]; q -= raydirection[j]; } } /* get the first + entry of the facet */ minplus = -1; for( j = 0; j < nsubspacevars; ++j ) { if( facets[i][j] ) { minplus = j; break; } } /* facet (- - ... -) cannot be hit, because raydirection >= 0 */ assert(minplus >= 0); assert(q != 0.0); assert(SCIPisFeasEQ(scip, lambda[i], p/q)); assert(lambda[i] >= 0.0); /* reverse search for facets from which the actual facet can be got by a single, decreasing + to - flip */ /* a facet will be inserted into the queue, iff it is one of the fmax closest ones already found */ for( j = 0; j < nsubspacevars && !facets[i][j] && SCIPisFeasGT(scip, negquotient[j], lambda[i]); ++j ) { if( SCIPisFeasPositive(scip, q + 2*raydirection[j]) ) { lam = (p - 2*rayorigin[j]) / (q + 2*raydirection[j]); tryToInsert(scip, facets, lambda, i, j, f_max, nsubspacevars, lam, nfacets); } } /* reverse search for facets from which the actual facet can be got by a single, nonincreasing - to + flip */ /* a facet will be inserted into the queue, iff it is one of the fmax closest ones already found */ for( j = nsubspacevars - 1; j >= 0 && facets[i][j] && SCIPisFeasLE(scip, negquotient[j], lambda[i]); --j ) { if( SCIPisFeasPositive(scip, q - 2*raydirection[j]) ) { lam = (p + 2*rayorigin[j]) / (q - 2*raydirection[j]); if( negquotient[minplus] <= lam ) tryToInsert(scip, facets, lambda, i, j, f_max, nsubspacevars, lam, nfacets); } } #ifndef NDEBUG for( j = 1; j < f_max; j++) assert(SCIPisFeasGE(scip, lambda[j], lambda[j-1])); #endif }
/** 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; }
/** presolving execution method */ static SCIP_DECL_PRESOLEXEC(presolExecTrivial) { /*lint --e{715}*/ SCIP_VAR** vars; int nvars; int v; assert(result != NULL); *result = SCIP_DIDNOTFIND; /* get the problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* scan the variables for trivial bound reductions * (loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array) */ for( v = nvars-1; v >= 0; --v ) { SCIP_Real lb; SCIP_Real ub; SCIP_Bool infeasible; SCIP_Bool fixed; /* get variable's bounds */ lb = SCIPvarGetLbGlobal(vars[v]); ub = SCIPvarGetUbGlobal(vars[v]); /* is variable integral? */ if( SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real newlb; SCIP_Real newub; /* round fractional bounds on integer variables */ newlb = SCIPfeasCeil(scip, lb); newub = SCIPfeasFloor(scip, ub); /* check bounds on variable for infeasibility */ if( newlb > newub + 0.5 ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible: integral variable <%s> has bounds [%.17f,%.17f] rounded to [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, newub); *result = SCIP_CUTOFF; return SCIP_OKAY; } /* fix variables with equal bounds */ if( newlb > newub - 0.5 ) { SCIPdebugMessage("fixing integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, newub); SCIP_CALL( SCIPfixVar(scip, vars[v], newlb, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } assert(fixed); (*nfixedvars)++; } else { /* round fractional bounds */ if( !SCIPisFeasEQ(scip, lb, newlb) ) { SCIPdebugMessage("rounding lower bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub, newlb, ub); SCIP_CALL( SCIPchgVarLb(scip, vars[v], newlb) ); (*nchgbds)++; } if( !SCIPisFeasEQ(scip, ub, newub) ) { SCIPdebugMessage("rounding upper bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), newlb, ub, newlb, newub); SCIP_CALL( SCIPchgVarUb(scip, vars[v], newub) ); (*nchgbds)++; } } } else { /* check bounds on continuous variable for infeasibility */ if( SCIPisFeasGT(scip, lb, ub) ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible: continuous variable <%s> has bounds [%.17f,%.17f]\n", SCIPvarGetName(vars[v]), lb, ub); *result = SCIP_CUTOFF; return SCIP_OKAY; } /* fix variables with equal bounds */ if( SCIPisEQ(scip, lb, ub) ) { SCIP_Real fixval; #ifdef FIXSIMPLEVALUE fixval = SCIPselectSimpleValue(lb - 0.9 * SCIPepsilon(scip), ub + 0.9 * SCIPepsilon(scip), MAXDNOM); #else fixval = (lb + ub)/2; #endif SCIPdebugMessage("fixing continuous variable <%s>[%.17f,%.17f] to %.17f\n", SCIPvarGetName(vars[v]), lb, ub, fixval); SCIP_CALL( SCIPfixVar(scip, vars[v], fixval, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } assert(fixed); (*nfixedvars)++; } } } return SCIP_OKAY; }
/** create the extra constraint of local branching and add it to subscip */ static SCIP_RETCODE addLocalBranchingConstraint( SCIP* scip, /**< SCIP data structure of the original problem */ SCIP* subscip, /**< SCIP data structure of the subproblem */ SCIP_VAR** subvars, /**< variables of the subproblem */ SCIP_HEURDATA* heurdata /**< heuristic's data structure */ ) { SCIP_CONS* cons; /* local branching constraint to create */ SCIP_VAR** consvars; SCIP_VAR** vars; SCIP_SOL* bestsol; int nbinvars; int i; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* consvals; char consname[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_localbranchcons", SCIPgetProbName(scip)); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, NULL, NULL, NULL) ); bestsol = SCIPgetBestSol(scip); assert( bestsol != NULL ); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) ); /* set initial left and right hand sides of local branching constraint */ lhs = (SCIP_Real)heurdata->emptyneighborhoodsize + 1.0; rhs = (SCIP_Real)heurdata->curneighborhoodsize; /* create the distance (to incumbent) function of the binary variables */ for( i = 0; i < nbinvars; i++ ) { SCIP_Real solval; solval = SCIPgetSolVal(scip, bestsol, vars[i]); assert( SCIPisFeasIntegral(scip,solval) ); /* is variable i part of the binary support of bestsol? */ if( SCIPisFeasEQ(scip,solval,1.0) ) { consvals[i] = -1.0; rhs -= 1.0; lhs -= 1.0; } else consvals[i] = 1.0; consvars[i] = subvars[i]; assert( SCIPvarGetType(consvars[i]) == SCIP_VARTYPE_BINARY ); } /* creates localbranching constraint and adds it to subscip */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, consname, nbinvars, consvars, consvals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free local memory */ SCIPfreeBufferArray(scip, &consvals); SCIPfreeBufferArray(scip, &consvars); return SCIP_OKAY; }
/** reduced cost pricing method of variable pricer for feasible LPs */ static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking) { /*lint --e{715}*/ SCIP* subscip; SCIP_PRICERDATA* pricerdata; SCIP_CONS** conss; SCIP_VAR** vars; int* ids; SCIP_Bool addvar; SCIP_SOL** sols; int nsols; int s; int nitems; SCIP_Longint capacity; SCIP_Real timelimit; SCIP_Real memorylimit; assert(scip != NULL); assert(pricer != NULL); (*result) = SCIP_DIDNOTRUN; /* get the pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); capacity = pricerdata->capacity; conss = pricerdata->conss; ids = pricerdata->ids; nitems = pricerdata->nitems; /* get the remaining time and memory limit */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; /* initialize SCIP */ SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* create problem in sub SCIP */ SCIP_CALL( SCIPcreateProbBasic(subscip, "pricing") ); SCIP_CALL( SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* set time and memory limit */ SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPallocMemoryArray(subscip, &vars, nitems) ); /* initialization local pricing problem */ SCIP_CALL( initPricing(scip, pricerdata, subscip, vars) ); SCIPdebugMessage("solve pricer problem\n"); /* solve sub SCIP */ SCIP_CALL( SCIPsolve(subscip) ); sols = SCIPgetSols(subscip); nsols = SCIPgetNSols(subscip); addvar = FALSE; /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master, * that is the objective value i greater than 1.0 */ for( s = 0; s < nsols; ++s ) { SCIP_Bool feasible; SCIP_SOL* sol; /* the soultion should be sorted w.r.t. the objective function value */ assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s-1]), SCIPgetSolOrigObj(subscip, sols[s]))); sol = sols[s]; assert(sol != NULL); /* check if solution is feasible in original sub SCIP */ SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE ) ); if( !feasible ) { SCIPwarningMessage(scip, "solution in pricing problem (capacity <%d>) is infeasible\n", capacity); continue; } /* check if the solution has a value greater than 1.0 */ if( SCIPisFeasGT(subscip, SCIPgetSolOrigObj(subscip, sol), 1.0) ) { SCIP_VAR* var; SCIP_VARDATA* vardata; int* consids; char strtmp[SCIP_MAXSTRLEN]; char name[SCIP_MAXSTRLEN]; int nconss; int o; int v; SCIPdebug( SCIP_CALL( SCIPprintSol(subscip, sol, NULL, FALSE) ) ); nconss = 0; (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items"); SCIP_CALL( SCIPallocBufferArray(scip, &consids, nitems) ); /* check which variables are fixed -> which item belongs to this packing */ for( o = 0, v = 0; o < nitems; ++o ) { if( !SCIPconsIsEnabled(conss[o]) ) continue; assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0); if( SCIPgetSolVal(subscip, sol, vars[v]) > 0.5 ) { (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]); strcat(name, strtmp); consids[nconss] = o; nconss++; } else assert( SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0) ); v++; } SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss) ); /* create variable for a new column with objective function coefficient 0.0 */ SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, FALSE, TRUE, vardata) ); /* add the new variable to the pricer store */ SCIP_CALL( SCIPaddPricedVar(scip, var, 1.0) ); addvar = TRUE; /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have * a positive reduced cost */ SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) ); /* check which variable are fixed -> which orders belong to this packing */ for( v = 0; v < nconss; ++v ) { assert(SCIPconsIsEnabled(conss[consids[v]])); SCIP_CALL( SCIPaddCoefSetppc(scip, conss[consids[v]], var) ); } SCIPdebug(SCIPprintVar(scip, var, NULL) ); SCIP_CALL( SCIPreleaseVar(scip, &var) ); SCIPfreeBufferArray(scip, &consids); } else break; } /* free pricer MIP */ SCIPfreeMemoryArray(subscip, &vars); if( addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL ) (*result) = SCIP_SUCCESS; /* free sub SCIP */ SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** scoring callback for distribution diving. best candidate maximizes the distribution score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreDistributiondiving) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_Real upscore; SCIP_Real downscore; int varindex; heurdata = SCIPheurGetData(SCIPdivesetGetHeur(diveset)); assert(heurdata != NULL); /* process pending bound change events */ while( heurdata->nupdatedvars > 0 ) { SCIP_VAR* nextvar; /* pop the next variable from the queue and process its bound changes */ nextvar = heurdataPopBoundChangeVar(scip, heurdata); assert(nextvar != NULL); SCIP_CALL( varProcessBoundChanges(scip, heurdata, nextvar) ); } assert(cand != NULL); varindex = SCIPvarGetProbindex(cand); /* terminate with a penalty for inactive variables, which the plugin can currently not score * this should never happen with default settings where only LP branching candidates are iterated, but might occur * if other constraint handlers try to score an inactive variable that was (multi-)aggregated or negated */ if( varindex == - 1 ) { *score = -1.0; *roundup = FALSE; return SCIP_OKAY; } /* in debug mode, ensure that all bound process events which occurred in the mean time have been captured * by the heuristic event system */ assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(cand), SCIPvarGetUbLocal(cand))); assert(0 <= varindex && varindex < heurdata->varpossmemsize); assert((heurdata->currentlbs[varindex] == SCIP_INVALID) == (heurdata->currentubs[varindex] == SCIP_INVALID));/*lint !e777 doesn't like comparing floats for equality */ assert((heurdata->currentlbs[varindex] == SCIP_INVALID) || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(cand), heurdata->currentlbs[varindex])); /*lint !e777 */ assert((heurdata->currentubs[varindex] == SCIP_INVALID) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(cand), heurdata->currentubs[varindex])); /*lint !e777 */ /* if the heuristic has not captured the variable bounds yet, this can be done now */ if( heurdata->currentlbs[varindex] == SCIP_INVALID ) /*lint !e777 */ heurdataUpdateCurrentBounds(scip, heurdata, cand); upscore = 0.0; downscore = 0.0; /* loop over candidate rows and determine the candidate up- and down- branching score w.r.t. the score parameter */ SCIP_CALL( calcBranchScore(scip, heurdata, cand, candsol, &upscore, &downscore, heurdata->score) ); /* score is simply the maximum of the two individual scores */ *roundup = (upscore > downscore); *score = MAX(upscore, downscore); return SCIP_OKAY; }
/** 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; }
/* check whether coef is the r-th row of the inverse basis matrix B^-1; this is * the case if( coef * B ) is the r-th unit vector */ SCIP_RETCODE SCIPdebugCheckBInvRow( SCIP* scip, /**< SCIP data structure */ int r, /**< row number */ SCIP_Real* coef /**< r-th row of the inverse basis matrix */ ) { SCIP_Real vecval; SCIP_Real matrixval; int* basisind; int nrows; int idx; int i; int k; assert(scip != NULL); nrows = SCIPgetNLPRows(scip); /* get basic indices for the basic matrix B */ SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* loop over the columns of B */ for( k = 0; k < nrows; ++k ) { vecval = 0.0; /* indices of basic columns and rows: * - index i >= 0 corresponds to column i, * - index i < 0 to row -i-1 */ idx = basisind[k]; /* check if we have a slack variable; this is the case if idx < 0 */ if( idx >= 0 ) { /* loop over the rows to compute the corresponding value in the unit vector */ for( i = 0; i < nrows; ++i ) { SCIP_CALL( SCIPlpiGetCoef(scip->lp->lpi, i, idx, &matrixval) ); vecval += coef[i] * matrixval; } } else { assert( idx < 0 ); /* retransform idx * - index i >= 0 corresponds to column i, * - index i < 0 to row -i-1 */ idx = -idx - 1; assert( idx >= 0 && idx < nrows ); /* since idx < 0 we are in the case of a slack variable, i.e., the corresponding column is the idx-unit vector; note that some LP solver return a -idx-unit vector */ /* vecval = REALABS(coef[idx]);*/ vecval = coef[idx]; } /* check if vecval fits to the r-th unit vector */ if( k == r && !SCIPisFeasEQ(scip, vecval, 1.0) ) { /* we expected a 1.0 and found something different */ SCIPwarningMessage("checked SCIPgetLPBInvRow() found value <%g> expected 1.0\n", vecval); } else if( k != r && !SCIPisFeasZero(scip, vecval) ) { /* we expected a 0.0 and found something different */ SCIPwarningMessage("checked SCIPgetLPBInvRow() found value <%g> expected 0.0\n", vecval); } } SCIPfreeBufferArray(scip, &basisind); return SCIP_OKAY; }
/** separate */ static SCIP_RETCODE sep_flow( SCIP* scip, /**< SCIP data structure */ SCIP_CONSHDLR* conshdlr, /**< constraint handler */ SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ SCIP_CONSDATA* consdata, /**< constraint data */ int maxcuts, /**< maximal number of cuts */ int* ncuts /**< pointer to store number of cuts */ ) { GRAPH* g; SCIP_VAR** vars; SCIP_ROW* row = NULL; SCIP_Real* xval; SCIP_Real sum; int i; int k; int j; int ind; int layer; int count = 0; unsigned int flowsep; assert(scip != NULL); assert(conshdlr != NULL); assert(conshdlrdata != NULL); vars = SCIPprobdataGetVars(scip); flowsep = conshdlrdata->flowsep; /* get the graph */ g = consdata->graph; assert(g != NULL); xval = SCIPprobdataGetXval(scip, NULL); assert(xval != NULL); for(i = 0; i < g->knots; i++) { for(layer = 0; layer < g->layers; layer++) { /* continue at root */ if( i == g->source[layer] ) continue; /* at terminal: input sum == 1 * basically a cut (starcut)) */ if( g->term[i] == layer ) { sum = 0.0; for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; sum += (xval != NULL) ? xval[ind] : 0.0; } if( !SCIPisFeasEQ(scip, sum, 1.0) ) { SCIP_Bool infeasible; SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, "term", 1.0, 1.0, FALSE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); for(k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k]) { ind = layer * g->edges + k; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], 1.0) ); } SCIP_CALL( SCIPflushRowExtensions(scip, row) ); SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) ); count++; SCIP_CALL( SCIPreleaseRow(scip, &row) ); if( *ncuts + count >= maxcuts ) goto TERMINATE; } } /* no flows ? */ if( !flowsep ) continue; /* the value of each outgoing edge needs to be smaller than the sum of the ingoing edges */ for( j = g->outbeg[i]; j != EAT_LAST; j = g->oeat[j] ) { ind = layer * g->edges + j; sum = (xval != NULL) ? -xval[ind] : -1.0; for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; sum += (xval != NULL) ? xval[ind] : 0.0; } if( SCIPisFeasNegative(scip, sum) ) { SCIP_Bool infeasible; SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, "flow", 0.0, SCIPinfinity(scip), FALSE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); ind = layer * g->edges + j; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], -1.0) ); for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], 1.0) ); } SCIP_CALL( SCIPflushRowExtensions(scip, row) ); SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) ); count++; SCIP_CALL( SCIPreleaseRow(scip, &row) ); if( *ncuts + count >= maxcuts ) goto TERMINATE; } } /* consider only non terminals */ if( g->term[i] == layer ) continue; /* input of a vertex has to be <= 1.0 */ sum = 0.0; for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; sum += (xval != NULL) ? xval[ind] : 1.0; } if( SCIPisFeasGT(scip, sum, 1.0) ) { SCIP_Bool infeasible; SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, "infl", -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], 1.0) ); } SCIP_CALL( SCIPflushRowExtensions(scip, row) ); SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) ); count++; SCIP_CALL( SCIPreleaseRow(scip, &row) ); if( *ncuts + count >= maxcuts ) goto TERMINATE; } /* incoming flow <= outgoing flow */ sum = 0.0; for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; sum -= (xval != NULL) ? xval[ind] : 1.0; } for( k = g->outbeg[i]; k != EAT_LAST; k = g->oeat[k] ) { ind = layer * g->edges + k; sum += (xval != NULL) ? xval[ind] : 0.0; } if( SCIPisFeasNegative(scip, sum) ) { SCIP_Bool infeasible; SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, conshdlr, "bala", 0.0, (g->locals[layer] == 2) ? 0.0 : SCIPinfinity(scip), FALSE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, row) ); for( k = g->inpbeg[i]; k != EAT_LAST; k = g->ieat[k] ) { ind = layer * g->edges + k; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], -1.0) ); } for( k = g->outbeg[i]; k != EAT_LAST; k = g->oeat[k] ) { ind = layer * g->edges + k; SCIP_CALL( SCIPaddVarToRow(scip, row, vars[ind], 1.0) ); } SCIP_CALL( SCIPflushRowExtensions(scip, row) ); SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) ); count++; SCIP_CALL( SCIPreleaseRow(scip, &row) ); if( *ncuts + count >= maxcuts ) goto TERMINATE; } } } TERMINATE: SCIPdebugMessage("In/Out Separator: %d Inequalities added\n", count); *ncuts += count; return SCIP_OKAY; }
/** 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; }
/** perform dual presolving */ static SCIP_RETCODE performDualfix( SCIP* scip, /**< SCIP data structure */ int* nfixedvars, /**< pointer to store number of fixed variables */ SCIP_Bool* unbounded, /**< pointer to store if an unboundness was detected */ SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */ ) { SCIP_VAR** vars; int nvars; int v; /* get active problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* look for fixable variables * loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array */ for( v = nvars - 1; v >= 0; --v ) { SCIP_VAR* var; SCIP_Real bound; SCIP_Real obj; SCIP_Bool infeasible; SCIP_Bool fixed; var = vars[v]; assert(var != NULL); /* don't perform dual presolving operations on deleted variables */ if( SCIPvarIsDeleted(var) ) continue; /* ignore already fixed variables (use feasibility tolerance since this is used in SCIPfixVar() */ if( SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ) continue; obj = SCIPvarGetObj(var); /* if the objective coefficient of the variable is 0 and it may be rounded both * up and down, then fix it to the closest feasible value to 0 */ if( SCIPisZero(scip, obj) && SCIPvarMayRoundDown(var) && SCIPvarMayRoundUp(var) ) { SCIP_Real roundbound; bound = SCIPvarGetLbGlobal(var); if( SCIPisLT(scip, bound, 0.0) ) { if( SCIPisLE(scip, 0.0, SCIPvarGetUbGlobal(var)) ) bound = 0.0; else { /* try to take an integer value, only for polishing */ roundbound = SCIPfloor(scip, SCIPvarGetUbGlobal(var)); if( roundbound < bound ) bound = SCIPvarGetUbGlobal(var); else bound = roundbound; } } else { /* try to take an integer value, only for polishing */ roundbound = SCIPceil(scip, bound); if( roundbound < SCIPvarGetUbGlobal(var) ) bound = roundbound; } SCIPdebugMessage("fixing variable <%s> with objective 0 to %g\n", SCIPvarGetName(var), bound); } else { /* if it is always possible to round variable in direction of objective value, fix it to its proper bound */ if( SCIPvarMayRoundDown(var) && !SCIPisNegative(scip, obj) ) { bound = SCIPvarGetLbGlobal(var); if ( SCIPisInfinity(scip, -bound) ) { /* variable can be fixed to -infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksUp(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than -infinity and do nothing * here. */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d uplocks to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksUp(var), bound); } else if( SCIPvarMayRoundUp(var) && !SCIPisPositive(scip, obj) ) { bound = SCIPvarGetUbGlobal(var); if ( SCIPisInfinity(scip, bound) ) { /* variable can be fixed to infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksDown(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than +infinity and do nothing * here */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d downlocks to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksDown(var), bound); } else continue; } if( SCIPisInfinity(scip, REALABS(bound)) && !SCIPisZero(scip, obj) ) { SCIPdebugMessage(" -> unbounded fixing\n"); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible or unbounded: variable <%s> with objective %.15g can be made infinitely %s\n", SCIPvarGetName(var), SCIPvarGetObj(var), bound < 0.0 ? "small" : "large"); *unbounded = TRUE; return SCIP_OKAY; } /* apply the fixing */ SCIPdebugMessage("apply fixing of variable %s to %g\n", SCIPvarGetName(var), bound); SCIP_CALL( SCIPfixVar(scip, var, bound, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *cutoff = TRUE; return SCIP_OKAY; } assert(fixed || (SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisFeasEQ(scip, bound, SCIPvarGetLbLocal(var)) && SCIPisFeasEQ(scip, bound, SCIPvarGetUbLocal(var)))); (*nfixedvars)++; } return SCIP_OKAY; }
/** generates the direction of the shooting ray as the average of the normalized non-basic vars and rows */ static SCIP_RETCODE generateAverageNBRay( SCIP* scip, /**< SCIP data structure */ SCIP_Real* raydirection, /**< shooting ray */ int* fracspace, /**< index set of fractional variables */ SCIP_VAR** subspacevars, /**< pointer to fractional space variables */ int nsubspacevars /**< dimension of fractional space */ ) { SCIP_ROW** rows; SCIP_COL** cols; int nrows; int ncols; int i; assert(scip != NULL); assert(raydirection != NULL); assert(fracspace != NULL); assert(subspacevars != NULL); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); /* add up non-basic variables */ for( i = nsubspacevars - 1; i >= 0; --i ) { SCIP_Real solval; solval = SCIPvarGetLPSol(subspacevars[i]); if( SCIPisFeasEQ(scip, solval, SCIPvarGetLbLocal(subspacevars[i])) ) raydirection[i] = +1.0; else if( SCIPisFeasEQ(scip, solval, SCIPvarGetUbLocal(subspacevars[i])) ) raydirection[i] = -1.0; else raydirection[i] = 0.0; } /* add up non-basic rows */ for( i = nrows - 1; i >= 0; --i ) { SCIP_Real dualsol; SCIP_Real factor; SCIP_Real* coeffs; SCIP_Real rownorm; int j; int nnonz; dualsol = SCIProwGetDualsol(rows[i]); if( SCIPisFeasPositive(scip, dualsol) ) factor = 1.0; else if( SCIPisFeasNegative(scip, dualsol) ) factor = -1.0; else continue; /* get the row's data */ coeffs = SCIProwGetVals(rows[i]); cols = SCIProwGetCols(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); rownorm = 0.0; for( j = nnonz - 1; j >= 0; --j ) { SCIP_VAR* var; var = SCIPcolGetVar(cols[j]); if( fracspace[SCIPvarGetProbindex(var)] >= 0 ) rownorm += coeffs[j] * coeffs[j]; } if( SCIPisFeasZero(scip,rownorm) ) continue; else { assert(rownorm > 0); rownorm = SQRT(rownorm); } for( j = nnonz - 1; j >= 0; --j ) { SCIP_VAR* var; int f; var = SCIPcolGetVar(cols[j]); f = fracspace[SCIPvarGetProbindex(var)]; if( f >= 0 ) { raydirection[f] += factor * coeffs[j] / rownorm; assert(SCIP_REAL_MIN <= raydirection[f] && raydirection[f] <= SCIP_REAL_MAX); } } } return SCIP_OKAY; }