/** returns the next unprocessed variable (last in, first out) with pending bound changes, or NULL */ static SCIP_VAR* heurdataPopBoundChangeVar( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata /**< heuristic data */ ) { SCIP_VAR* var; int varpos; int varindex; assert(heurdata->nupdatedvars >= 0); /* return if no variable is currently pending */ if( heurdata->nupdatedvars == 0 ) return NULL; varpos = heurdata->nupdatedvars - 1; var = heurdata->updatedvars[varpos]; assert(var != NULL); varindex = SCIPvarGetProbindex(var); assert(0 <= varindex && varindex < heurdata->varpossmemsize); assert(varpos == heurdata->varposs[varindex]); heurdata->varposs[varindex] = -1; heurdata->nupdatedvars--; return var; }
/** creates the rows of the subproblem */ static SCIP_RETCODE createRows( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars /**< the variables of the subproblem */ ) { SCIP_ROW** rows; /* original scip rows */ SCIP_CONS* cons; /* new constraint */ SCIP_VAR** consvars; /* new constraint's variables */ SCIP_COL** cols; /* original row's columns */ SCIP_Real constant; /* constant added to the row */ SCIP_Real lhs; /* left hand side of the row */ SCIP_Real rhs; /* left right side of the row */ SCIP_Real* vals; /* variables' coefficient values of the row */ int nrows; int nnonz; int i; int j; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert(lhs <= rhs); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } return SCIP_OKAY; }
/** free heuristic data */ static SCIP_RETCODE heurdataFreeArrays( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata /**< heuristic data */ ) { assert(heurdata->memsize == 0 || heurdata->rowmeans != NULL); assert(heurdata->memsize >= 0); if( heurdata->memsize > 0 ) { SCIPfreeBufferArray(scip, &heurdata->rowmeans); SCIPfreeBufferArray(scip, &heurdata->rowvariances); SCIPfreeBufferArray(scip, &heurdata->rowinfinitiesup); SCIPfreeBufferArray(scip, &heurdata->rowinfinitiesdown); heurdata->memsize = 0; } if( heurdata->varpossmemsize > 0 ) { SCIP_VAR** vars; int v; assert(heurdata->varpossmemsize == SCIPgetNVars(scip)); vars = SCIPgetVars(scip); for( v = heurdata->varpossmemsize - 1; v >= 0; --v ) { SCIP_VAR* var; var = vars[v]; assert(var != NULL); assert(v == SCIPvarGetProbindex(var)); SCIP_CALL( SCIPdropVarEvent(scip, var, EVENT_DISTRIBUTION, heurdata->eventhdlr, NULL, heurdata->varfilterposs[v]) ); } SCIPfreeBufferArray(scip, &heurdata->currentlbs); SCIPfreeBufferArray(scip, &heurdata->currentubs); SCIPfreeBufferArray(scip, &heurdata->updatedvars); SCIPfreeBufferArray(scip, &heurdata->varposs); SCIPfreeBufferArray(scip, &heurdata->varfilterposs); } /* allocate variable update event processing array storage */ heurdata->varpossmemsize = 0; heurdata->nupdatedvars = 0; return SCIP_OKAY; }
/** add variable to the bound change event queue; skipped if variable is already in there, or if variable has * no row currently watched */ static void heurdataAddBoundChangeVar( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_VAR* var /**< the variable whose bound changes need to be processed */ ) { int varindex; int varpos; assert(var != NULL); varindex = SCIPvarGetProbindex(var); assert(-1 <= varindex && varindex < heurdata->varpossmemsize); /* if variable is not active, it should not be watched */ if( varindex == -1 ) return; varpos = heurdata->varposs[varindex]; assert(varpos < heurdata->nupdatedvars); /* nothing to do if variable is already in the queue */ if( varpos >= 0 ) { assert(heurdata->updatedvars[varpos] == var); return; } /* if none of the variables rows was calculated yet, variable needs not to be watched */ assert((heurdata->currentlbs[varindex] == SCIP_INVALID) == (heurdata->currentubs[varindex] == SCIP_INVALID)); /*lint !e777 doesn't like comparing floats for equality */ /* we don't need to enqueue the variable if it hasn't been watched so far */ if( heurdata->currentlbs[varindex] == SCIP_INVALID ) /*lint !e777 see above */ return; /* add the variable to the heuristic data of variables to process updates for */ assert(heurdata->varpossmemsize > heurdata->nupdatedvars); varpos = heurdata->nupdatedvars; heurdata->updatedvars[varpos] = var; heurdata->varposs[varindex] = varpos; ++heurdata->nupdatedvars; }
/** update the variables current lower and upper bound */ static void heurdataUpdateCurrentBounds( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ SCIP_VAR* var /**< the variable to update current bounds */ ) { int varindex; SCIP_Real lblocal; SCIP_Real ublocal; assert(var != NULL); varindex = SCIPvarGetProbindex(var); assert(0 <= varindex && varindex < heurdata->varpossmemsize); lblocal = SCIPvarGetLbLocal(var); ublocal = SCIPvarGetUbLocal(var); assert(SCIPisFeasLE(scip, lblocal, ublocal)); heurdata->currentlbs[varindex] = lblocal; heurdata->currentubs[varindex] = ublocal; }
/** reads a block section */ static SCIP_RETCODE readBlock( SCIP* scip, /**< SCIP data structure */ BLKINPUT* blkinput, /**< BLK reading data */ SCIP_READERDATA* readerdata /**< reader data */ ) { int blockid; assert(blkinput != NULL); blockid = blkinput->blocknr; while( getNextToken(blkinput) ) { SCIP_VAR* var; int varidx; int oldblock; /* check if we reached a new section */ if( isNewSection(scip, blkinput) ) return SCIP_OKAY; /* the token must be the name of an existing variable */ var = SCIPfindVar(scip, blkinput->token); if( var == NULL ) { syntaxError(scip, blkinput, "unknown variable in block section"); return SCIP_OKAY; } varidx = SCIPvarGetProbindex(var); oldblock = readerdata->varstoblock[varidx]; /* set the block number of the variable to the number of the current block */ if( oldblock == NOVALUE ) { SCIPdebugMessage("\tVar %s temporary in block %d.\n", SCIPvarGetName(var), blockid); readerdata->varstoblock[varidx] = blockid; ++(readerdata->nblockvars[blockid]); } /* variable was assigned to another (non-linking) block before, so it becomes a linking variable, now */ else if( (oldblock != LINKINGVALUE) ) { assert(oldblock != blockid); SCIPdebugMessage("\tVar %s is linking (old %d != %d new).\n", SCIPvarGetName(var), oldblock, blockid); readerdata->varstoblock[varidx] = LINKINGVALUE; /* decrease the number of variables in the old block and increase the number of linking variables */ --(readerdata->nblockvars[oldblock]); ++(readerdata->nlinkingvars); assert(readerdata->nlinkingvarsblocks[varidx] == 0); assert(readerdata->linkingvarsblocks[varidx] == NULL); SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->linkingvarsblocks[varidx], 2) ); /*lint !e506 !e866*/ readerdata->linkingvarsblocks[varidx][0] = oldblock; readerdata->linkingvarsblocks[varidx][1] = blockid; readerdata->nlinkingvarsblocks[varidx] = 2; } /* variable is a linking variable already, store the new block to which it belongs */ else { assert(oldblock == LINKINGVALUE); assert(readerdata->nlinkingvarsblocks[varidx] >= 2); assert(readerdata->linkingvarsblocks[varidx] != NULL); SCIP_CALL( SCIPreallocMemoryArray(scip, &readerdata->linkingvarsblocks[varidx], readerdata->nlinkingvarsblocks[varidx] + 1) ); /*lint !e866*/ readerdata->linkingvarsblocks[varidx][readerdata->nlinkingvarsblocks[varidx]] = blockid; ++(readerdata->nlinkingvarsblocks[varidx]); } } return SCIP_OKAY; }
/* Generate edges from given row * * We avoid parallel edges. Each row generates a clique in the graph. */ static SCIP_RETCODE createEdgesFromRow( SCIP* scip, /**< SCIP data structure */ SCIP_VAR** vars, /**< array of constraint variables */ SCIP_Real* vals, /**< array of constraint values */ int nvars, /**< number of constraint variables */ SparseGraph* G /**< graph */ ) { int i, j; SCIP_Real w; assert( scip != NULL ); assert( nvars > 0 ); /* compute weight */ w = 0; for( i = 0; i < nvars; ++i ) w += ABS(vals[i]); /* generate edges */ for( i = 0; i < nvars; ++i ) { int s; s = SCIPvarGetProbindex(vars[i]); assert( s >= 0 ); for( j = i+1; j < nvars; ++j ) { unsigned int k; int t; int a; t = SCIPvarGetProbindex(vars[j]); assert( t >= 0 ); /* search whether edge is already present */ k = 0; a = G->A[s][k]; while( a >= 0 ) { /* if we found edge, add weight */ if( a == t ) { G->W[s][k] += w; break; } a = G->A[s][++k]; assert( k <= G->size[s] ); } /* add new edge */ if( a < 0 ) { /* forward edge */ SCIP_CALL( ensureEdgeCapacity(scip, G, (unsigned int) s) ); k = G->deg[s]; assert( G->A[s][k] == -1 ); G->A[s][k] = t; G->W[s][k] = w; G->A[s][k+1] = -1; /*lint !e679*/ ++G->deg[s]; /* backward edge */ SCIP_CALL( ensureEdgeCapacity(scip, G, (unsigned int) t) ); k = G->deg[t]; assert( G->A[t][k] == -1 ); G->A[t][k] = s; G->W[t][k] = w; G->A[t][k+1] = -1; /*lint !e679*/ ++G->deg[t]; /* increase number of edges */ ++G->m; } } } return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ SCIP_Bool binarybounds, /**< should general integers get binary bounds [floor(.),ceil(.)] ? */ SCIP_Bool uselprows, /**< should subproblem be created out of the rows in the LP rows? */ SCIP_Bool* success /**< pointer to store whether the problem was created successfully */ ) { SCIP_VAR** vars; /* original SCIP variables */ SCIP_Real fixingrate; int nvars; int nbinvars; int nintvars; int i; int fixingcounter; assert(scip != NULL); assert(subscip != NULL); assert(subvars != NULL); assert(0.0 <= minfixingrate && minfixingrate <= 1.0); /* get required variable data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); fixingcounter = 0; /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { SCIP_Real lpsolval; SCIP_Real lb; SCIP_Real ub; /* get the current LP solution for each variable */ lpsolval = SCIPgetRelaxSolVal(scip, vars[i]); if( SCIPisFeasIntegral(scip, lpsolval) ) { /* fix variables to current LP solution if it is integral, * use exact integral value, if the variable is only integral within numerical tolerances */ lb = SCIPfloor(scip, lpsolval+0.5); ub = lb; fixingcounter++; } else if( binarybounds ) { /* if the sub problem should be a binary problem, change the bounds to nearest integers */ lb = SCIPfeasFloor(scip,lpsolval); ub = SCIPfeasCeil(scip,lpsolval); } else { /* otherwise just copy bounds */ lb = SCIPvarGetLbGlobal(vars[i]); ub = SCIPvarGetUbGlobal(vars[i]); } /* perform the bound change */ SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], lb) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], ub) ); } /* abort, if all integer variables were fixed (which should not happen for MIP) */ if( fixingcounter == nbinvars + nintvars ) { *success = FALSE; return SCIP_OKAY; } else fixingrate = fixingcounter / (SCIP_Real)(MAX(nbinvars + nintvars, 1)); SCIPdebugMessage("fixing rate: %g = %d of %d\n", fixingrate, fixingcounter, nbinvars + nintvars); /* abort, if the amount of fixed variables is insufficient */ if( fixingrate < minfixingrate ) { *success = FALSE; return SCIP_OKAY; } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; int j; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(subscip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(subscip, &consvars); } } *success = TRUE; return SCIP_OKAY; }
/** 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; }
/** 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; }
/** returns a variable, that pushes activity of the row in the given direction with minimal negative impact on other rows; * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction; * prefer fractional integers over other variables in order to become integral during the process; * shifting in a direction is forbidden, if this forces the objective value over the upper bound, or if the variable * was already shifted in the opposite direction */ static SCIP_RETCODE selectShifting( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* sol, /**< primal solution */ SCIP_ROW* row, /**< LP row */ SCIP_Real rowactivity, /**< activity of LP row */ int direction, /**< should the activity be increased (+1) or decreased (-1)? */ SCIP_Real* nincreases, /**< array with weighted number of increasings per variables */ SCIP_Real* ndecreases, /**< array with weighted number of decreasings per variables */ SCIP_Real increaseweight, /**< current weight of increase/decrease updates */ SCIP_VAR** shiftvar, /**< pointer to store the shifting variable, returns NULL if impossible */ SCIP_Real* oldsolval, /**< pointer to store old solution value of shifting variable */ SCIP_Real* newsolval /**< pointer to store new (shifted) solution value of shifting variable */ ) { SCIP_COL** rowcols; SCIP_Real* rowvals; int nrowcols; SCIP_Real activitydelta; SCIP_Real bestshiftscore; SCIP_Real bestdeltaobj; int c; assert(direction == +1 || direction == -1); assert(nincreases != NULL); assert(ndecreases != NULL); assert(shiftvar != NULL); assert(oldsolval != NULL); assert(newsolval != NULL); /* get row entries */ rowcols = SCIProwGetCols(row); rowvals = SCIProwGetVals(row); nrowcols = SCIProwGetNLPNonz(row); /* calculate how much the activity must be shifted in order to become feasible */ activitydelta = (direction == +1 ? SCIProwGetLhs(row) - rowactivity : SCIProwGetRhs(row) - rowactivity); assert((direction == +1 && SCIPisPositive(scip, activitydelta)) || (direction == -1 && SCIPisNegative(scip, activitydelta))); /* select shifting variable */ bestshiftscore = SCIP_REAL_MAX; bestdeltaobj = SCIPinfinity(scip); *shiftvar = NULL; *newsolval = 0.0; *oldsolval = 0.0; for( c = 0; c < nrowcols; ++c ) { SCIP_COL* col; SCIP_VAR* var; SCIP_Real val; SCIP_Real solval; SCIP_Real shiftval; SCIP_Real shiftscore; SCIP_Bool isinteger; SCIP_Bool isfrac; SCIP_Bool increase; col = rowcols[c]; var = SCIPcolGetVar(col); val = rowvals[c]; assert(!SCIPisZero(scip, val)); solval = SCIPgetSolVal(scip, sol, var); isinteger = (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER); isfrac = isinteger && !SCIPisFeasIntegral(scip, solval); increase = (direction * val > 0.0); /* calculate the score of the shifting (prefer smaller values) */ if( isfrac ) shiftscore = increase ? -1.0 / (SCIPvarGetNLocksUp(var) + 1.0) : -1.0 / (SCIPvarGetNLocksDown(var) + 1.0); else { int probindex; probindex = SCIPvarGetProbindex(var); if( increase ) shiftscore = ndecreases[probindex]/increaseweight; else shiftscore = nincreases[probindex]/increaseweight; if( isinteger ) shiftscore += 1.0; } if( shiftscore <= bestshiftscore ) { SCIP_Real deltaobj; if( !increase ) { /* shifting down */ assert(direction * val < 0.0); if( isfrac ) shiftval = SCIPfeasFloor(scip, solval); else { SCIP_Real lb; assert(activitydelta/val < 0.0); shiftval = solval + activitydelta/val; assert(shiftval <= solval); /* may be equal due to numerical digit erasement in the subtraction */ if( SCIPvarIsIntegral(var) ) shiftval = SCIPfeasFloor(scip, shiftval); lb = SCIPvarGetLbGlobal(var); shiftval = MAX(shiftval, lb); } } else { /* shifting up */ assert(direction * val > 0.0); if( isfrac ) shiftval = SCIPfeasCeil(scip, solval); else { SCIP_Real ub; assert(activitydelta/val > 0.0); shiftval = solval + activitydelta/val; assert(shiftval >= solval); /* may be equal due to numerical digit erasement in the subtraction */ if( SCIPvarIsIntegral(var) ) shiftval = SCIPfeasCeil(scip, shiftval); ub = SCIPvarGetUbGlobal(var); shiftval = MIN(shiftval, ub); } } if( SCIPisEQ(scip, shiftval, solval) ) continue; deltaobj = SCIPvarGetObj(var) * (shiftval - solval); if( shiftscore < bestshiftscore || deltaobj < bestdeltaobj ) { bestshiftscore = shiftscore; bestdeltaobj = deltaobj; *shiftvar = var; *oldsolval = solval; *newsolval = shiftval; } } } return SCIP_OKAY; }
/** reads the blocks section */ static SCIP_RETCODE readBlock( SCIP* scip, /**< SCIP data structure */ DECINPUT* decinput, /**< DEC reading data */ SCIP_READERDATA* readerdata /**< reader data */ ) { int oldblock; int varidx; int consindex; int i; int blockid; int nvars; SCIP_CONS* cons; SCIP_VAR** vars; SCIP_Bool conshasvar; assert(decinput != NULL); assert(readerdata != NULL); while( getNextToken(decinput) ) { /* check if we reached a new section */ if( isNewSection(scip, decinput) ) break; /* the token must be the name of an existing cons */ cons = SCIPfindCons(scip, decinput->token); if( cons == NULL ) { syntaxError(scip, decinput, "unknown constraint in block section"); break; } conshasvar = FALSE; /* get all vars for the specific constraint */ nvars = SCIPgetNVarsXXX(scip, cons); vars = NULL; if( nvars > 0 ) { SCIP_CALL( SCIPallocMemoryArray(scip, &vars, nvars) ); SCIP_CALL( SCIPgetVarsXXX(scip, cons, vars, nvars) ); } blockid = decinput->blocknr; for( i = 0; i < nvars; i ++ ) { SCIP_VAR* var; assert(vars != NULL); /* for flexelint */ if( decinput->presolved ) { var = SCIPvarGetProbvar(vars[i]); if( !SCIPisVarRelevant(var) ) continue; } else var = vars[i]; conshasvar = TRUE; /* store for each var whether it is in none, one or more blocks */ varidx = SCIPvarGetProbindex(var); assert(varidx >= 0 && varidx < SCIPgetNVars(scip)); oldblock = readerdata->varstoblock[varidx]; assert(oldblock == NOVALUE || oldblock == LINKINGVALUE || (oldblock >= 0 && oldblock < decinput->nblocks)); /* variable was assigned to no block before, just assign it to the new block */ if( oldblock == NOVALUE ) { SCIPdebugMessage("\tVar %s temporary in block %d.\n", SCIPvarGetName(vars[i]), blockid); readerdata->varstoblock[varidx] = blockid; ++(readerdata->nblockvars[blockid]); } /* variable was assigned to another (non-linking) block before, so it becomes a linking variable, now */ else if( (oldblock != LINKINGVALUE) && oldblock != blockid ) { SCIPdebugMessage("\tVar %s is linking (old %d != %d new).\n", SCIPvarGetName(vars[i]), oldblock, blockid); assert(oldblock != blockid); readerdata->varstoblock[varidx] = LINKINGVALUE; /* decrease the value again if it is a linking var */ --(readerdata->nblockvars[oldblock]); ++(readerdata->nlinkingvars); } } SCIPfreeMemoryArrayNull(scip, &vars); if( !conshasvar ) { assert(!SCIPhashmapExists(readerdata->constoblock, cons)); SCIPwarningMessage(scip, "Cons <%s> has been deleted by presolving, skipping.\n", SCIPconsGetName(cons)); continue; } /* * saving block <-> constraint */ /** @todo check if linking constraints are not in the subscipcons */ consindex = readerdata->nblockconss[blockid]; readerdata->blockconss[blockid][consindex] = cons; ++(readerdata->nblockconss[blockid]); assert(SCIPhashmapGetImage(readerdata->constoblock, cons) == (void*)(size_t) LINKINGVALUE); SCIPdebugMessage("cons %s is in block %d\n", SCIPconsGetName(cons), blockid); SCIP_CALL( SCIPhashmapSetImage(readerdata->constoblock, cons, (void*) ((size_t) blockid)) ); --(readerdata->nlinkingconss); } return SCIP_OKAY; }
/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE createSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ SCIP_Real minfixingrate, /**< percentage of integer variables that have to be fixed */ unsigned int* randseed, /**< a seed value for the random number generator */ SCIP_Bool uselprows /**< should subproblem be created out of the rows in the LP rows? */ ) { SCIP_VAR** vars; /* original scip variables */ SCIP_SOL* sol; /* pool of solutions */ SCIP_Bool* marked; /* array of markers, which variables to fixed */ SCIP_Bool fixingmarker; /* which flag should label a fixed variable? */ int nvars; int nbinvars; int nintvars; int i; int j; int nmarkers; /* get required data of the original problem */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); sol = SCIPgetBestSol(scip); assert(sol != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &marked, nbinvars+nintvars) ); if( minfixingrate > 0.5 ) { nmarkers = nbinvars + nintvars - (int) SCIPfloor(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = FALSE; } else { nmarkers = (int) SCIPceil(scip, minfixingrate*(nbinvars+nintvars)); fixingmarker = TRUE; } assert( 0 <= nmarkers && nmarkers <= SCIPceil(scip,(nbinvars+nintvars)/2.0 ) ); j = 0; BMSclearMemoryArray(marked, nbinvars+nintvars); while( j < nmarkers ) { do { i = SCIPgetRandomInt(0, nbinvars+nintvars-1, randseed); } while( marked[i] ); marked[i] = TRUE; j++; } assert( j == nmarkers ); /* change bounds of variables of the subproblem */ for( i = 0; i < nbinvars + nintvars; i++ ) { /* fix all randomly marked variables */ if( marked[i] == fixingmarker ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, sol, vars[i]); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); assert(SCIPisLE(scip, lb, ub)); /* due to dual reductions, it may happen that the solution value is not in the variable's domain anymore */ if( SCIPisLT(scip, solval, lb) ) solval = lb; else if( SCIPisGT(scip, solval, ub) ) solval = ub; /* perform the bound change */ if( !SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval) ) { SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], solval) ); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], solval) ); } } } if( uselprows ) { SCIP_ROW** rows; /* original scip rows */ int nrows; /* get the rows and their number */ SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* copy all rows to linear constraints */ for( i = 0; i < nrows; i++ ) { SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* vals; int nnonz; /* ignore rows that are only locally valid */ if( SCIProwIsLocal(rows[i]) ) continue; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]) - constant; rhs = SCIProwGetRhs(rows[i]) - constant; vals = SCIProwGetVals(rows[i]); nnonz = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); assert( lhs <= rhs ); /* allocate memory array to be filled with the corresponding subproblem variables */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nnonz) ); for( j = 0; j < nnonz; j++ ) consvars[j] = subvars[SCIPvarGetProbindex(SCIPcolGetVar(cols[j]))]; /* create a new linear constraint and add it to the subproblem */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, SCIProwGetName(rows[i]), nnonz, consvars, vals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free temporary memory */ SCIPfreeBufferArray(scip, &consvars); } } SCIPfreeBufferArray(scip, &marked); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOctane) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_SOL** first_sols; /* stores the first ffirst sols in order to check for common violation of a row */ SCIP_VAR** vars; /* the variables of the problem */ SCIP_VAR** fracvars; /* variables, that are fractional in current LP solution */ SCIP_VAR** subspacevars; /* the variables on which the search is performed. Either coinciding with vars or with the * space of all fractional variables of the current LP solution */ SCIP_Real p; /* n/2 - <delta,x> ( for some facet delta ) */ SCIP_Real q; /* <delta,a> */ SCIP_Real* rayorigin; /* origin of the ray, vector x in paper */ SCIP_Real* raydirection; /* direction of the ray, vector a in paper */ SCIP_Real* negquotient; /* negated quotient of rayorigin and raydirection, vector v in paper */ SCIP_Real* lambda; /* stores the distance of the facets (s.b.) to the origin of the ray */ SCIP_Bool usefracspace; /* determines whether the search concentrates on fractional variables and fixes integer ones */ SCIP_Bool cons_viol; /* used for checking whether a linear constraint is violated by one of the possible solutions */ SCIP_Bool success; SCIP_Bool* sign; /* signature of the direction of the ray */ SCIP_Bool** facets; /* list of extended facets */ int nvars; /* number of variables */ int nbinvars; /* number of 0-1-variables */ int nfracvars; /* number of fractional variables in current LP solution */ int nsubspacevars; /* dimension of the subspace on which the search is performed */ int nfacets; /* number of facets hidden by the ray that where already found */ int i; /* counter */ int j; /* counter */ int f_max; /* {0,1}-points to be checked */ int f_first; /* {0,1}-points to be generated at first in order to check whether a restart is necessary */ int r; /* counter */ int firstrule; int* perm; /* stores the way in which the coordinates were permuted */ int* fracspace; /* maps the variables of the subspace to the original variables */ assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); /* OCTANE is for use in 0-1 programs only */ if( nvars != nbinvars ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* don't call heuristic, if it was not successful enough in the past */ /*lint --e{647}*/ if( SCIPgetNNodes(scip) % (SCIPheurGetNCalls(heur) / (100 * SCIPheurGetNBestSolsFound(heur) + 10*heurdata->nsuccess + 1) + 1) != 0 ) return SCIP_OKAY; SCIP_CALL( SCIPgetLPBranchCands(scip, &fracvars, NULL, NULL, &nfracvars, NULL) ); /* don't use integral starting points */ if( nfracvars == 0 ) return SCIP_OKAY; /* get working pointers from heurdata */ sol = heurdata->sol; assert( sol != NULL ); f_max = heurdata->f_max; f_first = heurdata->f_first; usefracspace = heurdata->usefracspace; SCIP_CALL( SCIPallocBufferArray(scip, &fracspace, nvars) ); /* determine the space one which OCTANE should work either as the whole space or as the space of fractional variables */ if( usefracspace ) { nsubspacevars = nfracvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); BMScopyMemoryArray(subspacevars, fracvars, nsubspacevars); for( i = nvars - 1; i >= 0; --i ) fracspace[i] = -1; for( i = nsubspacevars - 1; i >= 0; --i ) fracspace[SCIPvarGetProbindex(subspacevars[i])] = i; } else { int currentindex; nsubspacevars = nvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); /* only copy the variables which are in the current LP */ currentindex = 0; for( i = 0; i < nvars; ++i ) { if( SCIPcolGetLPPos(SCIPvarGetCol(vars[i])) >= 0 ) { subspacevars[currentindex] = vars[i]; fracspace[i] = currentindex; ++currentindex; } else { fracspace[i] = -1; --nsubspacevars; } } } /* nothing to do for empty search space */ if( nsubspacevars == 0 ) return SCIP_OKAY; assert(0 < nsubspacevars && nsubspacevars <= nvars); for( i = 0; i < nsubspacevars; i++) assert(fracspace[SCIPvarGetProbindex(subspacevars[i])] == i); /* at most 2^(n-1) facets can be hit */ if( nsubspacevars < 30 ) { /*lint --e{701}*/ assert(f_max > 0); f_max = MIN(f_max, 1 << (nsubspacevars - 1) ); } f_first = MIN(f_first, f_max); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &rayorigin, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &raydirection, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &negquotient, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &sign, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &perm, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &lambda, f_max + 1) ); SCIP_CALL( SCIPallocBufferArray(scip, &facets, f_max + 1) ); for( i = f_max; i >= 0; --i ) { /*lint --e{866}*/ SCIP_CALL( SCIPallocBufferArray(scip, &facets[i], nsubspacevars) ); } SCIP_CALL( SCIPallocBufferArray(scip, &first_sols, f_first) ); *result = SCIP_DIDNOTFIND; /* starting OCTANE */ SCIPdebugMessage("run Octane heuristic on %s variables, which are %d vars, generate at most %d facets, using rule number %d\n", usefracspace ? "fractional" : "all", nsubspacevars, f_max, (heurdata->lastrule+1)%5); /* generate starting point in original coordinates */ SCIP_CALL( generateStartingPoint(scip, rayorigin, subspacevars, nsubspacevars) ); for( i = nsubspacevars - 1; i >= 0; --i ) rayorigin[i] -= 0.5; firstrule = heurdata->lastrule; ++firstrule; for( r = firstrule; r <= firstrule + 10 && !SCIPisStopped(scip); r++ ) { SCIP_ROW** rows; int nrows; /* generate shooting ray in original coordinates by certain rules */ switch(r % 5) { case 1: if( heurdata->useavgnbray ) { SCIP_CALL( generateAverageNBRay(scip, raydirection, fracspace, subspacevars, nsubspacevars) ); } break; case 2: if( heurdata->useobjray ) { SCIP_CALL( generateObjectiveRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 3: if( heurdata->usediffray ) { SCIP_CALL( generateDifferenceRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 4: if( heurdata->useavgwgtray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, TRUE) ); } break; case 0: if( heurdata->useavgray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, FALSE) ); } break; default: SCIPerrorMessage("invalid ray rule identifier\n"); SCIPABORT(); } /* there must be a feasible direction for the shooting ray */ if( isZero(scip, raydirection, nsubspacevars) ) continue; /* transform coordinates such that raydirection >= 0 */ flipCoords(rayorigin, raydirection, sign, nsubspacevars); for( i = f_max - 1; i >= 0; --i) lambda[i] = SCIPinfinity(scip); /* calculate negquotient, initialize perm, facets[0], p, and q */ p = 0.5 * nsubspacevars; q = 0.0; for( i = nsubspacevars - 1; i >= 0; --i ) { /* calculate negquotient, the ratio of rayorigin and raydirection, paying special attention to the case raydirection[i] == 0 */ if( SCIPisFeasZero(scip, raydirection[i]) ) { if( rayorigin[i] < 0 ) negquotient[i] = SCIPinfinity(scip); else negquotient[i] = -SCIPinfinity(scip); } else negquotient[i] = - (rayorigin[i] / raydirection[i]); perm[i] = i; /* initialization of facets[0] to the all-one facet with p and q its characteristic values */ facets[0][i] = TRUE; p -= rayorigin[i]; q += raydirection[i]; } assert(SCIPisPositive(scip, q)); /* resort the coordinates in nonincreasing order of negquotient */ SCIPsortDownRealRealRealBoolPtr( negquotient, raydirection, rayorigin, sign, (void**) subspacevars, nsubspacevars); #ifndef NDEBUG for( i = 0; i < nsubspacevars; i++ ) assert( raydirection[i] >= 0 ); for( i = 1; i < nsubspacevars; i++ ) assert( negquotient[i - 1] >= negquotient[i] ); #endif /* finished initialization */ /* find the first facet of the octahedron hit by a ray shot from rayorigin into direction raydirection */ for( i = 0; i < nsubspacevars && negquotient[i] * q > p; ++i ) { facets[0][i] = FALSE; p += 2 * rayorigin[i]; q -= 2 * raydirection[i]; assert(SCIPisPositive(scip, p)); assert(SCIPisPositive(scip, q)); } /* avoid dividing by values close to 0.0 */ if( !SCIPisFeasPositive(scip, q) ) continue; /* assert necessary for flexelint */ assert(q > 0); lambda[0] = p / q; nfacets = 1; /* find the first facets hit by the ray */ for( i = 0; i < nfacets && i < f_first; ++i) generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); /* construct the first ffirst possible solutions */ for( i = 0; i < nfacets && i < f_first; ++i ) { SCIP_CALL( SCIPcreateSol(scip, &first_sols[i], heur) ); SCIP_CALL( getSolFromFacet(scip, facets[i], first_sols[i], sign, subspacevars, nsubspacevars) ); assert( first_sols[i] != NULL ); } /* try, whether there is a row violated by all of the first ffirst solutions */ cons_viol = FALSE; SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); for( i = nrows - 1; i >= 0; --i ) { if( !SCIProwIsLocal(rows[i]) ) { SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real rowval; SCIP_Real* coeffs; int nnonzerovars; int k; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]); rhs = SCIProwGetRhs(rows[i]); coeffs = SCIProwGetVals(rows[i]); nnonzerovars = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[0], SCIPcolGetVar(cols[j])); /* if the row's lhs is violated by the first sol, test, whether it is violated by the next ones, too */ if( lhs > rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( lhs <= rowval ) { cons_viol = FALSE; break; } } } /* dito for the right hand side */ else if( rhs < rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( rhs >= rowval ) { cons_viol = FALSE; break; } } } /* break as soon as one row is violated by all of the ffirst solutions */ if( cons_viol ) break; } } if( !cons_viol ) { /* if there was no row violated by all solutions, try whether one or more of them are feasible */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { assert(first_sols[i] != NULL); SCIP_CALL( SCIPtrySol(scip, first_sols[i], FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } /* search for further facets and construct and try solutions out of facets fixed as closest ones */ for( i = f_first; i < f_max; ++i) { if( i >= nfacets ) break; generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); SCIP_CALL( getSolFromFacet(scip, facets[i], sol, sign, subspacevars, nsubspacevars) ); SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } } /* finished OCTANE */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { SCIP_CALL( SCIPfreeSol(scip, &first_sols[i]) ); } } heurdata->lastrule = r; if( *result == SCIP_FOUNDSOL ) ++(heurdata->nsuccess); /* free temporary memory */ SCIPfreeBufferArray(scip, &first_sols); for( i = f_max; i >= 0; --i ) SCIPfreeBufferArray(scip, &facets[i]); SCIPfreeBufferArray(scip, &facets); SCIPfreeBufferArray(scip, &lambda); SCIPfreeBufferArray(scip, &perm); SCIPfreeBufferArray(scip, &sign); SCIPfreeBufferArray(scip, &negquotient); SCIPfreeBufferArray(scip, &raydirection); SCIPfreeBufferArray(scip, &rayorigin); SCIPfreeBufferArray(scip, &subspacevars); SCIPfreeBufferArray(scip, &fracspace); return SCIP_OKAY; }
/** fills the whole Decomp struct after the blk file has been read */ static SCIP_RETCODE fillDecompStruct( SCIP* scip, /**< SCIP data structure */ BLKINPUT* blkinput, /**< blk reading data */ DEC_DECOMP* decomp, /**< DEC_DECOMP structure to fill */ SCIP_READERDATA* readerdata /**< reader data*/ ) { SCIP_HASHMAP* constoblock; SCIP_CONS** allcons; SCIP_VAR** consvars; int i; int j; int nvars; int blocknr; int nconss; int nblocks; SCIP_Bool valid; assert(scip != NULL); assert(blkinput != NULL); assert(readerdata != NULL); allcons = SCIPgetConss(scip); nvars = SCIPgetNVars(scip); nconss = SCIPgetNConss(scip); nblocks = blkinput->nblocks; DECdecompSetPresolved(decomp, blkinput->presolved); DECdecompSetNBlocks(decomp, nblocks); DECdecompSetDetector(decomp, NULL); DECdecompSetType(decomp, DEC_DECTYPE_ARROWHEAD, &valid); assert(valid); /* hashmaps */ SCIP_CALL( SCIPhashmapCreate(&constoblock, SCIPblkmem(scip), nconss) ); SCIP_CALL( SCIPallocMemoryArray(scip, &consvars, nvars) ); /* assign constraints to blocks or declare them linking */ for( i = 0; i < nconss; i ++ ) { SCIP_CONS* cons; cons = allcons[i]; if( SCIPhashmapGetImage(readerdata->constoblock, cons) == (void*) (size_t) LINKINGVALUE ) { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (nblocks+1)) ); SCIPdebugMessage("cons %s is linking\n", SCIPconsGetName(cons)); } /* check whether all variables in the constraint belong to one block */ else { int nconsvars; nconsvars = SCIPgetNVarsXXX(scip, cons); assert(nconsvars < nvars); SCIP_CALL( SCIPgetVarsXXX(scip, cons, consvars, nvars) ); blocknr = -1; /* find the first unique assignment of a contained variable to a block */ for( j = 0; j < nconsvars; ++j ) { /* if a contained variables is directly transferred to the master, the constraint is a linking constraint */ if( readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])] == NOVALUE ) { blocknr = -1; break; } /* assign the constraint temporarily to the block of the variable, if it is unique */ if( blocknr == -1 && readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])] != LINKINGVALUE ) { blocknr = readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])]; } } if( blocknr != -1 ) { int varidx; int varblock; /* check whether all contained variables are copied into the assigned block; * if not, the constraint is treated as a linking constraint */ for( j = 0; j < nconsvars; ++j ) { varidx = SCIPvarGetProbindex(consvars[j]); varblock = readerdata->varstoblock[varidx]; assert(varblock != NOVALUE); if( varblock != LINKINGVALUE && varblock != blocknr ) { blocknr = -1; break; } else if( varblock == LINKINGVALUE ) { int k; for( k = 0; k < readerdata->nlinkingvarsblocks[varidx]; ++k ) { if( readerdata->linkingvarsblocks[varidx][k] == blocknr ) break; } /* we did not break, so the variable is not assigned to the block */ if( k == readerdata->nlinkingvarsblocks[varidx] ) { blocknr = -1; break; } } } } if( blocknr == -1 ) { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (nblocks+1)) ); SCIPdebugMessage("constraint <%s> is a linking constraint\n", SCIPconsGetName(cons)); } else { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (blocknr+1)) ); SCIPdebugMessage("constraint <%s> is assigned to block %d\n", SCIPconsGetName(cons), blocknr); } } } SCIP_CALL( DECfilloutDecdecompFromConstoblock(scip, decomp, constoblock, nblocks, SCIPgetVars(scip), SCIPgetNVars(scip), SCIPgetConss(scip), SCIPgetNConss(scip), FALSE) ); SCIPfreeMemoryArray(scip, &consvars); return SCIP_OKAY; }
/** ensure that maxindex + 1 rows can be represented in data arrays; memory gets reallocated with 10% extra space * to save some time for future allocations */ static SCIP_RETCODE heurdataEnsureArraySize( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int maxindex /**< row index at hand (size must be at least this large) */ ) { int newsize; int r; /* maxindex fits in current array -> nothing to do */ if( maxindex < heurdata->memsize ) return SCIP_OKAY; /* new memory size is the max index + 1 plus 10% additional space */ newsize = (int)SCIPfeasCeil(scip, (maxindex + 1) * 1.1); assert(newsize > heurdata->memsize); assert(heurdata->memsize >= 0); /* alloc memory arrays for row information */ if( heurdata->memsize == 0 ) { SCIP_VAR** vars; int v; int nvars; SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowmeans, newsize) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowvariances, newsize) ); assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING); vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); assert(nvars > 0); /* allocate variable update event processing array storage */ SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varfilterposs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varposs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->updatedvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentubs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentlbs, nvars) ); heurdata->varpossmemsize = nvars; heurdata->nupdatedvars = 0; /* init variable event processing data */ for( v = 0; v < nvars; ++v ) { assert(SCIPvarIsActive(vars[v])); assert(SCIPvarGetProbindex(vars[v]) == v); /* set up variable events to catch bound changes */ SCIP_CALL( SCIPcatchVarEvent(scip, vars[v], EVENT_DISTRIBUTION, heurdata->eventhdlr, NULL, &(heurdata->varfilterposs[v])) ); assert(heurdata->varfilterposs[v] >= 0); heurdata->varposs[v] = -1; heurdata->updatedvars[v] = NULL; heurdata->currentlbs[v] = SCIP_INVALID; heurdata->currentubs[v] = SCIP_INVALID; } } else { SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowmeans, newsize) ); SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowvariances, newsize) ); } /* loop over extended arrays and invalidate data to trigger initialization of this row when necessary */ for( r = heurdata->memsize; r < newsize; ++r ) { heurdata->rowmeans[r] = SCIP_INVALID; heurdata->rowvariances[r] = SCIP_INVALID; heurdata->rowinfinitiesdown[r] = 0; heurdata->rowinfinitiesup[r] = 0; } /* adjust memsize */ heurdata->memsize = newsize; return SCIP_OKAY; }
/** print row in PPM format to file stream */ static void printRow( SCIP* scip, /**< SCIP data structure */ FILE* file, /**< output file (or NULL for standard output) */ SCIP_READERDATA* readerdata, /**< information for reader */ SCIP_VAR** vars, /**< array of constraint variables */ SCIP_Real* vals, /**< array of constraint values */ int nvars, /**< number of constraint variables */ int ntotalvars, /**< number of variables */ SCIP_Real maxcoef /**< maximal coefficient */ ) { int v; int i; int j; int red; int green; int blue; char linebuffer[PPM_MAX_LINELEN]; int linecnt; int varindex; int actvarindex; int maxvarindex; int indexvar = 0; char buffer[PPM_MAX_LINELEN]; const unsigned char max = (unsigned char)255; char white[4]; assert( scip != NULL ); assert (nvars > 0); assert (readerdata != NULL); i = 0; varindex = -1; maxvarindex = 0; (void) SCIPsnprintf(white, 4, "%c%c%c", max, max, max); clearLine(linebuffer, &linecnt); /* calculate maximum index of the variables in this constraint */ for( v = 0; v < nvars; ++v ) { if(maxvarindex < SCIPvarGetProbindex(vars[v])) maxvarindex = SCIPvarGetProbindex(vars[v]); } assert(maxvarindex < ntotalvars); /* print coefficients */ for(v = 0; v < nvars; ++v) { actvarindex = maxvarindex; for(j = 0; j < nvars; ++j) { if( varindex < SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) <= actvarindex ) { actvarindex = SCIPvarGetProbindex(vars[j]); indexvar = j; } } varindex = actvarindex; /* fill in white points since these variables indices do not exits in this constraint */ for( ; i < varindex; ++i ) { if(readerdata->rgb_ascii) appendLine(scip, file, readerdata, linebuffer, &linecnt, white); else appendLine(scip, file, readerdata, linebuffer, &linecnt, " 255 255 255 "); } calcColorValue(scip, readerdata, REALABS(vals[indexvar]), &red, &green, &blue, maxcoef); if(readerdata->rgb_ascii) { if(red == 35 || red == 0) red++; if(green==35 || green == 0) green++; if(blue==35 || blue == 0) blue++; (void) SCIPsnprintf(buffer, PPM_MAX_LINELEN, "%c%c%c", (unsigned char)red, (unsigned char)green, (unsigned char)blue); } else (void) SCIPsnprintf(buffer, PPM_MAX_LINELEN, " %d %d %d ", red, green, blue); appendLine(scip, file, readerdata, linebuffer, &linecnt, buffer); i++; } /* fill in white points since these variables indices do not exits in this constraint */ for( ; i < ntotalvars; ++i ) { if(readerdata->rgb_ascii) appendLine(scip, file, readerdata, linebuffer, &linecnt, white); else appendLine(scip, file, readerdata, linebuffer, &linecnt, " 255 255 255 "); } endLine(scip, file, readerdata, linebuffer, &linecnt); }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecShifting) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_ROW** lprows; SCIP_Real* activities; SCIP_ROW** violrows; SCIP_Real* nincreases; SCIP_Real* ndecreases; int* violrowpos; int* nfracsinrow; SCIP_Real increaseweight; SCIP_Real obj; SCIP_Real bestshiftval; SCIP_Real minobj; int nlpcands; int nlprows; int nvars; int nfrac; int nviolrows; int nprevviolrows; int minnviolrows; int nnonimprovingshifts; int c; int r; SCIP_Longint nlps; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nnodes; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* 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); /* don't call heuristic, if we have already processed the current LP solution */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* don't call heuristic, if it was not successful enough in the past */ ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur); nnodes = SCIPgetNNodes(scip); if( nnodes % ((ncalls/100)/(nsolsfound+1)+1) != 0 ) return SCIP_OKAY; /* get fractional variables, that should be integral */ /* todo check if heuristic should include implicit integer variables for its calculations */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) ); nfrac = nlpcands; /* only call heuristic, if LP solution is fractional */ if( nfrac == 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* get LP rows */ SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) ); SCIPdebugMessage("executing shifting heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac); /* get memory for activities, violated rows, and row violation positions */ nvars = SCIPgetNVars(scip); SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &nfracsinrow, nlprows) ); SCIP_CALL( SCIPallocBufferArray(scip, &nincreases, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &ndecreases, nvars) ); BMSclearMemoryArray(nfracsinrow, nlprows); BMSclearMemoryArray(nincreases, nvars); BMSclearMemoryArray(ndecreases, nvars); /* get the activities for all globally valid rows; * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated */ nviolrows = 0; for( r = 0; r < nlprows; ++r ) { SCIP_ROW* row; row = lprows[r]; assert(SCIProwGetLPPos(row) == r); if( !SCIProwIsLocal(row) ) { activities[r] = SCIPgetRowActivity(scip, row); if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) ) { violrows[nviolrows] = row; violrowpos[r] = nviolrows; nviolrows++; } else violrowpos[r] = -1; } } /* calc the current number of fractional variables in rows */ for( c = 0; c < nlpcands; ++c ) addFracCounter(nfracsinrow, nlprows, lpcands[c], +1); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* calculate the minimal objective value possible after rounding fractional variables */ minobj = SCIPgetSolTransObj(scip, sol); assert(minobj < SCIPgetCutoffbound(scip)); for( c = 0; c < nlpcands; ++c ) { obj = SCIPvarGetObj(lpcands[c]); bestshiftval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]); minobj += obj * (bestshiftval - lpcandssol[c]); } /* try to shift remaining variables in order to become/stay feasible */ nnonimprovingshifts = 0; minnviolrows = INT_MAX; increaseweight = 1.0; while( (nfrac > 0 || nviolrows > 0) && nnonimprovingshifts < MAXSHIFTINGS ) { SCIP_VAR* shiftvar; SCIP_Real oldsolval; SCIP_Real newsolval; SCIP_Bool oldsolvalisfrac; int probindex; SCIPdebugMessage("shifting heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g), cutoff=%g\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj), SCIPretransformObj(scip, SCIPgetCutoffbound(scip))); nprevviolrows = nviolrows; /* choose next variable to process: * - if a violated row exists, shift a variable decreasing the violation, that has least impact on other rows * - otherwise, shift a variable, that has strongest devastating impact on rows in opposite direction */ shiftvar = NULL; oldsolval = 0.0; newsolval = 0.0; if( nviolrows > 0 && (nfrac == 0 || nnonimprovingshifts < MAXSHIFTINGS-1) ) { SCIP_ROW* row; int rowidx; int rowpos; int direction; rowidx = -1; rowpos = -1; row = NULL; if( nfrac > 0 ) { for( rowidx = nviolrows-1; rowidx >= 0; --rowidx ) { row = violrows[rowidx]; rowpos = SCIProwGetLPPos(row); assert(violrowpos[rowpos] == rowidx); if( nfracsinrow[rowpos] > 0 ) break; } } if( rowidx == -1 ) { rowidx = SCIPgetRandomInt(0, nviolrows-1, &heurdata->randseed); row = violrows[rowidx]; rowpos = SCIProwGetLPPos(row); assert(0 <= rowpos && rowpos < nlprows); assert(violrowpos[rowpos] == rowidx); assert(nfracsinrow[rowpos] == 0); } assert(violrowpos[rowpos] == rowidx); SCIPdebugMessage("shifting heuristic: try to fix violated row <%s>: %g <= %g <= %g\n", SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row)); SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); /* get direction in which activity must be shifted */ assert(SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) || SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row))); direction = SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) ? +1 : -1; /* search a variable that can shift the activity in the necessary direction */ SCIP_CALL( selectShifting(scip, sol, row, activities[rowpos], direction, nincreases, ndecreases, increaseweight, &shiftvar, &oldsolval, &newsolval) ); } if( shiftvar == NULL && nfrac > 0 ) { SCIPdebugMessage("shifting heuristic: search rounding variable and try to stay feasible\n"); SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &shiftvar, &oldsolval, &newsolval) ); } /* check, whether shifting was possible */ if( shiftvar == NULL || SCIPisEQ(scip, oldsolval, newsolval) ) { SCIPdebugMessage("shifting heuristic: -> didn't find a shifting variable\n"); break; } SCIPdebugMessage("shifting heuristic: -> shift var <%s>[%g,%g], type=%d, oldval=%g, newval=%g, obj=%g\n", SCIPvarGetName(shiftvar), SCIPvarGetLbGlobal(shiftvar), SCIPvarGetUbGlobal(shiftvar), SCIPvarGetType(shiftvar), oldsolval, newsolval, SCIPvarGetObj(shiftvar)); /* update row activities of globally valid rows */ SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows, shiftvar, oldsolval, newsolval) ); if( nviolrows >= nprevviolrows ) nnonimprovingshifts++; else if( nviolrows < minnviolrows ) { minnviolrows = nviolrows; nnonimprovingshifts = 0; } /* store new solution value and decrease fractionality counter */ SCIP_CALL( SCIPsetSolVal(scip, sol, shiftvar, newsolval) ); /* update fractionality counter and minimal objective value possible after shifting remaining variables */ oldsolvalisfrac = !SCIPisFeasIntegral(scip, oldsolval) && (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER); obj = SCIPvarGetObj(shiftvar); if( (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER) && oldsolvalisfrac ) { assert(SCIPisFeasIntegral(scip, newsolval)); nfrac--; nnonimprovingshifts = 0; minnviolrows = INT_MAX; addFracCounter(nfracsinrow, nlprows, shiftvar, -1); /* the rounding was already calculated into the minobj -> update only if rounding in "wrong" direction */ if( obj > 0.0 && newsolval > oldsolval ) minobj += obj; else if( obj < 0.0 && newsolval < oldsolval ) minobj -= obj; } else { /* update minimal possible objective value */ minobj += obj * (newsolval - oldsolval); } /* update increase/decrease arrays */ if( !oldsolvalisfrac ) { probindex = SCIPvarGetProbindex(shiftvar); assert(0 <= probindex && probindex < nvars); increaseweight *= WEIGHTFACTOR; if( newsolval < oldsolval ) ndecreases[probindex] += increaseweight; else nincreases[probindex] += increaseweight; if( increaseweight >= 1e+09 ) { int i; for( i = 0; i < nvars; ++i ) { nincreases[i] /= increaseweight; ndecreases[i] /= increaseweight; } increaseweight = 1.0; } } SCIPdebugMessage("shifting heuristic: -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n", nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj)); } /* check, if the new solution is feasible */ if( nfrac == 0 && nviolrows == 0 ) { SCIP_Bool stored; /* check solution for feasibility, and add it to solution store if possible * neither integrality nor feasibility of LP rows has to be checked, because this is already * done in the shifting heuristic itself; however, we better check feasibility of LP rows, * because of numerical problems with activity updating */ SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) ); if( stored ) { SCIPdebugMessage("found feasible shifted solution:\n"); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ) ); *result = SCIP_FOUNDSOL; } } /* free memory buffers */ SCIPfreeBufferArray(scip, &ndecreases); SCIPfreeBufferArray(scip, &nincreases); SCIPfreeBufferArray(scip, &nfracsinrow); SCIPfreeBufferArray(scip, &violrowpos); SCIPfreeBufferArray(scip, &violrows); SCIPfreeBufferArray(scip, &activities); return SCIP_OKAY; }
/** searches and adds implied bound cuts that are violated by the given solution value array */ static SCIP_RETCODE separateCuts( SCIP* scip, /**< SCIP data structure */ SCIP_SEPA* sepa, /**< separator */ SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */ SCIP_Real* solvals, /**< array with solution values of all problem variables */ SCIP_VAR** fracvars, /**< array of fractional variables */ SCIP_Real* fracvals, /**< solution values of fractional variables */ int nfracs, /**< number of fractional variables */ SCIP_Bool* cutoff, /**< whether a cutoff has been detected */ int* ncuts /**< pointer to store the number of generated cuts */ ) { SCIP_CLIQUE** cliques; SCIP_SEPADATA* sepadata; int ncliques; int i; assert(solvals != NULL); assert(fracvars != NULL || nfracs == 0); assert(fracvals != NULL || nfracs == 0); assert(cutoff != NULL); assert(ncuts != NULL); *cutoff = FALSE; *ncuts = 0; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); SCIPdebugMessage("searching for implied bound cuts\n"); /* search binary variables for violated implications */ for( i = 0; i < nfracs; i++ ) { SCIP_BOUNDTYPE* impltypes; SCIP_Real* implbounds; SCIP_VAR** implvars; int nimpl; int j; assert(fracvars != NULL); assert(fracvals != NULL); /* only process binary variables */ if( SCIPvarGetType(fracvars[i]) != SCIP_VARTYPE_BINARY ) continue; /* get implications of x == 1 */ nimpl = SCIPvarGetNImpls(fracvars[i], TRUE); implvars = SCIPvarGetImplVars(fracvars[i], TRUE); impltypes = SCIPvarGetImplTypes(fracvars[i], TRUE); implbounds = SCIPvarGetImplBounds(fracvars[i], TRUE); /*debugMessage("%d implications for <%s>[%g] == 1\n", nimpl, SCIPvarGetName(fracvars[i]), fracvals[i]);*/ /* try to add cuts for implications of x == 1 * x == 1 -> y <= p: y <= ub + x * (p - ub) <==> y + (ub - p) * x <= ub * x == 1 -> y >= p: y >= lb + x * (p - lb) <==> -y + (p - lb) * x <= -lb * with lb (ub) global lower (upper) bound of y */ for( j = 0; j < nimpl; j++ ) { SCIP_Real solval; assert(implvars != NULL); assert(impltypes != NULL); assert(implbounds != NULL); /* consider only implications with active implvar */ if( SCIPvarGetProbindex(implvars[j]) < 0 ) continue; solval = solvals[SCIPvarGetProbindex(implvars[j])]; if( impltypes[j] == SCIP_BOUNDTYPE_UPPER ) { SCIP_Real ub; /* implication x == 1 -> y <= p */ ub = SCIPvarGetUbGlobal(implvars[j]); /* consider only nonredundant and numerical harmless implications */ if( SCIPisLE(scip, implbounds[j], ub) && (ub - implbounds[j]) * SCIPfeastol(scip) <= RELCUTCOEFMAXRANGE ) { /* add cut if violated */ SCIP_CALL( addCut(scip, sepa, sol, 1.0, implvars[j], solval, (ub - implbounds[j]), fracvars[i], fracvals[i], ub, cutoff, ncuts) ); if ( *cutoff ) return SCIP_OKAY; } } else { SCIP_Real lb; /* implication x == 1 -> y >= p */ lb = SCIPvarGetLbGlobal(implvars[j]); assert(impltypes[j] == SCIP_BOUNDTYPE_LOWER); /* consider only nonredundant and numerical harmless implications */ if( SCIPisGE(scip, implbounds[j], lb) && (implbounds[j] - lb) * SCIPfeastol(scip) <= RELCUTCOEFMAXRANGE ) { /* add cut if violated */ SCIP_CALL( addCut(scip, sepa, sol, -1.0, implvars[j], solval, (implbounds[j] - lb), fracvars[i], fracvals[i], -lb, cutoff, ncuts) ); if ( *cutoff ) return SCIP_OKAY; } } } /* get implications of x == 0 */ nimpl = SCIPvarGetNImpls(fracvars[i], FALSE); implvars = SCIPvarGetImplVars(fracvars[i], FALSE); impltypes = SCIPvarGetImplTypes(fracvars[i], FALSE); implbounds = SCIPvarGetImplBounds(fracvars[i], FALSE); /*debugMessage("%d implications for <%s>[%g] == 0\n", nimpl, SCIPvarGetName(fracvars[i]), fracvals[i]);*/ /* try to add cuts for implications of x == 0 * x == 0 -> y <= p: y <= p + x * (ub - p) <==> y + (p - ub) * x <= p * x == 0 -> y >= p: y >= p + x * (lb - p) <==> -y + (lb - p) * x <= -p * with lb (ub) global lower (upper) bound of y */ for( j = 0; j < nimpl; j++ ) { SCIP_Real solval; /* consider only implications with active implvar */ if( SCIPvarGetProbindex(implvars[j]) < 0 ) continue; solval = solvals[SCIPvarGetProbindex(implvars[j])]; if( impltypes[j] == SCIP_BOUNDTYPE_UPPER ) { SCIP_Real ub; /* implication x == 0 -> y <= p */ ub = SCIPvarGetUbGlobal(implvars[j]); /* consider only nonredundant and numerical harmless implications */ if( SCIPisLE(scip, implbounds[j], ub) && (ub - implbounds[j]) * SCIPfeastol(scip) < RELCUTCOEFMAXRANGE ) { /* add cut if violated */ SCIP_CALL( addCut(scip, sepa, sol, 1.0, implvars[j], solval, (implbounds[j] - ub), fracvars[i], fracvals[i], implbounds[j], cutoff, ncuts) ); if ( *cutoff ) return SCIP_OKAY; } } else { SCIP_Real lb; /* implication x == 0 -> y >= p */ lb = SCIPvarGetLbGlobal(implvars[j]); assert(impltypes[j] == SCIP_BOUNDTYPE_LOWER); /* consider only nonredundant and numerical harmless implications */ if( SCIPisGE(scip, implbounds[j], lb) && (implbounds[j] - lb) * SCIPfeastol(scip) < RELCUTCOEFMAXRANGE ) { /* add cut if violated */ SCIP_CALL( addCut(scip, sepa, sol, -1.0, implvars[j], solval, (lb - implbounds[j]), fracvars[i], fracvals[i], -implbounds[j], cutoff, ncuts) ); if ( *cutoff ) return SCIP_OKAY; } } } } /* stop separation here if cliques should not be separated */ if( ! sepadata->usetwosizecliques ) return SCIP_OKAY; /* prepare clean clique data */ SCIP_CALL( SCIPcleanupCliques(scip, cutoff) ); if( *cutoff ) return SCIP_OKAY; cliques = SCIPgetCliques(scip); ncliques = SCIPgetNCliques(scip); /* loop over cliques of size 2 which are essentially implications and add cuts if they are violated */ for( i = 0; i < ncliques; ++i ) { SCIP_CLIQUE* clique; SCIP_VAR** clqvars; SCIP_Bool* clqvals; SCIP_Real rhs; clique = cliques[i]; /* only consider inequality cliques of size 2 */ if( SCIPcliqueGetNVars(clique) != 2 || SCIPcliqueIsEquation(clique) ) continue; /* get variables and values of the clique */ clqvars = SCIPcliqueGetVars(clique); clqvals = SCIPcliqueGetValues(clique); /* clique variables should never be equal after clean up */ assert(clqvars[0] != clqvars[1]); /* calculate right hand side of clique inequality, which is initially 1 and decreased by 1 for every occurence of * a negated variable in the clique */ rhs = 1.0; if( ! clqvals[0] ) rhs -= 1.0; if( ! clqvals[1] ) rhs -= 1.0; /* Basic clique inequality is * * cx * x + (1-cx) (1-x) + cy * y + (1-cy) * (1-y) <= 1, * * where x and y are the two binary variables in the clique and cx and cy are their clique values, where a * clique value of 0 means that the negation of the variable should be part of the inequality. * Hence, exactly one of the two possible terms for x and y has a nonzero coefficient */ SCIP_CALL( addCut(scip, sepa, sol, clqvals[0] ? 1.0 : -1.0, clqvars[0], SCIPgetSolVal(scip, sol, clqvars[0]), clqvals[1] ? 1.0 : -1.0, clqvars[1], SCIPgetSolVal(scip, sol, clqvars[1]), rhs, cutoff, ncuts) ); /* terminate if cutoff was found */ if( *cutoff ) return SCIP_OKAY; } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecObjpscostdiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_LPSOLSTAT lpsolstat; SCIP_VAR* var; SCIP_VAR** lpcands; SCIP_Real* lpcandssol; SCIP_Real* lpcandsfrac; SCIP_Real primsol; SCIP_Real frac; SCIP_Real pscostquot; SCIP_Real bestpscostquot; SCIP_Real oldobj; SCIP_Real newobj; SCIP_Real objscale; SCIP_Bool bestcandmayrounddown; SCIP_Bool bestcandmayroundup; SCIP_Bool bestcandroundup; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; SCIP_Bool roundup; SCIP_Bool lperror; SCIP_Longint ncalls; SCIP_Longint nsolsfound; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int* roundings; int nvars; int varidx; int nlpcands; int startnlpcands; int depth; int maxdepth; int maxdivedepth; int divedepth; int bestcand; int c; assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* 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; /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* don't dive two times at the same node */ if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only apply heuristic, if only a few solutions have been found */ if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols ) return SCIP_OKAY; /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */ depth = SCIPgetDepth(scip); maxdepth = SCIPgetMaxDepth(scip); maxdepth = MAX(maxdepth, 30); if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth ) return SCIP_OKAY; /* calculate the maximal number of LP iterations until heuristic is aborted */ nlpiterations = SCIPgetNNodeLPIterations(scip); ncalls = SCIPheurGetNCalls(heur); nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess; maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations); maxnlpiterations += heurdata->maxlpiterofs; /* don't try to dive, if we took too many LP iterations during diving */ if( heurdata->nlpiterations >= maxnlpiterations ) return SCIP_OKAY; /* allow at least a certain number of LP iterations in this dive */ maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER); /* get fractional variables that should be integral */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); /* don't try to dive, if there are no fractional variables */ if( nlpcands == 0 ) return SCIP_OKAY; /* calculate the maximal diving depth */ nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip); if( SCIPgetNSolsFound(scip) == 0 ) maxdivedepth = (int)(heurdata->depthfacnosol * nvars); else maxdivedepth = (int)(heurdata->depthfac * nvars); maxdivedepth = MIN(maxdivedepth, 10*maxdepth); *result = SCIP_DIDNOTFIND; /* get temporary memory for remembering the current soft roundings */ SCIP_CALL( SCIPallocBufferArray(scip, &roundings, nvars) ); BMSclearMemoryArray(roundings, nvars); /* start diving */ SCIP_CALL( SCIPstartDive(scip) ); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing objpscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth); /* dive as long we are in the given diving depth and iteration limits and fractional variables exist, but * - if the last objective change was in a direction, that corresponds to a feasible rounding, we continue in any case * - if possible, we dive at least with the depth 10 * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving */ lperror = FALSE; lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; divedepth = 0; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; startnlpcands = nlpcands; while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && nlpcands <= startnlpcands - divedepth/10 && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) ) { SCIP_RETCODE retcode; divedepth++; /* choose variable for objective change: * - prefer variables that may not be rounded without destroying LP feasibility: * - of these variables, change objective value of variable with largest rel. difference of pseudo cost values * - if all remaining fractional variables may be rounded without destroying LP feasibility: * - change objective value of variable with largest rel. difference of pseudo cost values */ bestcand = -1; bestpscostquot = -1.0; bestcandmayrounddown = TRUE; bestcandmayroundup = TRUE; bestcandroundup = FALSE; for( c = 0; c < nlpcands; ++c ) { var = lpcands[c]; mayrounddown = SCIPvarMayRoundDown(var); mayroundup = SCIPvarMayRoundUp(var); primsol = lpcandssol[c]; frac = lpcandsfrac[c]; if( mayrounddown || mayroundup ) { /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */ if( bestcandmayrounddown || bestcandmayroundup ) { /* choose rounding direction: * - if variable may be rounded in both directions, round corresponding to the pseudo cost values * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ roundup = FALSE; if( mayrounddown && mayroundup ) calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup); else if( mayrounddown ) calcPscostQuot(scip, var, primsol, frac, +1, &pscostquot, &roundup); else calcPscostQuot(scip, var, primsol, frac, -1, &pscostquot, &roundup); /* prefer variables, that have already been soft rounded but failed to get integral */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] != 0 ) pscostquot *= 1000.0; /* check, if candidate is new best candidate */ if( pscostquot > bestpscostquot ) { bestcand = c; bestpscostquot = pscostquot; bestcandmayrounddown = mayrounddown; bestcandmayroundup = mayroundup; bestcandroundup = roundup; } } } else { /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */ calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup); /* prefer variables, that have already been soft rounded but failed to get integral */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] != 0 ) pscostquot *= 1000.0; /* check, if candidate is new best candidate: prefer unroundable candidates in any case */ if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot ) { bestcand = c; bestpscostquot = pscostquot; bestcandmayrounddown = FALSE; bestcandmayroundup = FALSE; bestcandroundup = roundup; } } } assert(bestcand != -1); /* if all candidates are roundable, try to round the solution */ if( bestcandmayrounddown || bestcandmayroundup ) { SCIP_Bool success; /* create solution from diving LP and try to round it */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) ); if( success ) { SCIPdebugMessage("objpscostdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } } var = lpcands[bestcand]; /* check, if the best candidate was already subject to soft rounding */ varidx = SCIPvarGetProbindex(var); assert(0 <= varidx && varidx < nvars); if( roundings[varidx] == +1 ) { /* variable was already soft rounded upwards: hard round it downwards */ SCIP_CALL( SCIPchgVarUbDive(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) ); SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded upwards -> bounds=[%g,%g]\n", divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var)); } else if( roundings[varidx] == -1 ) { /* variable was already soft rounded downwards: hard round it upwards */ SCIP_CALL( SCIPchgVarLbDive(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) ); SCIPdebugMessage(" dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded downwards -> bounds=[%g,%g]\n", divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var)); } else { assert(roundings[varidx] == 0); /* apply soft rounding of best candidate via a change in the objective value */ objscale = divedepth * 1000.0; oldobj = SCIPgetVarObjDive(scip, var); if( bestcandroundup ) { /* soft round variable up: make objective value (more) negative */ if( oldobj < 0.0 ) newobj = objscale * oldobj; else newobj = -objscale * oldobj; newobj = MIN(newobj, -objscale); /* remember, that this variable was soft rounded upwards */ roundings[varidx] = +1; } else { /* soft round variable down: make objective value (more) positive */ if( oldobj > 0.0 ) newobj = objscale * oldobj; else newobj = -objscale * oldobj; newobj = MAX(newobj, objscale); /* remember, that this variable was soft rounded downwards */ roundings[varidx] = -1; } SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) ); SCIPdebugMessage(" dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, bounds=[%g,%g], obj=%g, newobj=%g\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup, lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var), oldobj, newobj); } /* resolve the diving LP */ nlpiterations = SCIPgetNLPIterations(scip); retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL); lpsolstat = SCIPgetLPSolstat(scip); /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic. * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY ) { SCIP_CALL( retcode ); } #endif SCIPwarningMessage(scip, "Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode); SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n"); } if( lperror ) break; /* update iteration count */ heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations; /* get LP solution status and fractional variables, that should be integral */ if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { /* get new fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) ); } SCIPdebugMessage(" -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands); } /* check if a solution has been found */ if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) { SCIP_Bool success; /* create solution from diving LP */ SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) ); SCIPdebugMessage("objpscostdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol)); /* try to add solution to SCIP */ SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) ); /* check, if solution was feasible and good enough */ if( success ) { SCIPdebugMessage(" -> solution was feasible and good enough\n"); *result = SCIP_FOUNDSOL; } } /* end diving */ SCIP_CALL( SCIPendDive(scip) ); if( *result == SCIP_FOUNDSOL ) heurdata->nsuccess++; /* free temporary memory for remembering the current soft roundings */ SCIPfreeBufferArray(scip, &roundings); SCIPdebugMessage("objpscostdiving heuristic finished\n"); return SCIP_OKAY; }
/** calculates the initial mean and variance of the row activity normal distribution. * * The mean value \f$ \mu \f$ is given by \f$ \mu = \sum_i=1^n c_i * (lb_i +ub_i) / 2 \f$ where * \f$n \f$ is the number of variables, and \f$ c_i, lb_i, ub_i \f$ are the variable coefficient and * bounds, respectively. With the same notation, the variance \f$ \sigma^2 \f$ is given by * \f$ \sigma^2 = \sum_i=1^n c_i^2 * \sigma^2_i \f$, with the variance being * \f$ \sigma^2_i = ((ub_i - lb_i + 1)^2 - 1) / 12 \f$ for integer variables and * \f$ \sigma^2_i = (ub_i - lb_i)^2 / 12 \f$ for continuous variables. */ static void rowCalculateGauss( SCIP* scip, /**< SCIP data structure */ SCIP_HEURDATA* heurdata, /**< the heuristic rule data */ SCIP_ROW* row, /**< the row for which the gaussian normal distribution has to be calculated */ SCIP_Real* mu, /**< pointer to store the mean value of the gaussian normal distribution */ SCIP_Real* sigma2, /**< pointer to store the variance value of the gaussian normal distribution */ int* rowinfinitiesdown, /**< pointer to store the number of variables with infinite bounds to DECREASE activity */ int* rowinfinitiesup /**< pointer to store the number of variables with infinite bounds to INCREASE activity */ ) { SCIP_COL** rowcols; SCIP_Real* rowvals; int nrowvals; int c; assert(scip != NULL); assert(row != NULL); assert(mu != NULL); assert(sigma2 != NULL); assert(rowinfinitiesup != NULL); assert(rowinfinitiesdown != NULL); rowcols = SCIProwGetCols(row); rowvals = SCIProwGetVals(row); nrowvals = SCIProwGetNNonz(row); assert(nrowvals == 0 || rowcols != NULL); assert(nrowvals == 0 || rowvals != NULL); *mu = SCIProwGetConstant(row); *sigma2 = 0.0; *rowinfinitiesdown = 0; *rowinfinitiesup = 0; /* loop over nonzero row coefficients and sum up the variable contributions to mu and sigma2 */ for( c = 0; c < nrowvals; ++c ) { SCIP_VAR* colvar; SCIP_Real colval; SCIP_Real colvarlb; SCIP_Real colvarub; SCIP_Real squarecoeff; SCIP_Real varvariance; SCIP_Real varmean; int varindex; assert(rowcols[c] != NULL); colvar = SCIPcolGetVar(rowcols[c]); assert(colvar != NULL); colval = rowvals[c]; colvarlb = SCIPvarGetLbLocal(colvar); colvarub = SCIPvarGetUbLocal(colvar); varmean = 0.0; varvariance = 0.0; varindex = SCIPvarGetProbindex(colvar); assert((heurdata->currentlbs[varindex] == SCIP_INVALID) == (heurdata->currentubs[varindex] == SCIP_INVALID)); /*lint !e777 doesn't like comparing floats for equality */ /* variable bounds need to be watched from now on */ if( heurdata->currentlbs[varindex] == SCIP_INVALID ) /*lint !e777 doesn't like comparing floats for equality */ heurdataUpdateCurrentBounds(scip, heurdata, colvar); assert(!SCIPisInfinity(scip, colvarlb)); assert(!SCIPisInfinity(scip, -colvarub)); assert(SCIPisFeasLE(scip, colvarlb, colvarub)); /* variables with infinite bounds are skipped for the calculation of the variance; they need to * be accounted for by the counters for infinite row activity decrease and increase and they * are used to shift the row activity mean in case they have one nonzero, but finite bound */ if( SCIPisInfinity(scip, -colvarlb) || SCIPisInfinity(scip, colvarub) ) { if( SCIPisInfinity(scip, colvarub) ) { /* an infinite upper bound gives the row an infinite maximum activity or minimum activity, if the coefficient is * positive or negative, resp. */ if( colval < 0.0 ) ++(*rowinfinitiesdown); else ++(*rowinfinitiesup); } /* an infinite lower bound gives the row an infinite maximum activity or minimum activity, if the coefficient is * negative or positive, resp. */ if( SCIPisInfinity(scip, -colvarlb) ) { if( colval > 0.0 ) ++(*rowinfinitiesdown); else ++(*rowinfinitiesup); } } SCIPvarCalcDistributionParameters(scip, colvarlb, colvarub, SCIPvarGetType(colvar), &varmean, &varvariance); /* actual values are updated; the contribution of the variable to mu is the arithmetic mean of its bounds */ *mu += colval * varmean; /* the variance contribution of a variable is c^2 * (u - l)^2 / 12.0 for continuous and c^2 * ((u - l + 1)^2 - 1) / 12.0 for integer */ squarecoeff = SQUARED(colval); *sigma2 += squarecoeff * varvariance; assert(!SCIPisFeasNegative(scip, *sigma2)); } SCIPdebug( SCIPprintRow(scip, row, NULL) ); SCIPdebugMessage(" Row %s has a mean value of %g at a sigma2 of %g \n", SCIProwGetName(row), *mu, *sigma2); }
/** adds priced variables to the LP */ SCIP_RETCODE SCIPpricestoreApplyVars( SCIP_PRICESTORE* pricestore, /**< pricing storage */ BMS_BLKMEM* blkmem, /**< block memory buffers */ SCIP_SET* set, /**< global SCIP settings */ SCIP_STAT* stat, /**< dynamic problem statistics */ SCIP_EVENTQUEUE* eventqueue, /**< event queue */ SCIP_PROB* prob, /**< transformed problem after presolve */ SCIP_TREE* tree, /**< branch and bound tree */ SCIP_LP* lp /**< LP data */ ) { SCIP_VAR* var; SCIP_COL* col; int v; assert(pricestore != NULL); assert(pricestore->naddedbdviolvars <= pricestore->nbdviolvars); assert(set != NULL); assert(prob != NULL); assert(lp != NULL); assert(tree != NULL); assert(SCIPtreeIsFocusNodeLPConstructed(tree)); SCIPdebugMessage("adding %d variables (%d bound violated and %d priced vars) to %d LP columns\n", SCIPpricestoreGetNVars(pricestore), pricestore->nbdviolvars - pricestore->naddedbdviolvars, pricestore->nvars, SCIPlpGetNCols(lp)); /* add the variables with violated bounds to LP */ for( v = pricestore->naddedbdviolvars; v < pricestore->nbdviolvars; ++v ) { var = pricestore->bdviolvars[v]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); assert(SCIPvarGetProbindex(var) >= 0); assert(var->nuses >= 2); /* at least used in pricing storage and in problem */ if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) { /* transform loose variable into column variable */ SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) ); } assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); col = SCIPvarGetCol(var); assert(col != NULL); assert(col->lppos == -1); SCIPdebugMessage("adding bound violated variable <%s> (lb=%g, ub=%g)\n", SCIPvarGetName(var), pricestore->bdviolvarslb[v], pricestore->bdviolvarsub[v]); SCIP_CALL( SCIPlpAddCol(lp, set, col, SCIPtreeGetCurrentDepth(tree)) ); if( !pricestore->initiallp ) pricestore->nvarsapplied++; } pricestore->naddedbdviolvars = pricestore->nbdviolvars; /* add the selected pricing variables to LP */ for( v = 0; v < pricestore->nvars; ++v ) { var = pricestore->vars[v]; assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); assert(SCIPvarGetProbindex(var) >= 0); assert(var->nuses >= 2); /* at least used in pricing storage and in problem */ /* transform variable into column variable, if needed */ if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE ) { SCIP_CALL( SCIPvarColumn(var, blkmem, set, stat, prob, lp) ); } assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); col = SCIPvarGetCol(var); assert(col != NULL); assert(col->lppos == -1); SCIPdebugMessage("adding priced variable <%s> (score=%g)\n", SCIPvarGetName(var), pricestore->scores[v]); SCIP_CALL( SCIPlpAddCol(lp, set, col, SCIPtreeGetCurrentDepth(tree)) ); /* release the variable */ SCIP_CALL( SCIPvarRelease(&pricestore->vars[v], blkmem, set, eventqueue, lp) ); if( !pricestore->initiallp ) pricestore->nvarsapplied++; } /* clear the pricing storage */ pricestore->nvars = 0; 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; }