/** checks the consistency of the origbranch constraints in the problem */ void GCGconsOrigbranchCheckConsistency( SCIP* scip /**< SCIP data structure */ ) { #ifdef CHECKCONSISTENCY SCIP_CONSHDLR* conshdlr; #ifndef NDEBUG SCIP_CONS** conss; int nconss; int i; SCIP_CONSDATA* consdata; #endif assert(scip != NULL); conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); if( conshdlr == NULL ) { SCIPerrorMessage("origbranch constraint handler not found\n"); return; } #ifndef NDEBUG conss = SCIPconshdlrGetConss(conshdlr); nconss = SCIPconshdlrGetNConss(conshdlr); for( i = 0; i < nconss; i++ ) { consdata = SCIPconsGetData(conss[i]); assert(consdata != NULL); assert(consdata->node != NULL); assert((consdata->parentcons == NULL) == (SCIPnodeGetDepth(consdata->node) == 0)); assert(consdata->parentcons == NULL || SCIPconsGetData(consdata->parentcons)->child1cons == conss[i] || SCIPconsGetData(consdata->parentcons)->child2cons == conss[i] || ( SCIPinProbing(scip) && SCIPconsGetData(consdata->parentcons)->probingtmpcons == conss[i])); assert(consdata->child1cons == NULL || SCIPconsGetData(consdata->child1cons)->parentcons == conss[i]); assert(consdata->child2cons == NULL || SCIPconsGetData(consdata->child2cons)->parentcons == conss[i]); assert(consdata->probingtmpcons == NULL || SCIPinProbing(scip)); assert(consdata->probingtmpcons == NULL || SCIPconsGetData(consdata->probingtmpcons)->parentcons == conss[i]); assert(consdata->mastercons == NULL || GCGconsMasterbranchGetOrigcons(consdata->mastercons) == conss[i]); } #endif #endif }
/** execution method of propagator */ static SCIP_DECL_PROPEXEC(propExecDualfix) { /*lint --e{715}*/ int nfixedvars; SCIP_Bool cutoff; SCIP_Bool unbounded; assert(prop != NULL); assert(strcmp(SCIPpropGetName(prop), PROP_NAME) == 0); assert(result != NULL); *result = SCIP_DIDNOTRUN; /** @warning Don't run in probing or in repropagation since this can lead to wrong conclusion * * do not run if propagation w.r.t. current objective is not allowed */ if( SCIPinProbing(scip) || SCIPinRepropagation(scip) || !SCIPallowDualReds(scip) ) return SCIP_OKAY; cutoff = FALSE; unbounded = FALSE; nfixedvars = 0; SCIP_CALL( performDualfix(scip, &nfixedvars, &unbounded, &cutoff) ); /* evaluate propagation result */ if( cutoff ) *result = SCIP_CUTOFF; else if( unbounded ) *result = SCIP_UNBOUNDED; else if( nfixedvars > 0 ) *result = SCIP_REDUCEDDOM; else *result = SCIP_DIDNOTFIND; 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; }
/** execution method of presolver */ static SCIP_DECL_PRESOLEXEC(presolExecDualagg) { /*lint --e{715}*/ SCIPMILPMATRIX* matrix; SCIP_Bool initialized; SCIP_Bool complete; assert(result != NULL); *result = SCIP_DIDNOTRUN; if( (SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING) || SCIPinProbing(scip) || SCIPisNLPEnabled(scip) ) return SCIP_OKAY; if( SCIPisStopped(scip) || SCIPgetNActivePricers(scip) > 0 ) return SCIP_OKAY; if( SCIPgetNBinVars(scip) == 0 ) return SCIP_OKAY; if( !SCIPallowDualReds(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; matrix = NULL; SCIP_CALL( SCIPmatrixCreate(scip, &matrix, &initialized, &complete) ); /* we only work on pure MIPs currently */ if( initialized && complete ) { AGGRTYPE* aggtypes; SCIP_VAR** binvars; int nvaragg; int ncols; ncols = SCIPmatrixGetNColumns(matrix); nvaragg = 0; SCIP_CALL( SCIPallocBufferArray(scip, &aggtypes, ncols) ); BMSclearMemoryArray(aggtypes, ncols); SCIP_CALL( SCIPallocBufferArray(scip, &binvars, ncols) ); SCIPdebug( BMSclearMemoryArray(binvars, ncols) ); /* search for aggregations */ SCIP_CALL( findUplockAggregations(scip, matrix, &nvaragg, aggtypes, binvars) ); SCIP_CALL( findDownlockAggregations(scip, matrix, &nvaragg, aggtypes, binvars) ); /* apply aggregations, if we found any */ if( nvaragg > 0 ) { int v; for( v = 0; v < ncols; v++ ) { if( aggtypes[v] != NOAGG ) { SCIP_Bool infeasible; SCIP_Bool redundant; SCIP_Bool aggregated; SCIP_Real ub; SCIP_Real lb; ub = SCIPmatrixGetColUb(matrix, v); lb = SCIPmatrixGetColLb(matrix, v); /* aggregate variable */ assert(binvars[v] != NULL); if( aggtypes[v] == BIN0UBOUND ) { SCIP_CALL( SCIPaggregateVars(scip, SCIPmatrixGetVar(matrix, v), binvars[v], 1.0, ub-lb, ub, &infeasible, &redundant, &aggregated) ); } else { assert(aggtypes[v] == BIN0LBOUND); SCIP_CALL( SCIPaggregateVars(scip, SCIPmatrixGetVar(matrix, v), binvars[v], 1.0, lb-ub, lb, &infeasible, &redundant, &aggregated) ); } /* infeasible aggregation */ if( infeasible ) { SCIPdebugMessage(" -> infeasible aggregation\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } if( aggregated ) (*naggrvars)++; } } /* set result pointer */ if( (*naggrvars) > 0 ) *result = SCIP_SUCCESS; } SCIPfreeBufferArray(scip, &binvars); SCIPfreeBufferArray(scip, &aggtypes); } SCIPmatrixFree(scip, &matrix); return SCIP_OKAY; }
/** creates and captures a origbranch constraint */ SCIP_RETCODE GCGcreateConsOrigbranch( SCIP* scip, /**< SCIP data structure */ SCIP_CONS** cons, /**< pointer to hold the created constraint */ const char* name, /**< name of constraint */ SCIP_NODE* node, /**< the node to which this origbranch constraint belongs */ SCIP_CONS* parentcons, /**< origbranch constraint associated with the father node */ SCIP_BRANCHRULE* branchrule, /**< the branching rule that created the b&b node the constraint belongs to */ GCG_BRANCHDATA* branchdata /**< branching data storing information about the branching restrictions at the * corresponding node */ ) { SCIP_CONSHDLR* conshdlr; SCIP_CONSDATA* consdata; assert(scip != NULL); assert((parentcons == NULL) == (node == NULL)); /* find the origbranch constraint handler */ conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME); if( conshdlr == NULL ) { SCIPerrorMessage("origbranch constraint handler not found\n"); return SCIP_PLUGINNOTFOUND; } /* create constraint data */ SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) ); /* initialize the fields in the constraint data */ consdata->parentcons = parentcons; consdata->node = node; consdata->child1cons = NULL; consdata->child2cons = NULL; consdata->probingtmpcons = NULL; consdata->mastercons = NULL; consdata->branchrule = branchrule; consdata->branchdata = branchdata; consdata->npropbounds = 0; consdata->maxpropbounds = 0; consdata->propvars = NULL; consdata->propboundtypes = NULL; consdata->propbounds = NULL; SCIPdebugMessage("Creating branch orig constraint: <%s>.\n", name); /* create constraint */ SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE) ); /* store the pointer to the new constraint in the origbranch constraint of the parent node */ if( parentcons != NULL ) { SCIP_CONSDATA* parentdata; parentdata = SCIPconsGetData(parentcons); assert(parentdata != NULL); if( parentdata->child1cons == NULL ) { parentdata->child1cons = *cons; } else { assert(parentdata->child2cons == NULL || SCIPinProbing(scip)); /* store the second child in case we are in probing and have to overwrite it */ if( SCIPinProbing(scip) ) { assert(parentdata->probingtmpcons == NULL); parentdata->probingtmpcons = parentdata->child2cons; } parentdata->child2cons = *cons; } } return SCIP_OKAY; }
/** frees specific constraint data */ static SCIP_DECL_CONSDELETE(consDeleteOrigbranch) { /*lint --e{715}*/ SCIP_CONSDATA* parentdata; assert(scip != NULL); assert(conshdlr != NULL); assert(cons != NULL); assert(consdata != NULL); assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); assert(*consdata != NULL); SCIPdebugMessage("Deleting branch orig constraint: <%s>.\n", SCIPconsGetName(cons)); /* set the origcons pointer of the corresponding mastercons to NULL */ if( (*consdata)->mastercons != NULL ) GCGconsMasterbranchSetOrigcons((*consdata)->mastercons, NULL); /* set the pointer in the parent constraint to NULL */ if( (*consdata)->parentcons != NULL ) { parentdata = SCIPconsGetData((*consdata)->parentcons); if( parentdata->child1cons == cons ) parentdata->child1cons = NULL; else if( parentdata->probingtmpcons == cons ) { assert(SCIPinProbing(scip)); parentdata->probingtmpcons = NULL; } else { assert(parentdata->child2cons == cons); parentdata->child2cons = NULL; if( SCIPinProbing(scip) ) { parentdata->child2cons = parentdata->probingtmpcons; parentdata->probingtmpcons = NULL; } } } /* no child nodes may exist */ assert((*consdata)->child1cons == NULL); assert((*consdata)->child2cons == NULL); /* delete branchdata, if no mastercons is linked, which would still need the branchdata * otherwise, the mastercons deletes the branchdata when it is deleted itself */ if( (*consdata)->mastercons == NULL && (*consdata)->branchdata != NULL ) { SCIP_CALL( GCGrelaxBranchDataDelete(scip, (*consdata)->branchrule, &(*consdata)->branchdata) ); } /* free propagation domain changes arrays */ if( (*consdata)->maxpropbounds > 0 ) { SCIPfreeMemoryArray(scip, &((*consdata)->propvars)); SCIPfreeMemoryArray(scip, &((*consdata)->propboundtypes)); SCIPfreeMemoryArray(scip, &((*consdata)->propbounds)); } /* free constraint data */ SCIPfreeBlockMemory(scip, consdata); 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; }