/* check whether coef is the r-th row of the inverse basis matrix B^-1; this is * the case if( coef * B ) is the r-th unit vector */ SCIP_RETCODE SCIPdebugCheckBInvRow( SCIP* scip, /**< SCIP data structure */ int r, /**< row number */ SCIP_Real* coef /**< r-th row of the inverse basis matrix */ ) { SCIP_Real vecval; SCIP_Real matrixval; int* basisind; int nrows; int idx; int i; int k; assert(scip != NULL); nrows = SCIPgetNLPRows(scip); /* get basic indices for the basic matrix B */ SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* loop over the columns of B */ for( k = 0; k < nrows; ++k ) { vecval = 0.0; /* indices of basic columns and rows: * - index i >= 0 corresponds to column i, * - index i < 0 to row -i-1 */ idx = basisind[k]; /* check if we have a slack variable; this is the case if idx < 0 */ if( idx >= 0 ) { /* loop over the rows to compute the corresponding value in the unit vector */ for( i = 0; i < nrows; ++i ) { SCIP_CALL( SCIPlpiGetCoef(scip->lp->lpi, i, idx, &matrixval) ); vecval += coef[i] * matrixval; } } else { assert( idx < 0 ); /* retransform idx * - index i >= 0 corresponds to column i, * - index i < 0 to row -i-1 */ idx = -idx - 1; assert( idx >= 0 && idx < nrows ); /* since idx < 0 we are in the case of a slack variable, i.e., the corresponding column is the idx-unit vector; note that some LP solver return a -idx-unit vector */ /* vecval = REALABS(coef[idx]);*/ vecval = coef[idx]; } /* check if vecval fits to the r-th unit vector */ if( k == r && !SCIPisFeasEQ(scip, vecval, 1.0) ) { /* we expected a 1.0 and found something different */ SCIPwarningMessage("checked SCIPgetLPBInvRow() found value <%g> expected 1.0\n", vecval); } else if( k != r && !SCIPisFeasZero(scip, vecval) ) { /* we expected a 0.0 and found something different */ SCIPwarningMessage("checked SCIPgetLPBInvRow() found value <%g> expected 0.0\n", vecval); } } SCIPfreeBufferArray(scip, &basisind); return SCIP_OKAY; }
/** initializes the pricing problem for the given capacity */ static SCIP_RETCODE initPricing( SCIP* scip, /**< SCIP data structure */ SCIP_PRICERDATA* pricerdata, /**< pricer data */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars /**< variable array for the items */ ) { SCIP_CONS** conss; SCIP_Longint* vals; SCIP_CONS* cons; SCIP_VAR* var; SCIP_Longint* weights; SCIP_Longint capacity; SCIP_Real dual; int nitems; int nvars; int c; assert( SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM ); assert(pricerdata != NULL); nitems = pricerdata->nitems; conss = pricerdata->conss; weights = pricerdata->weights; capacity = pricerdata->capacity; nvars = 0; SCIP_CALL( SCIPallocBufferArray(subscip, &vals, nitems) ); /* create for each order, which is not assigned yet, a variable with objective coefficient */ for( c = 0; c < nitems; ++c ) { cons = conss[c]; /* check if each constraint is setppc constraint */ assert( !strncmp( SCIPconshdlrGetName( SCIPconsGetHdlr(cons) ), "setppc", 6) ); /* constraints which are (locally) disabled/redundant are not of * interest since the corresponding job is assigned to a packing */ if( !SCIPconsIsEnabled(cons) ) continue; if( SCIPgetNFixedonesSetppc(scip, cons) == 1 ) { /* disable constraint locally */ SCIP_CALL( SCIPdelConsLocal(scip, cons) ); continue; } /* dual value in original SCIP */ dual = SCIPgetDualsolSetppc(scip, cons); SCIP_CALL( SCIPcreateVarBasic(subscip, &var, SCIPconsGetName(cons), 0.0, 1.0, dual, SCIP_VARTYPE_BINARY) ); SCIP_CALL( SCIPaddVar(subscip, var) ); vals[nvars] = weights[c]; vars[nvars] = var; nvars++; /* release variable */ SCIP_CALL( SCIPreleaseVar(subscip, &var) ); } /* create capacity constraint */ SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, "capacity", nvars, vars, vals, capacity) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* add constraint of the branching decisions */ SCIP_CALL( addBranchingDecisionConss(scip, subscip, vars, pricerdata->conshdlr) ); /* avoid to generate columns which are fixed to zero */ SCIP_CALL( addFixedVarsConss(scip, subscip, vars, conss, nitems) ); SCIPfreeBufferArray(subscip, &vals); 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; /* 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 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) ); /* 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); 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("Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode); SCIPwarningMessage("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) ); } 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; }
/** execution method of presolver */ static SCIP_DECL_PRESOLEXEC(presolExecDualagg) { /*lint --e{715}*/ SCIP_MATRIX* 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 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; }
/** create the extra constraint of local branching and add it to subscip */ static SCIP_RETCODE addLocalBranchingConstraint( SCIP* scip, /**< SCIP data structure of the original problem */ SCIP* subscip, /**< SCIP data structure of the subproblem */ SCIP_VAR** subvars, /**< variables of the subproblem */ SCIP_HEURDATA* heurdata /**< heuristic's data structure */ ) { SCIP_CONS* cons; /* local branching constraint to create */ SCIP_VAR** consvars; SCIP_VAR** vars; SCIP_SOL* bestsol; int nbinvars; int i; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real* consvals; char consname[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_localbranchcons", SCIPgetProbName(scip)); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, NULL, &nbinvars, NULL, NULL, NULL) ); bestsol = SCIPgetBestSol(scip); assert( bestsol != NULL ); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) ); /* set initial left and right hand sides of local branching constraint */ lhs = (SCIP_Real)heurdata->emptyneighborhoodsize + 1.0; rhs = (SCIP_Real)heurdata->curneighborhoodsize; /* create the distance (to incumbent) function of the binary variables */ for( i = 0; i < nbinvars; i++ ) { SCIP_Real solval; solval = SCIPgetSolVal(scip, bestsol, vars[i]); assert( SCIPisFeasIntegral(scip,solval) ); /* is variable i part of the binary support of bestsol? */ if( SCIPisFeasEQ(scip,solval,1.0) ) { consvals[i] = -1.0; rhs -= 1.0; lhs -= 1.0; } else consvals[i] = 1.0; consvars[i] = subvars[i]; assert( SCIPvarGetType(consvars[i]) == SCIP_VARTYPE_BINARY ); } /* creates localbranching constraint and adds it to subscip */ SCIP_CALL( SCIPcreateConsLinear(subscip, &cons, consname, nbinvars, consvars, consvals, lhs, rhs, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); /* free local memory */ SCIPfreeBufferArray(scip, &consvals); SCIPfreeBufferArray(scip, &consvars); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpGomory) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_VAR** vars; SCIP_COL** cols; SCIP_ROW** rows; SCIP_Real* binvrow; SCIP_Real* cutcoefs; SCIP_Real maxscale; SCIP_Real minfrac; SCIP_Real maxfrac; SCIP_Longint maxdnom; SCIP_Bool cutoff; int* basisind; int naddedcuts; int nvars; int ncols; int nrows; int ncalls; int depth; int maxdepth; int maxsepacuts; int c; int i; assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); depth = SCIPgetDepth(scip); ncalls = SCIPsepaGetNCallsAtNode(sepa); minfrac = sepadata->away; maxfrac = 1.0 - sepadata->away; /* only call separator, if we are not close to terminating */ if( SCIPisStopped(scip) ) return SCIP_OKAY; /* only call the gomory cut separator a given number of times at each node */ if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) ) return SCIP_OKAY; /* only call separator, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call separator, if the LP solution is basic */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* only call separator, if there are fractional variables */ if( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; /* get variables data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* get LP data */ SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); if( ncols == 0 || nrows == 0 ) return SCIP_OKAY; #if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */ if( ncols >= 50*nrows ) return SCIP_OKAY; if( ncols >= 5*nrows ) { int ncutsfound; ncutsfound = SCIPgetNCutsFound(scip); if( ncutsfound > sepadata->lastncutsfound || !SCIPsepaWasLPDelayed(sepa) ) { sepadata->lastncutsfound = ncutsfound; *result = SCIP_DELAYED; return SCIP_OKAY; } } #endif /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to * scale resulting cut to integral values to avoid numerical instabilities */ /**@todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */ maxdepth = SCIPgetMaxDepth(scip); if( depth == 0 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/4 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/2 ) { maxdnom = 100; maxscale = 100.0; } else { maxdnom = 10; maxscale = 10.0; } /* allocate temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) ); /* get basis indices */ SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* get the maximal number of cuts allowed in a separation round */ if( depth == 0 ) maxsepacuts = sepadata->maxsepacutsroot; else maxsepacuts = sepadata->maxsepacuts; SCIPdebugMessage("searching gomory cuts: %d cols, %d rows, maxdnom=%"SCIP_LONGINT_FORMAT", maxscale=%g, maxcuts=%d\n", ncols, nrows, maxdnom, maxscale, maxsepacuts); cutoff = FALSE; naddedcuts = 0; /* for all basic columns belonging to integer variables, try to generate a gomory cut */ for( i = 0; i < nrows && naddedcuts < maxsepacuts && !SCIPisStopped(scip) && !cutoff; ++i ) { SCIP_Bool tryrow; tryrow = FALSE; c = basisind[i]; if( c >= 0 ) { SCIP_VAR* var; assert(c < ncols); var = SCIPcolGetVar(cols[c]); if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real primsol; primsol = SCIPcolGetPrimsol(cols[c]); assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/ if( SCIPfeasFrac(scip, primsol) >= minfrac ) { SCIPdebugMessage("trying gomory cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol); tryrow = TRUE; } } } else if( sepadata->separaterows ) { SCIP_ROW* row; assert(0 <= -c-1 && -c-1 < nrows); row = rows[-c-1]; if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) ) { SCIP_Real primsol; primsol = SCIPgetRowActivity(scip, row); if( SCIPfeasFrac(scip, primsol) >= minfrac ) { SCIPdebugMessage("trying gomory cut for row <%s> [%g]\n", SCIProwGetName(row), primsol); tryrow = TRUE; } } } if( tryrow ) { SCIP_Real cutrhs; SCIP_Real cutact; SCIP_Bool success; SCIP_Bool cutislocal; /* get the row of B^-1 for this basic integer variable with fractional solution value */ SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow) ); cutact = 0.0; cutrhs = SCIPinfinity(scip); /* create a MIR cut out of the weighted LP rows using the B^-1 row as weights */ SCIP_CALL( SCIPcalcMIR(scip, NULL, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, FIXINTEGRALRHS, NULL, NULL, (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, minfrac, maxfrac, binvrow, 1.0, NULL, NULL, cutcoefs, &cutrhs, &cutact, &success, &cutislocal) ); assert(ALLOWLOCAL || !cutislocal); /* @todo Currently we are using the SCIPcalcMIR() function to compute the coefficients of the Gomory * cut. Alternatively, we could use the direct version (see thesis of Achterberg formula (8.4)) which * leads to cut a of the form \sum a_i x_i \geq 1. Rumor has it that these cuts are better. */ SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs); /* if successful, convert dense cut into sparse row, and add the row as a cut */ if( success && SCIPisFeasGT(scip, cutact, cutrhs) ) { SCIP_ROW* cut; char cutname[SCIP_MAXSTRLEN]; int v; /* construct cut name */ if( c >= 0 ) (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_x%d", SCIPgetNLPs(scip), c); else (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_s%d", SCIPgetNLPs(scip), -c-1); /* create empty cut */ SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) ); /* cache the row extension and only flush them if the cut gets added */ SCIP_CALL( SCIPcacheRowExtensions(scip, cut) ); /* collect all non-zero coefficients */ for( v = 0; v < nvars; ++v ) { if( !SCIPisZero(scip, cutcoefs[v]) ) { SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[v], cutcoefs[v]) ); } } if( SCIProwGetNNonz(cut) == 0 ) { assert(SCIPisFeasNegative(scip, cutrhs)); SCIPdebugMessage(" -> gomory cut detected infeasibility with cut 0 <= %f\n", cutrhs); cutoff = TRUE; } else if( SCIProwGetNNonz(cut) == 1 ) { /* add the bound change as cut to avoid that the LP gets modified. that would mean the LP is not flushed * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply that bound change automatically */ SCIP_CALL( SCIPaddCut(scip, NULL, cut, TRUE) ); naddedcuts++; } else { /* Only take efficacious cuts, except for cuts with one non-zero coefficients (= bound * changes); the latter cuts will be handeled internally in sepastore. */ if( SCIPisCutEfficacious(scip, NULL, cut) ) { assert(success == TRUE); SCIPdebugMessage(" -> gomory cut for <%s>: act=%f, rhs=%f, eff=%f\n", c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]), cutact, cutrhs, SCIPgetCutEfficacy(scip, NULL, cut)); if( sepadata->makeintegral ) { /* try to scale the cut to integral values */ SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); if( sepadata->forcecuts ) success = TRUE; /* in case the left hand side in minus infinity and the right hand side is plus infinity the cut is * useless so we are not taking it at all */ if( (SCIPisInfinity(scip, -SCIProwGetLhs(cut)) && SCIPisInfinity(scip, SCIProwGetRhs(cut))) ) success = FALSE; /* @todo Trying to make the Gomory cut integral might fail. Due to numerical reasons/arguments we * currently ignore such cuts. If the cut, however, has small support (let's say smaller or equal to * 5), we might want to add that cut (even it does not have integral coefficients). To be able to * do that we need to add a rank to the data structure of a row. The rank of original rows are * zero and for aggregated rows it is the maximum over all used rows plus one. */ } if( success ) { SCIPdebugMessage(" -> found gomory cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut), SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut)); /* flush all changes before adding the cut */ SCIP_CALL( SCIPflushRowExtensions(scip, cut) ); /* add global cuts which are not implicit bound changes to the cut pool */ if( !cutislocal ) { if( sepadata->delayedcuts ) { SCIP_CALL( SCIPaddDelayedPoolCut(scip, cut) ); } else { SCIP_CALL( SCIPaddPoolCut(scip, cut) ); } } else { /* local cuts we add to the sepastore */ SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE) ); } naddedcuts++; } } } /* release the row */ SCIP_CALL( SCIPreleaseRow(scip, &cut) ); } } } /* free temporary memory */ SCIPfreeBufferArray(scip, &binvrow); SCIPfreeBufferArray(scip, &basisind); SCIPfreeBufferArray(scip, &cutcoefs); SCIPdebugMessage("end searching gomory cuts: found %d cuts\n", naddedcuts); sepadata->lastncutsfound = SCIPgetNCutsFound(scip); /* evalute the result of the separation */ if( cutoff ) *result = SCIP_CUTOFF; else if ( naddedcuts > 0 ) *result = SCIP_SEPARATED; else *result = SCIP_DIDNOTFIND; return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecRootsoldiving) /*lint --e{715}*/ { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_VAR** vars; SCIP_Real* rootsol; SCIP_Real* objchgvals; int* softroundings; int* intvalrounds; int nvars; int nbinvars; int nintvars; int nlpcands; SCIP_LPSOLSTAT lpsolstat; SCIP_Real absstartobjval; SCIP_Real objstep; SCIP_Real alpha; SCIP_Real oldobj; SCIP_Real newobj; SCIP_Bool lperror; SCIP_Bool lpsolchanged; SCIP_Longint nsolsfound; SCIP_Longint ncalls; SCIP_Longint nlpiterations; SCIP_Longint maxnlpiterations; int depth; int maxdepth; int maxdivedepth; int divedepth; int startnlpcands; int ncycles; int i; 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; /* 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 number of fractional variables, that should be integral */ nlpcands = SCIPgetNLPBranchCands(scip); /* 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 = MAX(maxdivedepth, 10); *result = SCIP_DIDNOTFIND; /* get all variables of LP */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); /* get root solution value of all binary and integer variables */ SCIP_CALL( SCIPallocBufferArray(scip, &rootsol, nbinvars + nintvars) ); for( i = 0; i < nbinvars + nintvars; i++ ) rootsol[i] = SCIPvarGetRootSol(vars[i]); /* get current LP objective value, and calculate length of a single step in an objective coefficient */ absstartobjval = SCIPgetLPObjval(scip); absstartobjval = ABS(absstartobjval); absstartobjval = MAX(absstartobjval, 1.0); objstep = absstartobjval / 10.0; /* initialize array storing the preferred soft rounding directions and counting the integral value rounds */ SCIP_CALL( SCIPallocBufferArray(scip, &softroundings, nbinvars + nintvars) ); BMSclearMemoryArray(softroundings, nbinvars + nintvars); SCIP_CALL( SCIPallocBufferArray(scip, &intvalrounds, nbinvars + nintvars) ); BMSclearMemoryArray(intvalrounds, nbinvars + nintvars); /* allocate temporary memory for buffering objective changes */ SCIP_CALL( SCIPallocBufferArray(scip, &objchgvals, nbinvars + nintvars) ); /* start diving */ SCIP_CALL( SCIPstartDive(scip) ); SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing rootsoldiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d, LPobj=%g, objstep=%g\n", SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth, SCIPgetLPObjval(scip), objstep); lperror = FALSE; divedepth = 0; lpsolstat = SCIP_LPSOLSTAT_OPTIMAL; alpha = heurdata->alpha; ncycles = 0; lpsolchanged = TRUE; startnlpcands = nlpcands; while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && ncycles < 10 && (divedepth < 10 || nlpcands <= startnlpcands - divedepth/2 || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) ) { SCIP_Bool success; int hardroundingidx; int hardroundingdir; SCIP_Real hardroundingoldbd; SCIP_Real hardroundingnewbd; SCIP_Bool boundschanged; SCIP_RETCODE retcode; /* 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("rootsoldiving 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; } } divedepth++; hardroundingidx = -1; hardroundingdir = 0; hardroundingoldbd = 0.0; hardroundingnewbd = 0.0; boundschanged = FALSE; SCIPdebugMessage("dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT":\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations); /* round solution x* from diving LP: * - x~_j = down(x*_j) if x*_j is integer or binary variable and x*_j <= root solution_j * - x~_j = up(x*_j) if x*_j is integer or binary variable and x*_j > root solution_j * - x~_j = x*_j if x*_j is continuous variable * change objective function in diving LP: * - if x*_j is integral, or j is a continuous variable, set obj'_j = alpha * obj_j * - otherwise, set obj'_j = alpha * obj_j + sign(x*_j - x~_j) */ for( i = 0; i < nbinvars + nintvars; i++ ) { SCIP_VAR* var; SCIP_Real solval; var = vars[i]; oldobj = SCIPgetVarObjDive(scip, var); newobj = oldobj; solval = SCIPvarGetLPSol(var); if( SCIPisFeasIntegral(scip, solval) ) { /* if the variable became integral after a soft rounding, count the rounds; after a while, fix it to its * current integral value; * otherwise, fade out the objective value */ if( softroundings[i] != 0 && lpsolchanged ) { intvalrounds[i]++; if( intvalrounds[i] == 5 && SCIPgetVarLbDive(scip, var) < SCIPgetVarUbDive(scip, var) - 0.5 ) { /* use exact integral value, if the variable is only integral within numerical tolerances */ solval = SCIPfloor(scip, solval+0.5); SCIPdebugMessage(" -> fixing <%s> = %g\n", SCIPvarGetName(var), solval); SCIP_CALL( SCIPchgVarLbDive(scip, var, solval) ); SCIP_CALL( SCIPchgVarUbDive(scip, var, solval) ); boundschanged = TRUE; } } else newobj = alpha * oldobj; } else if( solval <= rootsol[i] ) { /* if the variable was soft rounded most of the time downwards, round it downwards by changing the bounds; * otherwise, apply soft rounding by changing the objective value */ softroundings[i]--; if( softroundings[i] <= -10 && hardroundingidx == -1 ) { SCIPdebugMessage(" -> hard rounding <%s>[%g] <= %g\n", SCIPvarGetName(var), solval, SCIPfeasFloor(scip, solval)); hardroundingidx = i; hardroundingdir = -1; hardroundingoldbd = SCIPgetVarUbDive(scip, var); hardroundingnewbd = SCIPfeasFloor(scip, solval); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd) ); boundschanged = TRUE; } else newobj = alpha * oldobj + objstep; } else { /* if the variable was soft rounded most of the time upwards, round it upwards by changing the bounds; * otherwise, apply soft rounding by changing the objective value */ softroundings[i]++; if( softroundings[i] >= +10 && hardroundingidx == -1 ) { SCIPdebugMessage(" -> hard rounding <%s>[%g] >= %g\n", SCIPvarGetName(var), solval, SCIPfeasCeil(scip, solval)); hardroundingidx = i; hardroundingdir = +1; hardroundingoldbd = SCIPgetVarLbDive(scip, var); hardroundingnewbd = SCIPfeasCeil(scip, solval); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd) ); boundschanged = TRUE; } else newobj = alpha * oldobj - objstep; } /* remember the objective change */ objchgvals[i] = newobj; } /* apply objective changes if there was no bound change */ if( !boundschanged ) { /* apply cached changes on integer variables */ for( i = 0; i < nbinvars + nintvars; ++i ) { SCIP_VAR* var; var = vars[i]; SCIPdebugMessage(" -> i=%d var <%s>, solval=%g, rootsol=%g, oldobj=%g, newobj=%g\n", i, SCIPvarGetName(var), SCIPvarGetLPSol(var), rootsol[i], SCIPgetVarObjDive(scip, var), objchgvals[i]); SCIP_CALL( SCIPchgVarObjDive(scip, var, objchgvals[i]) ); } /* fade out the objective values of the continuous variables */ for( i = nbinvars + nintvars; i < nvars; i++ ) { SCIP_VAR* var; var = vars[i]; oldobj = SCIPgetVarObjDive(scip, var); newobj = alpha * oldobj; SCIPdebugMessage(" -> i=%d var <%s>, solval=%g, oldobj=%g, newobj=%g\n", i, SCIPvarGetName(var), SCIPvarGetLPSol(var), oldobj, newobj); SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) ); } } SOLVEAGAIN: /* resolve the diving LP */ nlpiterations = SCIPgetNLPIterations(scip); retcode = SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror); 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 Rootsoldiving 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; /* if no LP iterations were performed, we stayed at the same solution -> count this cycling */ lpsolchanged = (SCIPgetNLPIterations(scip) != nlpiterations); if( lpsolchanged ) ncycles = 0; else if( !boundschanged ) /* do not count if integral variables have been fixed */ ncycles++; /* get LP solution status and number of fractional variables, that should be integral */ if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE && hardroundingidx != -1 ) { SCIP_VAR* var; var = vars[hardroundingidx]; /* round the hard rounded variable to the opposite direction and resolve the LP */ if( hardroundingdir == -1 ) { SCIPdebugMessage(" -> opposite hard rounding <%s> >= %g\n", SCIPvarGetName(var), hardroundingnewbd + 1.0); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingoldbd) ); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd + 1.0) ); } else { SCIPdebugMessage(" -> opposite hard rounding <%s> <= %g\n", SCIPvarGetName(var), hardroundingnewbd - 1.0); SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingoldbd) ); SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd - 1.0) ); } hardroundingidx = -1; goto SOLVEAGAIN; } if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL ) nlpcands = SCIPgetNLPBranchCands(scip); SCIPdebugMessage(" -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands); } SCIPdebugMessage("---> diving finished: lpsolstat = %d, depth %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT"\n", lpsolstat, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations); /* 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("rootsoldiving 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 */ SCIPfreeBufferArray(scip, &objchgvals); SCIPfreeBufferArray(scip, &intvalrounds); SCIPfreeBufferArray(scip, &softroundings); SCIPfreeBufferArray(scip, &rootsol); SCIPdebugMessage("rootsoldiving heuristic finished\n"); return SCIP_OKAY; }
/** 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; }
/** constraint copying method of constraint handler */ static SCIP_DECL_CONSCOPY(consCopyConjunction) { /*lint --e{715}*/ SCIP_CONSDATA* sourcedata; SCIP_CONS** sourceconss; SCIP_CONS** conss; int nconss; int c; *valid = TRUE; sourcedata = SCIPconsGetData(sourcecons); assert(sourcedata != NULL); sourceconss = sourcedata->conss; nconss = sourcedata->nconss; if( nconss > 0 ) { assert(sourceconss != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &conss, nconss) ); /* copy each constraint one by one */ for( c = 0; c < nconss && (*valid); ++c ) { SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourceconss[c], &conss[c], SCIPconsGetHdlr(sourceconss[c]), varmap, consmap, SCIPconsGetName(sourceconss[c]), SCIPconsIsInitial(sourceconss[c]), SCIPconsIsSeparated(sourceconss[c]), SCIPconsIsEnforced(sourceconss[c]), SCIPconsIsChecked(sourceconss[c]), SCIPconsIsPropagated(sourceconss[c]), SCIPconsIsLocal(sourceconss[c]), SCIPconsIsModifiable(sourceconss[c]), SCIPconsIsDynamic(sourceconss[c]), SCIPconsIsRemovable(sourceconss[c]), SCIPconsIsStickingAtNode(sourceconss[c]), global, valid) ); assert(!(*valid) || conss[c] != NULL); } if( *valid ) { if( name == NULL ) { SCIP_CALL( SCIPcreateConsConjunction(scip, cons, SCIPconsGetName(sourcecons), nconss, conss, enforce, check, local, modifiable, dynamic) ); } else { SCIP_CALL( SCIPcreateConsConjunction(scip, cons, name, nconss, conss, enforce, check, local, modifiable, dynamic) ); } } /* release the copied constraints */ for( c = (*valid ? c - 1 : c - 2); c >= 0; --c ) { assert(conss[c] != NULL); SCIP_CALL( SCIPreleaseCons(scip, &conss[c]) ); } SCIPfreeBufferArray(scip, &conss); } return SCIP_OKAY; }
/** * Preprocessing of the graph, using 2 methods in order to find redundant nodes * that can be deleted and easily colored later. * * Foundation of these methods is the computation of a maximum clique C with M nodes. * After this computation, the following two steps are repeated until no node was deleted * in the last iteration: * * 1: Low-Degree: * Iterativly delete all nodes v in the graph G with degree d(v) < M ( don't delete nodes of C ) * * 2: Dominated Neighbourhood: * If the neighbourhood of one node v is part of the neighbourhood of another node w, v can * be deleted, since it can later get the same color as w. */ static SCIP_RETCODE preprocessGraph( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; /* the problemdata */ SCIP_Bool changed; /* was the graph changed in the last round of preprocessing? */ SCIP_Bool dominates; /* is the neighbourhood of one node dominated by the neigbourhood of another one?*/ int* maxcliquenodes; /* pointer to store nodes of the maximum weight clique */ int nmaxcliquenodes; /* number of nodes in the maximum weight clique */ TCLIQUE_WEIGHT maxcliqueweight; /* weight of the maximum weight clique */ TCLIQUE_STATUS status; /* status of clique-computation */ TCLIQUE_GRAPH* currgraph; /* the current, not preprocessed graph in each step */ int currnnodes; /* the current number of nodes in each step */ int actnewnode; /* the number of nodes yet marked for beeing in the graph in the next round */ int* newnodes; /* the nodes that will be in the graph in the next round */ int* degrees; /* the degrees of the nodes */ int myround; /* the number of the current round */ int ndeletednodes; /* the total number of deleted nodes */ int nnodesdeleteddegreethisround; /* the number of nodes deleted due to low degree in the current round */ int nnodesdeletedneighbourthisround; /* the number of nodes deleted due to neighbourhood in the current round */ int* firstedge; /* pointer for the edges in the graph */ int* lastedge; /* pointer for the edges in the graph */ int i; int j; char opt; assert(scip != NULL); probdata = SCIPgetProbData(scip); assert(probdata != NULL); printf("\npreprocessing...\n"); /* copy the old graph */ if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, tcliqueGetNNodes(probdata->oldgraph)-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < tcliqueGetNNodes(probdata->oldgraph); i++ ) { /* get adjacent nodes for node i */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, i); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, i); while ( firstedge <= lastedge ) { if ( *firstedge > i ) { if( !tcliqueAddEdge(currgraph, i, *firstedge) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } currnnodes = tcliqueGetNNodes(probdata->oldgraph); /* get memory for array of deletednodes */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->deletednodes), COLORprobGetOriginalNNodes(scip)) ); /* get memory for array new2oldnodes */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->new2oldnode), COLORprobGetOriginalNNodes(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &newnodes, COLORprobGetOriginalNNodes(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &maxcliquenodes, COLORprobGetOriginalNNodes(scip)) ); for ( i = 0; i < currnnodes; i++ ) { /* set weights of the nodes to 1 */ tcliqueChangeWeight(currgraph, i, 1); /* every node in the graph represents the same node in the original graph */ probdata->new2oldnode[i] = i; } /* compute maximum clique */ tcliqueMaxClique(NULL, NULL, NULL, NULL, currgraph, NULL, NULL, maxcliquenodes, &nmaxcliquenodes, &maxcliqueweight, 0, 0, 50000, 0, INT_MAX, -1, NULL, &status); opt = ( status == TCLIQUE_OPTIMAL ? ' ' : '*' ); printf("size of the maximum clique: %d%c \n", nmaxcliquenodes, opt); ndeletednodes = 0; nnodesdeleteddegreethisround = 1; nnodesdeletedneighbourthisround = 1; myround = 0; /* main loop */ while ( (nnodesdeleteddegreethisround > 0) || (nnodesdeletedneighbourthisround > 0) ) { myround++; nnodesdeleteddegreethisround = 0; nnodesdeletedneighbourthisround = 0; changed = TRUE; /* node degree deletion loop */ while ( changed == TRUE ) { changed = FALSE; actnewnode = 0; degrees = tcliqueGetDegrees(currgraph); for (i = 0; i < currnnodes; i++) { /* degree is low, node can be deleted */ if ( (degrees[i] < nmaxcliquenodes ) && (!COLORprobIsNodeInArray(probdata->new2oldnode[i], maxcliquenodes, nmaxcliquenodes)) ) { probdata->deletednodes[ndeletednodes] = probdata->new2oldnode[i]; changed = TRUE; nnodesdeleteddegreethisround++; ndeletednodes++; } /* node will be in the new graph, because degree is not low enought for deletion or it is in the maxClique */ else { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /* at least one node was deletet, create new graph ( tclique doesn't support deletion of nodes) */ if ( changed ) { assert(actnewnode+ndeletednodes == COLORprobGetOriginalNNodes(scip)); /* create new current graph */ tcliqueFree(&currgraph); if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, actnewnode-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < actnewnode; i++ ) { /* get adjacent nodes for node newnodes[i] */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, newnodes[i]); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, newnodes[i]); while ( firstedge <= lastedge ) { /* try to find a node in newnodes which corresponds to the node in the old graph, that is the end-node of the edge */ for ( j = i+1; j < actnewnode; j++ ) { if ( *firstedge == newnodes[j] ) { if( !tcliqueAddEdge(currgraph, i, j) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } break; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* update currnnodes */ currnnodes = tcliqueGetNNodes(currgraph); /* update new2oldnodes */ for ( i = 0; i < actnewnode; i++ ) { probdata->new2oldnode[i] = newnodes[i]; } /* set the corresponding old node to -1 for all nodes not in the current graph (only for bug-finding) */ for ( i = actnewnode; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->new2oldnode[i] = -1; } } } /* end node degree deletion loop */ /* set changed to TRUE for getting into the while-loop */ changed = TRUE; /* loop for finding dominated neighbourhoods */ while ( changed == TRUE ) { changed = FALSE; actnewnode = 0; /* i is the node which is checked for beeing dominated */ for ( i = 0; i < currnnodes; i++ ) { assert(!COLORprobIsNodeInArray(probdata->new2oldnode[i], probdata->deletednodes, ndeletednodes)); /* i must be not in the clique and not yet deleted */ if ( (!COLORprobIsNodeInArray(probdata->new2oldnode[i], maxcliquenodes, nmaxcliquenodes)) ) { /* j is the node for which is checked whether it dominates i */ for ( j = 0; j < currnnodes; j++ ) { /* i must be distinct from j, there must be no edge between i and j, j may not have been deleted due to degree in the last round */ if ( (j != i) && !tcliqueIsEdge(currgraph, i, j) && (!COLORprobIsNodeInArray(probdata->new2oldnode[j], probdata->deletednodes, ndeletednodes)) ) /** @todo only check nodes deleted in the last round */ { /* check whether nodes adjacent to i are also adjacent to j <-> j dominates i */ dominates = TRUE; /* get adjacent nodes for node i in currgraph */ firstedge = tcliqueGetFirstAdjedge(currgraph, i); lastedge = tcliqueGetLastAdjedge(currgraph, i); while ( firstedge <= lastedge ) { /* check whether (j,firstedge) is in currgraph, if not, j doesn't dominate i */ if ( !tcliqueIsEdge(currgraph, j, *firstedge) ) { dominates = FALSE; break; } firstedge++; } if ( dominates ) { probdata->deletednodes[ndeletednodes] = probdata->new2oldnode[i]; changed = TRUE; ndeletednodes++; nnodesdeletedneighbourthisround++; break; /* for j, because we already now that i is dominated and deleted i */ } } } /* end for j */ /* if i is dominated by no other node and thus not deleted, put it into newnodes, so that it is in the next graph */ if ( ndeletednodes == 0 || probdata->deletednodes[ndeletednodes-1] != probdata->new2oldnode[i]) { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /* if i is in the maxClique und was thus not deleted, put it into newnodes, so that it is in the next graph */ else { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /*end for i */ /* at least one node was deletet, create new graph ( tclique doesn't support deletion of nodes) */ if ( changed ) { assert(actnewnode+ndeletednodes == COLORprobGetOriginalNNodes(scip)); /* create new current graph */ tcliqueFree(&currgraph); if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, actnewnode-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < actnewnode; i++ ) { /* get adjacent nodes for node newnodes[i] */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, newnodes[i]); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, newnodes[i]); while ( firstedge <= lastedge ) { /* try to find a node in newnodes which corresponds to the node in the old graph, that is the end-node of the edge */ for ( j = i+1; j < actnewnode; j++ ) { if ( *firstedge == newnodes[j] ) { if( !tcliqueAddEdge(currgraph, i, j) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } break; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* update currnnodes */ currnnodes = tcliqueGetNNodes(currgraph); /* update new2oldnodes */ for ( i = 0; i < actnewnode; i++ ) { probdata->new2oldnode[i] = newnodes[i]; } /* set the corresponding old node to -1 for all nodes not in the current graph (only for bug-finding) */ for ( i = actnewnode; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->new2oldnode[i] = -1; } } } /* end of loop for finding dominated neighbourhoods */ printf("Round %d of preprocessing:\n", myround); printf(" deleted low degree vertices: %d\n", nnodesdeleteddegreethisround); printf(" deleted almost cliques: %d\n", nnodesdeletedneighbourthisround); } for ( i = ndeletednodes; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->deletednodes[i] = -1; } printf("preprocessing overall deleted vertices: %d\n\n", ndeletednodes); /* copy preprocessed graph into problem data */ probdata->graph = currgraph; SCIPfreeBufferArray(scip, &newnodes); SCIPfreeBufferArray(scip, &maxcliquenodes); return SCIP_OKAY; }
/** constraint parsing method of constraint handler */ static SCIP_DECL_CONSPARSE(consParseConjunction) { /*lint --e{715}*/ SCIP_CONS** conss; int nconss; int sconss; char* token; char* saveptr; char* nexttokenstart; char* copystr; assert(scip != NULL); assert(conshdlr != NULL); assert(cons != NULL); assert(success != NULL); assert(str != NULL); assert(name != NULL); SCIPdebugMessage("parsing conjunction <%s>\n", name); *success = TRUE; /* allocate memory for constraint in conjunction, initial size is set to 10 */ nconss = 0; sconss = 10; SCIP_CALL( SCIPallocBufferArray(scip, &conss, sconss) ); SCIP_CALL( SCIPduplicateBufferArray(scip, ©str, str, (int)strlen(str)+1) ); /* find '(' at the beginning, string should start with 'conjunction(' */ saveptr = strpbrk(copystr, "("); /*lint !e158*/ if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* skip '(' */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; /* brackets '(' and ')' can exist co we check for them and the constraint delimeter */ saveptr = strpbrk(saveptr, "(,"); /* brackets '(' and ')' can exist in the rest of the string so we need to skip them to find the end of the first * sub-constraint marked by a ',' */ if( saveptr != NULL ) { do { int bracketcounter = 0; if( *saveptr == '(' ) { do { ++bracketcounter; ++saveptr; /* find last ending bracket */ while( bracketcounter > 0 ) { saveptr = strpbrk(saveptr, "()"); if( saveptr != NULL ) { if( *saveptr == '(' ) ++bracketcounter; else --bracketcounter; ++saveptr; } else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } } saveptr = strpbrk(saveptr, "(,"); } while( saveptr != NULL && *saveptr == '(' ); } /* we found a ',' so the end of the first sub-constraint is determined */ if( saveptr != NULL ) { assert(*saveptr == ','); /* resize constraint array if necessary */ if( nconss == sconss ) { sconss = SCIPcalcMemGrowSize(scip, nconss+1); assert(nconss < sconss); SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); SCIPfreeBufferArray(scip, &token); if( *success ) ++nconss; else { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); goto TERMINATE; } /* skip ',' delimeter */ ++saveptr; /* remember token start position */ nexttokenstart = saveptr; saveptr = strpbrk(saveptr, "(,"); } } while( saveptr != NULL ); } /* find end of conjunction constraint */ saveptr = strrchr(nexttokenstart, ')'); if( saveptr == NULL ) { SCIPdebugMessage("error parsing conjunctive constraint: \"%s\"\n", str); *success = FALSE; goto TERMINATE; } /* parse last sub-constraint */ else { /* resize constraint array if necessary */ if( nconss == sconss ) { ++sconss; SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) ); } assert(saveptr > nexttokenstart); /* extract token for parsing */ SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) ); token[saveptr - nexttokenstart] = '\0'; SCIPdebugMessage("conjunctive parsing token(constraint): %s\n", token); /* parsing a constraint, part of the conjunction */ SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, success) ); if( *success ) ++nconss; SCIPfreeBufferArray(scip, &token); } assert(nconss > 0 || !(*success)); /* if parsing sub-constraints was fine, create the conjunctive constraint */ if( *success ) { /* create conjunctive constraint */ SCIP_CALL( SCIPcreateConsConjunction(scip, cons, name, nconss, conss, enforce, check, local, modifiable, dynamic) ); } /* free parsed constraints */ for( --nconss; nconss >= 0; --nconss ) { SCIP_CALL( SCIPreleaseCons(scip, &conss[nconss]) ); } TERMINATE: /* free temporary memory */ SCIPfreeBufferArray(scip, ©str); SCIPfreeBufferArray(scip, &conss); return SCIP_OKAY; }
/** creates and captures an indicator constraint * * @note @a binvar is checked to be binary only later. This enables a change of the type in * procedures reading an instance. * * @note the constraint gets captured, hence at one point you have to release it using the method {@link releaseCons()} */ JNIEXPORT jlong JNISCIPCONSINDICATOR(createConsIndicator)( JNIEnv* env, /**< JNI environment variable */ jobject jobj, /**< JNI class pointer */ jlong jscip, /**< SCIP data structure */ jstring jname, /**< name of constraint */ jlong jbinvar, /**< binary indicator variable (or NULL) */ jint nvars, /**< number of variables in the constraint */ jlongArray jvars, /**< array with variables of constraint entries */ jdoubleArray jvals, /**< values of variables in inequality (or NULL) */ jdouble rhs, /**< rhs of the inequality */ jboolean jinitial, /**< should the LP relaxation of constraint be in the initial LP? * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */ jboolean jseparate, /**< should the constraint be separated during LP processing? * Usually set to TRUE. */ jboolean jenforce, /**< should the constraint be enforced during node processing? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean jcheck, /**< should the constraint be checked for feasibility? * TRUE for model constraints, FALSE for additional, redundant constraints. */ jboolean jpropagate, /**< should the constraint be propagated during node processing? * Usually set to TRUE. */ jboolean jlocal, /**< is constraint only valid locally? * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */ jboolean jdynamic, /**< is constraint subject to aging? * Usually set to FALSE. Set to TRUE for own cuts which * are seperated as constraints. */ jboolean jremovable, /**< should the relaxation be removed from the LP due to aging or cleanup? * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */ jboolean jstickingatnode /**< should the constraint always be kept at the node where it was added, even * if it may be moved to a more global node? * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */ ) { SCIP* scip; SCIP_CONS* cons; const char* name; SCIP_VAR* binvar; SCIP_VAR** vars; SCIP_Real* vals; /* convert JNI pointer into C pointer */ scip = (SCIP*) (size_t) jscip; assert(scip != NULL); /* convert JNI string into C const char* */ name = (*env)->GetStringUTFChars(env, jname, NULL); if( name == NULL ) SCIPABORT(); /* convert JNI pointer into C pointer */ binvar = (SCIP_VAR*) (size_t) jbinvar; JNISCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); JNISCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) ); (*env)->GetLongArrayRegion(env, jvars, 0, nvars, (jlong*)(*vars)); (*env)->GetDoubleArrayRegion(env, jvals, 0, nvars, (jdouble*)vals); JNISCIP_CALL( SCIPcreateConsIndicator(scip, &cons, name, binvar, (int)nvars, vars, vals, (SCIP_Real)rhs, (SCIP_Bool) jinitial, (SCIP_Bool) jseparate, (SCIP_Bool) jenforce, (SCIP_Bool) jcheck, (SCIP_Bool) jpropagate, (SCIP_Bool) jlocal, (SCIP_Bool) jdynamic, (SCIP_Bool) jremovable, (SCIP_Bool) jstickingatnode) ); SCIPfreeBufferArray(scip, &vals); SCIPfreeBufferArray(scip, &vars); (*env)->ReleaseStringUTFChars(env, jname, name); return (jlong)(size_t)cons; }
/** creates a cumulative scheduling problem */ SCIP_RETCODE SCIPcreateSchedulingProblem( SCIP* scip, /**< SCIP data structure */ const char* problemname, /**< problem name */ const char** jobnames, /**< job names, or NULL */ const char** resourcenames, /**< resource names, or NULL */ int** demands, /**< demand matrix resource job demand */ SCIP_DIGRAPH* precedencegraph, /**< direct graph to store the precedence conditions */ int* durations, /**< array to store the processing for each job */ int* capacities, /**< array to store the different capacities */ int njobs, /**< number of jobs to be parsed */ int nresources /**< number of capacities to be parsed */ ) { SCIP_VAR** jobs; SCIP_VAR** vars; SCIP_VAR* var; SCIP_CONS* cons; char name[SCIP_MAXSTRLEN]; int* consdurations; int* consdemands; int nvars; int ubmakespan; int i; int j; int r; assert( scip != NULL ); assert( njobs >= 0 ); SCIPdebugMessage( "start method SCIPcreateSchedulingSMProblem\n"); /* create SCIP data structure */ SCIP_CALL( SCIPcreateProb(scip, problemname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* compute a feasible upper bound on the makespan */ ubmakespan = computeUbmakespan(durations, njobs); ubmakespan *= 100; /* allocate buffer for jobs and precedence constraints */ SCIP_CALL( SCIPallocBufferArray(scip, &jobs, njobs) ); /* create an activity constraint for each activity */ for( j = 0; j < njobs - 1; ++j ) /* but not for last job which is the makespan (-1) */ { /* construct variable name */ if( jobnames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%s", jobnames[j]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "start_%d", j); /* create integer starting variable */ SCIP_CALL( SCIPcreateVar(scip, &var, name, 0.0, (SCIP_Real)ubmakespan, 0.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[j] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); } /* create makespan variable */ SCIP_CALL( SCIPcreateVar(scip, &var, "makespan", 0.0, (SCIP_Real)ubmakespan, 1.0, SCIP_VARTYPE_INTEGER, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, var) ); SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) ); jobs[njobs-1] = var; SCIP_CALL( SCIPreleaseVar(scip, &var) ); /* precedence constraints */ for( j = 0; j < njobs - 1; ++j ) { SCIP_VAR* predvar; int nsuccessors; nsuccessors = SCIPdigraphGetNSuccessors(precedencegraph, j); predvar = jobs[j]; assert(predvar != NULL); if( nsuccessors > 0 ) { int* successors; void** distances; successors = SCIPdigraphGetSuccessors(precedencegraph, j); distances = SCIPdigraphGetSuccessorsDatas(precedencegraph, j); for( i = 0; i < nsuccessors; ++i ) { SCIP_VAR* succvar; int distance; succvar = jobs[successors[i]]; assert(succvar != NULL); (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, successors[i]); distance = (int)(size_t)distances[i]; if( distance == INT_MAX ) distance = durations[j]; SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, succvar, -1.0, -SCIPinfinity(scip), -distance, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } else { /* add precedence constraints for those jobs without successor */ (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "precedences_(%d,%d)", j, njobs); SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, predvar, jobs[njobs-1], -1.0, -SCIPinfinity(scip), -durations[j], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } SCIP_CALL( SCIPallocBufferArray(scip, &vars, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdemands, njobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &consdurations, njobs) ); /* create resource constraints */ for( r = 0; r < nresources; ++r ) { nvars = 0; for( j = 0; j < njobs; ++j ) /* also makespan constraint! */ { if( demands[j][r] > 0 ) { vars[nvars] = jobs[j]; consdemands[nvars] = demands[j][r]; consdurations[nvars] = durations[j]; nvars++; } } if( nvars > 0 ) { /* construct constraint name */ if( resourcenames != NULL ) (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%s", resourcenames[r]); else (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "R%d", r); SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, consdurations, consdemands, capacities[r], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); } } /* initialize the problem specific heuristic */ SCIP_CALL( SCIPinitializeHeurListScheduling(scip, precedencegraph, jobs, durations, demands, capacities, njobs, nresources) ); /* free buffer array */ SCIPfreeBufferArray(scip, &consdurations); SCIPfreeBufferArray(scip, &consdemands); SCIPfreeBufferArray(scip, &vars); SCIPfreeBufferArray(scip, &jobs); return SCIP_OKAY; }
/** prints given linear constraint information in PPM format to file stream */ static SCIP_RETCODE printLinearCons( 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 variables */ SCIP_Real* vals, /**< array of coefficients values (or NULL if all coefficient values are 1) */ int nvars, /**< number of variables */ int ncompletevars, /**< number of variables in whole problem */ SCIP_Bool transformed, /**< transformed constraint? */ SCIP_Real* maxcoef, /**< maximal coefficient */ SCIP_Bool printbool /**< print row or calculate maximum coefficient */ ) { int v; SCIP_VAR** activevars; SCIP_Real* activevals; int nactivevars; SCIP_Real activeconstant = 0.0; assert( scip != NULL ); assert( vars != NULL ); assert( nvars > 0 ); assert( readerdata != NULL ); /* duplicate variable and value array */ nactivevars = nvars; SCIP_CALL( SCIPduplicateBufferArray(scip, &activevars, vars, nactivevars ) ); if( vals != NULL ) { SCIP_CALL( SCIPduplicateBufferArray(scip, &activevals, vals, nactivevars ) ); } else { SCIP_CALL( SCIPallocBufferArray(scip, &activevals, nactivevars) ); for( v = 0; v < nactivevars; ++v ) activevals[v] = 1.0; } /* retransform given variables to active variables */ SCIP_CALL( getActiveVariables(scip, activevars, activevals, &nactivevars, &activeconstant, transformed) ); if(!readerdata->rgb_relativ) { if(!printbool) for(v = 0; v < nactivevars; ++v) { if( REALABS(activevals[v]) > *maxcoef) *maxcoef = REALABS(activevals[v]); } else { assert (*maxcoef > 0); /* print constraint */ printRow(scip, file, readerdata, activevars, activevals, nactivevars, ncompletevars, *maxcoef); } } else { /* print constraint */ printRow(scip, file, readerdata, activevars, activevals, nactivevars, ncompletevars, *maxcoef); } /* free buffer arrays */ SCIPfreeBufferArray(scip, &activevars); SCIPfreeBufferArray(scip, &activevals); return SCIP_OKAY; }
static SCIP_DECL_BRANCHEXECPS(branchExecpsMyfullstrong) { /*lint --e{715}*/ SCIP_PROBDATA* probdata; SCIP_VAR** cands; int ncands; SCIP_NODE* childnode_0; /* z_j = 0 */ SCIP_NODE* childnode_1; /* z_j = 1 */ /* probdata */ int p; int ndep; SCIP_VAR** var_z; /* [p] 01 variables */ /* "_" means the matrix for blas */ SCIP_Real* orig_Q_; /* [p*p] <- (X^t) X */ SCIP_Real* orig_q; /* [p] <- (X^t) y */ SCIP_Real r; int* Mdep; /* [ndep] */ int* groupX; /* [ndep*p] */ int dim; SCIP_Real RSS; /* residual sum of square */ SCIP_Real RSS_new; SCIP_Real* a; /* [dim] */ int ublb; int *Branchz; /* [3*p] */ int *Branchz_new; /* [3*p] */ SCIP_Real* Q_; /* sub matrix of orig_Q_ */ SCIP_Real* Xy; /* sub vector of orig_q */ int* list; /* list of candidate variables */ int i,j,t,memo,ct; int ind; int dpv; #if MYPARA_LOG printf("[myfullstrong brnaching]"); Longline(); #endif /* get branching rule data */ /* SCIP_BRANCHRULEDATA* branchruledata; branchruledata = SCIPbranchruleGetData(branchrule); assert(branchruledata != NULL); */ /* get problem data*/ probdata = SCIPgetProbData(scip); assert(probdata != NULL); p = SCIPprobdataGetNexvars(probdata); ndep = SCIPprobdataGetNdep(probdata); orig_Q_ = SCIPprobdataGetQ(probdata); orig_q = SCIPprobdataGetq(probdata); r = SCIPprobdataGetr(probdata); var_z = SCIPprobdataGetVars_z(probdata); if( ndep ){ Mdep = SCIPprobdataGetMdep(probdata); groupX = SCIPprobdataGetgroupX(probdata); }else{ Mdep = NULL; groupX = NULL; } /* alloc */ SCIP_CALL( SCIPallocBufferArray(scip, &list, p)); SCIP_CALL( SCIPallocBufferArray(scip, &Branchz, 3*p)); SCIP_CALL( SCIPallocBufferArray(scip, &Branchz_new, 3*p)); GenerateZeroVecInt( p, list); GenerateZeroVecInt( 3*p, Branchz); /* get pseudo candidates (non-fixed integer variables) */ SCIP_CALL( SCIPgetPseudoBranchCands(scip, &cands, NULL, &ncands) ); for(i=0; i<ncands; i++){ for(j=0; j<p; j++){ if( cands[i]==var_z[j] ){ list[j] = 1; break; } } } #if MYPARA_LOG printf("list:"); printintv( p, list); #endif /* get branching info */ for(i=0; i<p; ++i){ ublb = SCIPround(scip, SCIPcomputeVarUbLocal(scip, var_z[i]) + SCIPcomputeVarLbLocal(scip, var_z[i])); *(Branchz+(ublb*p)+i) = 1; } #if MYPARA_LOG for(i=0; i<3; i++){ for(j=0; j<p; j++){ printf("%d, ", *(Branchz+(i*p)+j)); } newline(); } #endif RSS = -1.0; ind = -1; for(i=0; i<p; i++){ /* copy */ for(j=0; j<(3*p); j++){ Branchz_new[j] = Branchz[j]; } /* * solve * Q a = Xy */ if( list[i] == 1 ){ Branchz_new[i] = 1; Branchz_new[p+i] = 0; if( ndep ){ for(t=0; t<ndep; t++){ memo = -1; for(j=0; j<p; j++){ if( *(groupX+(t*p)+j)==1 ){ if( Branchz_new[j]==1 ) break; if( Branchz_new[p+j]==1 ) memo=j; if( j==Mdep[t] ){ if( memo==-1 ){ printf("error in branch_myfullstrong.c\n"); stop(); } *(Branchz_new+p+memo) = 0; *(Branchz_new+memo) = 1; break; } } } } } dim = p - sumint( &Branchz_new[0], p); /* alloc */ SCIP_CALL( SCIPallocBufferArray( scip, &a, dim)); SCIP_CALL( SCIPallocBufferArray( scip, &Q_, dim*dim)); SCIP_CALL( SCIPallocBufferArray( scip, &Xy, dim)); /* generate Q and Xy */ /* Q */ ct = 0; for(j=0; j<p; j++){ if( (Branchz_new[j]==0) && (j != i) ){ for(t=0; t<p; t++){ if( (Branchz_new[t]==0) && (t != i ) ){ Q_[ct++] = mat_( orig_Q_, p, j, t); } } } } if( ct != (dim*dim) ){ printf("error in branch_myfullstrong.c\n"); stop(); } /* Xy */ ct = 0; for(j=0; j<p; j++){ if( (Branchz_new[j]==0) && (j != i) ){ Xy[ct++] = orig_q[j]; } } if( ct != dim ){ printf("error in branch_myfullstrong.c\n"); stop(); } dpv = _dposv_( Q_, Xy, dim, a); if( dpv == 0 ){ /* test */ RSS_new = RSSvalue( dim, a, Xy, r); if( RSS_new > RSS ){ RSS = RSS_new; ind = i; } #if MYPARA_LOG printf("%d: RSS = %f\n", i, RSS_new); #endif } /* free */ SCIPfreeBufferArray(scip, &Q_); SCIPfreeBufferArray(scip, &Xy); SCIPfreeBufferArray(scip, &a); } } #if MYPARA_LOG printf("max->%dth var. \n", ind); #endif if( ind == -1 ){ /* free */ SCIPfreeBufferArray(scip, &list); SCIPfreeBufferArray(scip, &Branchz); SCIPfreeBufferArray(scip, &Branchz_new); *result = SCIP_DIDNOTRUN; return SCIP_OKAY; } SCIP_CALL( SCIPbranchVar( scip, var_z[ind], &childnode_0, NULL, &childnode_1)); /* free */ SCIPfreeBufferArray(scip, &list); SCIPfreeBufferArray(scip, &Branchz); SCIPfreeBufferArray(scip, &Branchz_new); *result = SCIP_BRANCHED; return SCIP_OKAY; }
/** writes problem to file */ SCIP_RETCODE SCIPwritePpm( SCIP* scip, /**< SCIP data structure */ FILE* file, /**< output file, or NULL if standard output should be used */ const char* name, /**< problem name */ SCIP_READERDATA* readerdata, /**< information for reader */ SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */ int nvars, /**< number of active variables in the problem */ SCIP_CONS** conss, /**< array with constraints of the problem */ int nconss, /**< number of constraints in the problem */ SCIP_RESULT* result /**< pointer to store the result of the file writing call */ ) { /*lint --e{715}*/ int c; int v; int i; int linecnt; char linebuffer[PPM_MAX_LINELEN]; SCIP_CONSHDLR* conshdlr; const char* conshdlrname; SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_Real* consvals; int nconsvars; int i_max = 1; SCIP_Real maxcoef = 0; SCIP_Bool printbool = FALSE; assert( scip != NULL ); assert(readerdata != NULL); /* print statistics as comment to file */ if(readerdata->rgb_ascii) SCIPinfoMessage(scip, file, "P6\n"); else SCIPinfoMessage(scip, file, "P3\n"); SCIPinfoMessage(scip, file, "# %s\n", name); SCIPinfoMessage(scip, file, "%d %d\n", nvars, nconss); SCIPinfoMessage(scip, file, "255\n"); clearLine(linebuffer, &linecnt); if(!(readerdata->rgb_relativ)) { i_max = 2; } for(i = 0; i < i_max; ++i) { if(i) { printbool = TRUE; SCIPdebugPrintf("Maximal coefficient = %g\n", maxcoef); } for(c = 0; c < nconss; ++c) { cons = conss[c]; assert( cons != NULL); /* in case the transformed is written only constraint are posted which are enabled in the current node */ assert(!transformed || SCIPconsIsEnabled(cons)); conshdlr = SCIPconsGetHdlr(cons); assert( conshdlr != NULL ); conshdlrname = SCIPconshdlrGetName(conshdlr); assert( transformed == SCIPconsIsTransformed(cons) ); if( strcmp(conshdlrname, "linear") == 0 ) { consvars = SCIPgetVarsLinear(scip, cons); nconsvars = SCIPgetNVarsLinear(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( printLinearCons(scip, file, readerdata, consvars, SCIPgetValsLinear(scip, cons), nconsvars, nvars, transformed, &maxcoef, printbool) ); } } else if( strcmp(conshdlrname, "setppc") == 0 ) { consvars = SCIPgetVarsSetppc(scip, cons); nconsvars = SCIPgetNVarsSetppc(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( printLinearCons(scip, file, readerdata, consvars, NULL, nconsvars, nvars, transformed, &maxcoef, printbool) ); } } else if( strcmp(conshdlrname, "logicor") == 0 ) { consvars = SCIPgetVarsLogicor(scip, cons); nconsvars = SCIPgetNVarsLogicor(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( printLinearCons(scip, file, readerdata, consvars, NULL, nconsvars, nvars, transformed, &maxcoef, printbool) ); } } else if( strcmp(conshdlrname, "knapsack") == 0 ) { SCIP_Longint* weights; consvars = SCIPgetVarsKnapsack(scip, cons); nconsvars = SCIPgetNVarsKnapsack(scip, cons); assert( consvars != NULL || nconsvars == 0 ); /* copy Longint array to SCIP_Real array */ weights = SCIPgetWeightsKnapsack(scip, cons); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); for( v = 0; v < nconsvars; ++v ) consvals[v] = (SCIP_Real)weights[v]; if( nconsvars > 0 ) { SCIP_CALL( printLinearCons(scip, file, readerdata, consvars, consvals, nconsvars, nvars, transformed, &maxcoef, printbool) ); } SCIPfreeBufferArray(scip, &consvals); } else if( strcmp(conshdlrname, "varbound") == 0 ) { SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); consvars[0] = SCIPgetVarVarbound(scip, cons); consvars[1] = SCIPgetVbdvarVarbound(scip, cons); consvals[0] = 1.0; consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); SCIP_CALL( printLinearCons(scip, file, readerdata, consvars, consvals, 2, nvars, transformed, &maxcoef, printbool) ); SCIPfreeBufferArray(scip, &consvars); SCIPfreeBufferArray(scip, &consvals); } else { SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname ); SCIPinfoMessage(scip, file, "\\ "); SCIP_CALL( SCIPprintCons(scip, cons, file) ); SCIPinfoMessage(scip, file, ";\n"); } } } *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** arbitrary primal solution separation method of separator */ static SCIP_DECL_SEPAEXECSOL(sepaExecsolImpliedbounds) { /*lint --e{715}*/ SCIP_VAR** vars; SCIP_VAR** fracvars; SCIP_Real* solvals; SCIP_Real* fracvals; SCIP_Bool cutoff; int nvars; int nbinvars; int nfracs; int ncuts; int i; assert(sepa != NULL); assert(scip != NULL); *result = SCIP_DIDNOTRUN; /* gets active problem variables */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); if( nbinvars == 0 ) return SCIP_OKAY; /* get solution values for all variables */ SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) ); SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) ); /* get binary problem variables that are fractional in given solution */ SCIP_CALL( SCIPallocBufferArray(scip, &fracvars, nbinvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &fracvals, nbinvars) ); nfracs = 0; for( i = 0; i < nbinvars; ++i ) { if( !SCIPisFeasIntegral(scip, solvals[i]) ) { fracvars[nfracs] = vars[i]; fracvals[nfracs] = solvals[i]; nfracs++; } } /* call the cut separation */ ncuts = 0; cutoff = FALSE; if( nfracs > 0 ) { SCIP_CALL( separateCuts(scip, sepa, sol, solvals, fracvars, fracvals, nfracs, &cutoff, &ncuts) ); } /* adjust result code */ if ( cutoff ) *result = SCIP_CUTOFF; else if ( ncuts > 0 ) *result = SCIP_SEPARATED; else *result = SCIP_DIDNOTFIND; /* free temporary memory */ SCIPfreeBufferArray(scip, &fracvals); SCIPfreeBufferArray(scip, &fracvars); SCIPfreeBufferArray(scip, &solvals); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecLocalbranching) { /*lint --e{715}*/ SCIP_Longint maxnnodes; /* maximum number of subnodes */ SCIP_Longint nsubnodes; /* nodelimit for subscip */ SCIP_HEURDATA* heurdata; SCIP* subscip; /* the subproblem created by localbranching */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_SOL* bestsol; /* best solution so far */ SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */ SCIP_Real timelimit; /* timelimit for subscip (equals remaining time of scip) */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real upperbound; SCIP_Real memorylimit; SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; int nvars; int i; SCIP_Bool success; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* there should be enough binary variables that a local branching constraint makes sense */ if( SCIPgetNBinVars(scip) < 2*heurdata->neighborhoodsize ) return SCIP_OKAY; *result = SCIP_DELAYED; /* only call heuristic, if an IP solution is at hand */ if( SCIPgetNSols(scip) <= 0 ) return SCIP_OKAY; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); /* only call heuristic, if the best solution comes from transformed problem */ if( SCIPsolIsOriginal(bestsol) ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip, bestsol) < heurdata->nwaitingnodes) return SCIP_OKAY; /* only call heuristic, if the best solution does not come from trivial heuristic */ if( SCIPsolGetHeur(bestsol) != NULL && strcmp(SCIPheurGetName(SCIPsolGetHeur(bestsol)), "trivial") == 0 ) return SCIP_OKAY; /* reset neighborhood and minnodes, if new solution was found */ if( heurdata->lastsol != bestsol ) { heurdata->curneighborhoodsize = heurdata->neighborhoodsize; heurdata->curminnodes = heurdata->minnodes; heurdata->emptyneighborhoodsize = 0; heurdata->callstatus = EXECUTE; heurdata->lastsol = bestsol; } /* if no new solution was found and local branching also seems to fail, just keep on waiting */ if( heurdata->callstatus == WAITFORNEWSOL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* calculate the maximal number of branching nodes until heuristic is aborted */ maxnnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip)); /* reward local branching if it succeeded often */ maxnnodes = (SCIP_Longint)(maxnnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0))); maxnnodes -= 100 * SCIPheurGetNCalls(heur); /* count the setup costs for the sub-MIP as 100 nodes */ maxnnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nsubnodes = maxnnodes - heurdata->usednodes; nsubnodes = MIN(nsubnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call sub problem solving */ if( nsubnodes < heurdata->curminnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIPdebugMessage("running localbranching heuristic ...\n"); /* get the data of the variables and the best solution */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initializing the subproblem */ SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; eventhdlr = NULL; if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_localbranchsub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_localbranchsub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "localbranchsub", TRUE, FALSE, TRUE, &success) ); if( heurdata->copycuts ) { /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } /* create event handler for LP events */ SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecLocalbranching, NULL) ); if( eventhdlr == NULL ) { SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n"); return SCIP_PLUGINNOTFOUND; } } SCIPdebugMessage("Copying the plugins was %ssuccessful.\n", success ? "" : "not "); for (i = 0; i < nvars; ++i) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* if the subproblem could not be created, free memory and return */ if( !success ) { *result = SCIP_DIDNOTRUN; goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); #ifndef SCIP_DEBUG /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); #endif /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* set limits for the subproblem */ heurdata->nodelimit = nsubnodes; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nsubnodes) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", MAX(10, nsubnodes/10)) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", 3) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* employ a limit on the number of enforcement rounds in the quadratic constraint handler; this fixes the issue that * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no deductions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 500) ); } /* copy the original problem and add the local branching constraint */ if( heurdata->uselprows ) { SCIP_CALL( createSubproblem(scip, subscip, subvars) ); } SCIP_CALL( addLocalBranchingConstraint(scip, subscip, subvars, heurdata) ); /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff ); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); /* catch LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPtransformProb(subscip) ); SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) ); } /* solve the subproblem */ SCIPdebugMessage("solving local branching subproblem with neighborhoodsize %d and maxnodes %"SCIP_LONGINT_FORMAT"\n", heurdata->curneighborhoodsize, nsubnodes); retcode = SCIPsolve(subscip); /* drop LP events of sub-SCIP */ if( !heurdata->uselprows ) { assert(eventhdlr != NULL); SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) ); } /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in local branching heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* print solving statistics of subproblem if we are in SCIP's debug mode */ SCIPdebug( SCIP_CALL( SCIPprintStatistics(subscip, NULL) ) ); heurdata->usednodes += SCIPgetNNodes(subscip); SCIPdebugMessage("local branching used %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT" nodes\n", SCIPgetNNodes(subscip), nsubnodes); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); } if( success ) { SCIPdebugMessage("-> accepted solution of value %g\n", SCIPgetSolOrigObj(subscip, subsols[i])); *result = SCIP_FOUNDSOL; } } /* check the status of the sub-MIP */ switch( SCIPgetStatus(subscip) ) { case SCIP_STATUS_OPTIMAL: case SCIP_STATUS_BESTSOLLIMIT: heurdata->callstatus = WAITFORNEWSOL; /* new solution will immediately be installed at next call */ SCIPdebugMessage(" -> found new solution\n"); break; case SCIP_STATUS_NODELIMIT: case SCIP_STATUS_STALLNODELIMIT: case SCIP_STATUS_TOTALNODELIMIT: heurdata->callstatus = EXECUTE; heurdata->curneighborhoodsize = (heurdata->emptyneighborhoodsize + heurdata->curneighborhoodsize)/2; heurdata->curminnodes *= 2; SCIPdebugMessage(" -> node limit reached: reduced neighborhood to %d, increased minnodes to %d\n", heurdata->curneighborhoodsize, heurdata->curminnodes); if( heurdata->curneighborhoodsize <= heurdata->emptyneighborhoodsize ) { heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> new neighborhood was already proven to be empty: wait for new solution\n"); } break; case SCIP_STATUS_INFEASIBLE: case SCIP_STATUS_INFORUNBD: heurdata->emptyneighborhoodsize = heurdata->curneighborhoodsize; heurdata->curneighborhoodsize += heurdata->curneighborhoodsize/2; heurdata->curneighborhoodsize = MAX(heurdata->curneighborhoodsize, heurdata->emptyneighborhoodsize + 2); heurdata->callstatus = EXECUTE; SCIPdebugMessage(" -> neighborhood is empty: increased neighborhood to %d\n", heurdata->curneighborhoodsize); break; case SCIP_STATUS_UNKNOWN: case SCIP_STATUS_USERINTERRUPT: case SCIP_STATUS_TIMELIMIT: case SCIP_STATUS_MEMLIMIT: case SCIP_STATUS_GAPLIMIT: case SCIP_STATUS_SOLLIMIT: case SCIP_STATUS_UNBOUNDED: default: heurdata->callstatus = WAITFORNEWSOL; SCIPdebugMessage(" -> unexpected sub-MIP status <%d>: waiting for new solution\n", SCIPgetStatus(subscip)); break; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpRapidlearning) {/*lint --e{715}*/ SCIP* subscip; /* the subproblem created by rapid learning */ SCIP_SEPADATA* sepadata; /* separator's private data */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_HASHMAP* varmapbw; /* mapping of sub-SCIP variables to SCIP variables */ SCIP_CONSHDLR** conshdlrs; /* array of constraint handler's that might that might obtain conflicts */ int* oldnconss; /* number of constraints without rapid learning conflicts */ SCIP_Longint nodelimit; /* node limit for the subproblem */ SCIP_Real timelimit; /* time limit for the subproblem */ SCIP_Real memorylimit; /* memory limit for the subproblem */ int nconshdlrs; /* size of conshdlr and oldnconss array */ int nfixedvars; /* number of variables that could be fixed by rapid learning */ int nvars; /* number of variables */ int restartnum; /* maximal number of conflicts that should be created */ int i; /* counter */ SCIP_Bool success; /* was problem creation / copying constraint successful? */ SCIP_RETCODE retcode; /* used for catching sub-SCIP errors in debug mode */ int nconflicts; /* statistic: number of conflicts applied */ int nbdchgs; /* statistic: number of bound changes applied */ int n1startinfers; /* statistic: number of one side infer values */ int n2startinfers; /* statistic: number of both side infer values */ SCIP_Bool soladded; /* statistic: was a new incumbent found? */ SCIP_Bool dualboundchg; /* statistic: was a new dual bound found? */ SCIP_Bool disabledualreductions; /* TRUE, if dual reductions in sub-SCIP are not valid for original SCIP, * e.g., because a constraint could not be copied or a primal solution * could not be copied back */ int ndiscvars; soladded = FALSE; assert(sepa != NULL); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip)+SCIPgetNImplVars(scip); /* only run when still not fixed binary variables exists */ if( ndiscvars == 0 ) return SCIP_OKAY; /* get separator's data */ sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); /* only run for integer programs */ if( !sepadata->contvars && ndiscvars != SCIPgetNVars(scip) ) return SCIP_OKAY; /* only run if there are few enough continuous variables */ if( sepadata->contvars && SCIPgetNContVars(scip) > sepadata->contvarsquot * SCIPgetNVars(scip) ) return SCIP_OKAY; /* do not run if pricers are present */ if( SCIPgetNActivePricers(scip) > 0 ) return SCIP_OKAY; /* if the separator should be exclusive to the root node, this prevents multiple calls due to restarts */ if( SCIPsepaGetFreq(sepa) == 0 && SCIPsepaGetNCalls(sepa) > 0) return SCIP_OKAY; /* call separator at most once per node */ if( SCIPsepaGetNCallsAtNode(sepa) > 0 ) return SCIP_OKAY; /* do not call rapid learning, if the problem is too big */ if( SCIPgetNVars(scip) > sepadata->maxnvars || SCIPgetNConss(scip) > sepadata->maxnconss ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initializing the subproblem */ SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; /* copy the subproblem */ SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "rapid", FALSE, FALSE, &success) ); if( sepadata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, FALSE) ); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]); SCIPhashmapFree(&varmapfw); /* this avoids dual presolving */ if( !success ) { for( i = 0; i < nvars; i++ ) { SCIP_CALL( SCIPaddVarLocks(subscip, subvars[i], 1, 1 ) ); } } SCIPdebugMessage("Copying SCIP was%s successful.\n", success ? "" : " not"); /* mimic an FD solver: DFS, no LP solving, 1-FUIP instead of all-FUIP */ SCIP_CALL( SCIPsetIntParam(subscip, "lp/solvefreq", -1) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/fuiplevels", 1) ); SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/dfs/stdpriority", INT_MAX/4) ); SCIP_CALL( SCIPsetBoolParam(subscip, "constraints/disableenfops", TRUE) ); SCIP_CALL( SCIPsetIntParam(subscip, "propagating/pseudoobj/freq", -1) ); /* use inference branching */ SCIP_CALL( SCIPsetBoolParam(subscip, "branching/inference/useweightedsum", FALSE) ); /* only create short conflicts */ SCIP_CALL( SCIPsetRealParam(subscip, "conflict/maxvarsfac", 0.05) ); /* set limits for the subproblem */ nodelimit = SCIPgetNLPIterations(scip); nodelimit = MAX(sepadata->minnodes, nodelimit); nodelimit = MIN(sepadata->maxnodes, nodelimit); restartnum = 1000; /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; if( timelimit <= 0.0 || memorylimit <= 0.0 ) goto TERMINATE; SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit/5) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/restarts", 0) ); SCIP_CALL( SCIPsetIntParam(subscip, "conflict/restartnum", restartnum) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); #ifndef SCIP_DEBUG /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); #endif /* add an objective cutoff */ SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetUpperbound(scip)) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapbw, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) ); /* store reversing mapping of variables */ SCIP_CALL( SCIPtransformProb(subscip) ); for( i = 0; i < nvars; ++i) { SCIP_CALL( SCIPhashmapInsert(varmapbw, SCIPvarGetTransVar(subvars[i]), vars[i]) ); } /** allocate memory for constraints storage. Each constraint that will be created from now on will be a conflict. * Therefore, we need to remember oldnconss to get the conflicts from the FD search. */ nconshdlrs = 4; SCIP_CALL( SCIPallocBufferArray(scip, &conshdlrs, nconshdlrs) ); SCIP_CALL( SCIPallocBufferArray(scip, &oldnconss, nconshdlrs) ); /* store number of constraints before rapid learning search */ conshdlrs[0] = SCIPfindConshdlr(subscip, "bounddisjunction"); conshdlrs[1] = SCIPfindConshdlr(subscip, "setppc"); conshdlrs[2] = SCIPfindConshdlr(subscip, "linear"); conshdlrs[3] = SCIPfindConshdlr(subscip, "logicor"); /* redundant constraints might be eliminated in presolving */ SCIP_CALL( SCIPpresolve(subscip)); for( i = 0; i < nconshdlrs; ++i) { if( conshdlrs[i] != NULL ) oldnconss[i] = SCIPconshdlrGetNConss(conshdlrs[i]); } nfixedvars = SCIPgetNFixedVars(scip); /* solve the subproblem */ retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } /* abort solving, if limit of applied conflicts is reached */ if( SCIPgetNConflictConssApplied(subscip) >= restartnum ) { SCIPdebugMessage("finish after %lld successful conflict calls.\n", SCIPgetNConflictConssApplied(subscip)); } /* if the first 20% of the solution process were successful, proceed */ else if( (sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPisFeasLT(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) || (sepadata->applybdchgs && SCIPgetNFixedVars(subscip) > nfixedvars) || (sepadata->applyconflicts && SCIPgetNConflictConssApplied(subscip) > 0) ) { SCIPdebugMessage("proceed solving after the first 20%% of the solution process, since:\n"); if( SCIPgetNSols(subscip) > 0 && SCIPisFeasLE(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) ) { SCIPdebugMessage(" - there was a better solution (%f < %f)\n",SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip)); } if( SCIPgetNFixedVars(subscip) > nfixedvars ) { SCIPdebugMessage(" - there were %d variables fixed\n", SCIPgetNFixedVars(scip)-nfixedvars ); } if( SCIPgetNConflictConssFound(subscip) > 0 ) { SCIPdebugMessage(" - there were %lld conflict constraints created\n", SCIPgetNConflictConssApplied(subscip)); } /* set node limit to 100% */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit) ); /* solve the subproblem */ retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage("Error while solving subproblem in rapid learning separator; sub-SCIP terminated with code <%d>\n",retcode); } } else { SCIPdebugMessage("do not proceed solving after the first 20%% of the solution process.\n"); } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif disabledualreductions = FALSE; /* check, whether a solution was found */ if( sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPfindHeur(scip, "trysol") != NULL ) { SCIP_HEUR* heurtrysol; SCIP_SOL** subsols; int nsubsols; /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until was declared to be feasible */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); soladded = FALSE; heurtrysol = SCIPfindHeur(scip, "trysol"); /* sequentially add solutions to trysol heuristic */ for( i = 0; i < nsubsols && !soladded; ++i ) { SCIPdebugMessage("Try to create new solution by copying subscip solution.\n"); SCIP_CALL( createNewSol(scip, subscip, subvars, heurtrysol, subsols[i], &soladded) ); } if( !soladded || !SCIPisEQ(scip, SCIPgetSolOrigObj(subscip, subsols[i-1]), SCIPgetSolOrigObj(subscip, subsols[0])) ) disabledualreductions = TRUE; } /* if the sub problem was solved completely, we update the dual bound */ dualboundchg = FALSE; if( sepadata->applysolved && !disabledualreductions && (SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL || SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE) ) { /* we need to multiply the dualbound with the scaling factor and add the offset, * because this information has been disregarded in the sub-SCIP */ SCIPdebugMessage("Update old dualbound %g to new dualbound %g.\n", SCIPgetDualbound(scip), SCIPgetTransObjscale(scip) * SCIPgetDualbound(subscip) + SCIPgetTransObjoffset(scip)); SCIP_CALL( SCIPupdateLocalDualbound(scip, SCIPgetDualbound(subscip) * SCIPgetTransObjscale(scip) + SCIPgetTransObjoffset(scip)) ); dualboundchg = TRUE; } /* check, whether conflicts were created */ nconflicts = 0; if( sepadata->applyconflicts && !disabledualreductions && SCIPgetNConflictConssApplied(subscip) > 0 ) { SCIP_HASHMAP* consmap; int hashtablesize; assert(SCIPgetNConflictConssApplied(subscip) < (SCIP_Longint) INT_MAX); hashtablesize = (int) SCIPgetNConflictConssApplied(subscip); assert(hashtablesize < INT_MAX/5); hashtablesize *= 5; /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), SCIPcalcHashtableSize(hashtablesize)) ); /* loop over all constraint handlers that might contain conflict constraints */ for( i = 0; i < nconshdlrs; ++i) { /* copy constraints that have been created in FD run */ if( conshdlrs[i] != NULL && SCIPconshdlrGetNConss(conshdlrs[i]) > oldnconss[i] ) { SCIP_CONS** conss; int c; int nconss; nconss = SCIPconshdlrGetNConss(conshdlrs[i]); conss = SCIPconshdlrGetConss(conshdlrs[i]); /* loop over all constraints that have been added in sub-SCIP run, these are the conflicts */ for( c = oldnconss[i]; c < nconss; ++c) { SCIP_CONS* cons; SCIP_CONS* conscopy; cons = conss[c]; assert(cons != NULL); success = FALSE; SCIP_CALL( SCIPgetConsCopy(subscip, scip, cons, &conscopy, conshdlrs[i], varmapbw, consmap, NULL, SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), TRUE, FALSE, SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), FALSE, TRUE, &success) ); if( success ) { nconflicts++; SCIP_CALL( SCIPaddCons(scip, conscopy) ); SCIP_CALL( SCIPreleaseCons(scip, &conscopy) ); } else { SCIPdebugMessage("failed to copy conflict constraint %s back to original SCIP\n", SCIPconsGetName(cons)); } } } } SCIPhashmapFree(&consmap); } /* check, whether tighter global bounds were detected */ nbdchgs = 0; if( sepadata->applybdchgs && !disabledualreductions ) for( i = 0; i < nvars; ++i ) { SCIP_Bool infeasible; SCIP_Bool tightened; assert(SCIPisLE(scip, SCIPvarGetLbGlobal(vars[i]), SCIPvarGetLbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetLbGlobal(subvars[i]), SCIPvarGetUbGlobal(subvars[i]))); assert(SCIPisLE(scip, SCIPvarGetUbGlobal(subvars[i]), SCIPvarGetUbGlobal(vars[i]))); /* update the bounds of the original SCIP, if a better bound was proven in the sub-SCIP */ SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; SCIP_CALL( SCIPtightenVarLb(scip, vars[i], SCIPvarGetLbGlobal(subvars[i]), FALSE, &infeasible, &tightened) ); if( tightened ) nbdchgs++; } n1startinfers = 0; n2startinfers = 0; /* install start values for inference branching */ if( sepadata->applyinfervals && (!sepadata->reducedinfer || soladded || nbdchgs+nconflicts > 0) ) { for( i = 0; i < nvars; ++i ) { SCIP_Real downinfer; SCIP_Real upinfer; SCIP_Real downvsids; SCIP_Real upvsids; SCIP_Real downconflen; SCIP_Real upconflen; /* copy downwards branching statistics */ downvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); downinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS); /* copy upwards branching statistics */ upvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); upinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS); /* memorize statistics */ if( downinfer+downconflen+downvsids > 0.0 || upinfer+upconflen+upvsids != 0 ) n1startinfers++; if( downinfer+downconflen+downvsids > 0.0 && upinfer+upconflen+upvsids != 0 ) n2startinfers++; SCIP_CALL( SCIPinitVarBranchStats(scip, vars[i], 0.0, 0.0, downvsids, upvsids, downconflen, upconflen, downinfer, upinfer, 0.0, 0.0) ); } } SCIPdebugPrintf("XXX Rapidlearning added %d conflicts, changed %d bounds, %s primal solution, %s dual bound improvement.\n", nconflicts, nbdchgs, soladded ? "found" : "no", dualboundchg ? "found" : "no"); SCIPdebugPrintf("YYY Infervalues initialized on one side: %5.2f %% of variables, %5.2f %% on both sides\n", 100.0 * n1startinfers/(SCIP_Real)nvars, 100.0 * n2startinfers/(SCIP_Real)nvars); /* change result pointer */ if( nconflicts > 0 || dualboundchg ) *result = SCIP_CONSADDED; else if( nbdchgs > 0 ) *result = SCIP_REDUCEDDOM; /* free local data */ SCIPfreeBufferArray(scip, &oldnconss); SCIPfreeBufferArray(scip, &conshdlrs); SCIPhashmapFree(&varmapbw); TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** writes problem to file */ SCIP_RETCODE SCIPwriteCcg( SCIP* scip, /**< SCIP data structure */ FILE* file, /**< output file, or NULL if standard output should be used */ const char* name, /**< problem name */ SCIP_Bool transformed, /**< TRUE iff problem is the transformed problem */ SCIP_VAR** vars, /**< array with active variables ordered binary, integer, implicit, continuous */ int nvars, /**< number of active variables in the problem */ SCIP_CONS** conss, /**< array with constraints of the problem */ int nconss, /**< number of constraints in the problem */ SCIP_RESULT* result /**< pointer to store the result of the file writing call */ ) { /*lint --e{715}*/ int c; int v; int i; SCIP_CONSHDLR* conshdlr; const char* conshdlrname; SCIP_CONS* cons; SCIP_VAR** consvars; SCIP_Real* consvals; int nconsvars; SparseGraph G; assert( scip != NULL ); assert( nvars >= 0 ); /* initialize graph */ SCIP_CALL( initGraph(scip, &G, (unsigned int) nvars, 10) ); /* check all constraints */ for( c = 0; c < nconss; ++c) { cons = conss[c]; assert( cons != NULL); /* in case the transformed is written only constraint are posted which are enabled in the current node */ assert(!transformed || SCIPconsIsEnabled(cons)); conshdlr = SCIPconsGetHdlr(cons); assert( conshdlr != NULL ); conshdlrname = SCIPconshdlrGetName(conshdlr); assert( transformed == SCIPconsIsTransformed(cons) ); if( strcmp(conshdlrname, "linear") == 0 ) { consvars = SCIPgetVarsLinear(scip, cons); nconsvars = SCIPgetNVarsLinear(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( handleLinearCons(scip, SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons), SCIPgetNVarsLinear(scip, cons), transformed, &G) ); } } else if( strcmp(conshdlrname, "setppc") == 0 ) { consvars = SCIPgetVarsSetppc(scip, cons); nconsvars = SCIPgetNVarsSetppc(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( handleLinearCons(scip, consvars, NULL, nconsvars, transformed, &G) ); } } else if( strcmp(conshdlrname, "logicor") == 0 ) { consvars = SCIPgetVarsLogicor(scip, cons); nconsvars = SCIPgetNVarsLogicor(scip, cons); assert( consvars != NULL || nconsvars == 0 ); if( nconsvars > 0 ) { SCIP_CALL( handleLinearCons(scip, SCIPgetVarsLogicor(scip, cons), NULL, SCIPgetNVarsLogicor(scip, cons), transformed, &G) ); } } else if( strcmp(conshdlrname, "knapsack") == 0 ) { SCIP_Longint* w; consvars = SCIPgetVarsKnapsack(scip, cons); nconsvars = SCIPgetNVarsKnapsack(scip, cons); assert( consvars != NULL || nconsvars == 0 ); /* copy Longint array to SCIP_Real array */ w = SCIPgetWeightsKnapsack(scip, cons); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) ); for( v = 0; v < nconsvars; ++v ) consvals[v] = (SCIP_Real)w[v]; if( nconsvars > 0 ) { SCIP_CALL( handleLinearCons(scip, consvars, consvals, nconsvars, transformed, &G) ); } SCIPfreeBufferArray(scip, &consvals); } else if( strcmp(conshdlrname, "varbound") == 0 ) { SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 2) ); SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 2) ); consvars[0] = SCIPgetVarVarbound(scip, cons); consvars[1] = SCIPgetVbdvarVarbound(scip, cons); consvals[0] = 1.0; consvals[1] = SCIPgetVbdcoefVarbound(scip, cons); SCIP_CALL( handleLinearCons(scip, consvars, consvals, 2, transformed, &G) ); SCIPfreeBufferArray(scip, &consvars); SCIPfreeBufferArray(scip, &consvals); } else { SCIPwarningMessage(scip, "constraint handler <%s> cannot print requested format\n", conshdlrname ); SCIPinfoMessage(scip, file, "\\ "); SCIP_CALL( SCIPprintCons(scip, cons, file) ); SCIPinfoMessage(scip, file, ";\n"); } } /* output graph */ SCIPinfoMessage(scip, file, "c graph generated from %s\n", name); SCIPinfoMessage(scip, file, "p edge %d %d\n", nvars, G.m); for( i = 0; i < nvars; ++i ) { unsigned int k; int a; k = 0; a = G.A[i][k]; while( a >= 0 ) { /* only output edges from lower to higher number */ if( i < a ) { /* note: node numbers start with 1 in the DIMACS format */ SCIPinfoMessage(scip, file, "e %d %d %f\n", i+1, a+1, G.W[i][k]); } a = G.A[i][++k]; assert( k <= G.size[i] ); } assert( k == G.deg[i] ); } freeGraph(scip, &G); *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** problem reading method of reader */ static SCIP_DECL_READERREAD(readerReadBpa) { /*lint --e{715}*/ SCIP_FILE* file; SCIP_Longint* weights; int* ids; SCIP_Bool error; char name[SCIP_MAXSTRLEN]; char format[16]; char buffer[SCIP_MAXSTRLEN]; int capacity; int nitems; int bestsolvalue; int nread; int weight; int nweights; int lineno; *result = SCIP_DIDNOTRUN; /* open file */ file = SCIPfopen(filename, "r"); if( file == NULL ) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); SCIPprintSysError(filename); return SCIP_NOFILE; } lineno = 0; sprintf(name, "++ uninitialized ++"); /* read problem name */ if( !SCIPfeof(file) ) { /* get next line */ if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL ) return SCIP_READERROR; lineno++; /* parse dimension line */ sprintf(format, "%%%ds\n", SCIP_MAXSTRLEN); nread = sscanf(buffer, format, name); if( nread == 0 ) { SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer); return SCIP_READERROR; } SCIPdebugMessage("problem name <%s>\n", name); } capacity = 0; nitems = 0; /* read problem dimension */ if( !SCIPfeof(file) ) { /* get next line */ if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL ) return SCIP_READERROR; lineno++; /* parse dimension line */ nread = sscanf(buffer, "%d %d %d\n", &capacity, &nitems, &bestsolvalue); if( nread < 2 ) { SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer); return SCIP_READERROR; } SCIPdebugMessage("capacity = <%d>, number of items = <%d>, best known solution = <%d>\n", capacity, nitems, bestsolvalue); } /* allocate buffer memory for storing the weights and ids temporary */ SCIP_CALL( SCIPallocBufferArray(scip, &weights, nitems) ); SCIP_CALL( SCIPallocBufferArray(scip, &ids, nitems) ); /* pasre weights */ nweights = 0; error = FALSE; while( !SCIPfeof(file) && !error ) { /* get next line */ if( SCIPfgets(buffer, (int)sizeof(buffer), file) == NULL ) break; lineno++; /* parse the line */ nread = sscanf(buffer, "%d\n", &weight); if( nread == 0 ) { SCIPwarningMessage(scip, "invalid input line %d in file <%s>: <%s>\n", lineno, filename, buffer); error = TRUE; break; } SCIPdebugMessage("found weight %d <%d>\n", nweights, weight); weights[nweights] = weight; ids[nweights] = nweights; nweights++; if( nweights == nitems ) break; } if( nweights < nitems ) { SCIPwarningMessage(scip, "set nitems from <%d> to <%d> since the file <%s> only contains <%d> weights\n", nitems, weights, filename, weights); nitems = nweights; } if( !error ) { /* create a new problem in SCIP */ SCIP_CALL( SCIPprobdataCreate(scip, name, ids, weights, nitems, (SCIP_Longint)capacity) ); } (void)SCIPfclose(file); SCIPfreeBufferArray(scip, &ids); SCIPfreeBufferArray(scip, &weights); if( error ) return SCIP_READERROR; *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** main procedure of the RENS heuristic, creates and solves a subMIP */ SCIP_RETCODE SCIPapplyGcgrens( SCIP* scip, /**< original SCIP data structure */ SCIP_HEUR* heur, /**< heuristic data structure */ SCIP_RESULT* result, /**< result data structure */ SCIP_Real minfixingrate, /**< minimum percentage of integer variables that have to be fixed */ SCIP_Real minimprove, /**< factor by which RENS should at least improve the incumbent */ SCIP_Longint maxnodes, /**< maximum number of nodes for the subproblem */ SCIP_Longint nstallnodes, /**< number of stalling nodes for the subproblem */ 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* subscip; /* the subproblem created by RENS */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real timelimit; SCIP_Real memorylimit; int nvars; int i; SCIP_Bool success; SCIP_RETCODE retcode; assert(scip != NULL); assert(heur != NULL); assert(result != NULL); assert(maxnodes >= 0); assert(nstallnodes >= 0); assert(0.0 <= minfixingrate && minfixingrate <= 1.0); assert(0.0 <= minimprove && minimprove <= 1.0); SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initialize the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); if( uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_gcgrenssub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_gcgrenssub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_Bool valid; SCIP_HEURDATA* heurdata; valid = FALSE; SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "gcgrens", TRUE, FALSE, TRUE, &valid) ); /** @todo check for thread safeness */ /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); if( heurdata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } SCIPdebugMessage("Copying the SCIP instance was %s complete.\n", valid ? "" : "not "); } for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); /* create a new problem, which fixes variables with same value in bestsol and LP relaxation */ SCIP_CALL( createSubproblem(scip, subscip, subvars, minfixingrate, binarybounds, uselprows, &success) ); SCIPdebugMessage("RENS subproblem: %d vars, %d cons, success=%u\n", SCIPgetNVars(subscip), SCIPgetNConss(subscip), success); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* check whether there is enough time and memory left */ timelimit = 0.0; memorylimit = 0.0; SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; if( timelimit <= 0.0 || memorylimit <= 0.0 ) goto TERMINATE; /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", nstallnodes) ); SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving sub-SCIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(scip, "estimate") != NULL ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(scip, "inference") != NULL ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); #ifdef SCIP_DEBUG /* for debugging RENS, enable MIP output */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) ); #endif /* if the subproblem could not be created, free memory and return */ if( !success ) { *result = SCIP_DIDNOTRUN; SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; } /* if there is already a solution, add an objective cutoff */ if( SCIPgetNSols(scip) > 0 ) { SCIP_Real upperbound; assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-minimprove)*SCIPgetUpperbound(scip) + minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); } /* presolve the subproblem */ retcode = SCIPpresolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while presolving subproblem in GCG RENS heuristic; sub-SCIP terminated with code <%d>\n",retcode); } SCIPdebugMessage("GCG RENS presolved subproblem: %d vars, %d cons, success=%u\n", SCIPgetNVars(subscip), SCIPgetNConss(subscip), success); /* after presolving, we should have at least reached a certain fixing rate over ALL variables (including continuous) * to ensure that not only the MIP but also the LP relaxation is easy enough */ if( ( nvars - SCIPgetNVars(subscip) ) / (SCIP_Real)nvars >= minfixingrate / 2.0 ) { SCIP_SOL** subsols; int nsubsols; /* solve the subproblem */ SCIPdebugMessage("solving subproblem: nstallnodes=%"SCIP_LONGINT_FORMAT", maxnodes=%"SCIP_LONGINT_FORMAT"\n", nstallnodes, maxnodes); retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in GCG RENS heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); } if( success ) *result = SCIP_FOUNDSOL; } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecCrossover) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; /* primal heuristic data */ SCIP* subscip; /* the subproblem created by crossover */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_SOL** sols; SCIP_Real memorylimit; /* memory limit for the subproblem */ SCIP_Real timelimit; /* time limit for the subproblem */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real upperbound; SCIP_Bool success; SCIP_Longint nstallnodes; /* node limit for the subproblem */ int* selection; /* pool of solutions crossover uses */ int nvars; /* number of original problem's variables */ int nbinvars; int nintvars; int nusedsols; int i; SCIP_RETCODE retcode; assert(heur != NULL); assert(scip != NULL); assert(result != NULL); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); nusedsols = heurdata->nusedsols; *result = SCIP_DELAYED; /* only call heuristic, if enough solutions are at hand */ if( SCIPgetNSols(scip) < nusedsols ) return SCIP_OKAY; sols = SCIPgetSols(scip); assert(sols != NULL); /* if one good solution was found, heuristic should not be delayed any longer */ if( sols[nusedsols-1] != heurdata->prevlastsol ) { heurdata->nextnodenumber = SCIPgetNNodes(scip); if( sols[0] != heurdata->prevbestsol ) heurdata->nfailures = 0; } /* in nonrandomized mode: only recall heuristic, if at least one new good solution was found in the meantime */ else if( !heurdata->randomization ) return SCIP_OKAY; /* if heuristic should be delayed, wait until certain number of nodes is reached */ if( SCIPgetNNodes(scip) < heurdata->nextnodenumber ) return SCIP_OKAY; /* only call heuristic, if enough nodes were processed since last incumbent */ if( SCIPgetNNodes(scip) - SCIPgetSolNodenum(scip,SCIPgetBestSol(scip)) < heurdata->nwaitingnodes && (SCIPgetDepth(scip) > 0 || !heurdata->dontwaitatroot) ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; /* calculate the maximal number of branching nodes until heuristic is aborted */ nstallnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip)); /* reward Crossover if it succeeded often */ nstallnodes = (SCIP_Longint) (nstallnodes * (1.0 + 2.0*(SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur)+1.0))); /* count the setup costs for the sub-MIP as 100 nodes */ nstallnodes -= 100 * SCIPheurGetNCalls(heur); nstallnodes += heurdata->nodesofs; /* determine the node limit for the current process */ nstallnodes -= heurdata->usednodes; nstallnodes = MIN(nstallnodes, heurdata->maxnodes); /* check whether we have enough nodes left to call subproblem solving */ if( nstallnodes < heurdata->minnodes ) return SCIP_OKAY; if( SCIPisStopped(scip) ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) ); assert(nvars > 0); /* check whether discrete variables are available */ if( nbinvars == 0 && nintvars == 0 ) return SCIP_OKAY; /* initializing the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); success = FALSE; if( heurdata->uselprows ) { char probname[SCIP_MAXSTRLEN]; /* copy all plugins */ SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* get name of the original problem and add the string "_crossoversub" */ (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_crossoversub", SCIPgetProbName(scip)); /* create the subproblem */ SCIP_CALL( SCIPcreateProb(subscip, probname, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* copy all variables */ SCIP_CALL( SCIPcopyVars(scip, subscip, varmapfw, NULL, TRUE) ); } else { SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "crossover", TRUE, FALSE, TRUE, &success) ); if( heurdata->copycuts ) { /** copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */ SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, TRUE, NULL) ); } } SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &selection, nusedsols) ); for( i = 0; i < nvars; i++ ) subvars[i] = (SCIP_VAR*) (size_t) SCIPhashmapGetImage(varmapfw, vars[i]); /* free hash map */ SCIPhashmapFree(&varmapfw); success = FALSE; /* create a new problem, which fixes variables with same value in a certain set of solutions */ SCIP_CALL( setupSubproblem(scip, subscip, subvars, selection, heurdata, &success) ); heurdata->prevbestsol = SCIPgetBestSol(scip); heurdata->prevlastsol = sols[heurdata->nusedsols-1]; /* if creation of sub-SCIP was aborted (e.g. due to number of fixings), free sub-SCIP and abort */ if( !success ) { *result = SCIP_DIDNOTRUN; /* this run will be counted as a failure since no new solution tuple could be generated or the neighborhood of the * solution was not fruitful in the sense that it was too big */ updateFailureStatistic(scip, heurdata); goto TERMINATE; } /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* check whether there is enough time and memory left */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) goto TERMINATE; /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nstallnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); /* forbid recursive call of heuristics and separators solving subMIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); /* use best estimate node selection */ if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) ); } /* disable conflict analysis */ if( !SCIPisParamFixed(subscip, "conflict/useprop") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useprop", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useinflp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useinflp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/useboundlp") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/useboundlp", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usesb") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usesb", FALSE) ); } if( !SCIPisParamFixed(subscip, "conflict/usepseudo") ) { SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/usepseudo", FALSE) ); } /* add an objective cutoff */ cutoff = SCIPinfinity(scip); assert(!SCIPisInfinity(scip, SCIPgetUpperbound(scip))); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-heurdata->minimprove)*SCIPgetUpperbound(scip) + heurdata->minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound ( scip ) >= 0 ) cutoff = ( 1 - heurdata->minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + heurdata->minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff ); SCIP_CALL( SCIPsetObjlimit(subscip, cutoff) ); /* permute the subproblem to increase diversification */ if( heurdata->permute ) { SCIP_CALL( SCIPpermuteProb(subscip, (unsigned int) SCIPheurGetNCalls(heur), TRUE, TRUE, TRUE, TRUE, TRUE) ); } /* solve the subproblem */ SCIPdebugMessage("Solve Crossover subMIP\n"); retcode = SCIPsolve(subscip); /* Errors in solving the subproblem should not kill the overall solving process. * Hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in Crossover heuristic; sub-SCIP terminated with code <%d>\n", retcode); } heurdata->usednodes += SCIPgetNNodes(subscip); /* check, whether a solution was found */ if( SCIPgetNSols(subscip) > 0 ) { SCIP_SOL** subsols; int nsubsols; int solindex; /* index of the solution created by crossover */ /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; solindex = -1; for( i = 0; i < nsubsols && !success; ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &solindex, &success) ); } if( success ) { int tmp; assert(solindex != -1); *result = SCIP_FOUNDSOL; /* insert all crossings of the new solution and (nusedsols-1) of its parents into the hashtable * in order to avoid incest ;) */ for( i = 0; i < nusedsols; i++ ) { SOLTUPLE* elem; tmp = selection[i]; selection[i] = solindex; SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) ); SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) ); selection[i] = tmp; } /* if solution was among the best ones, crossover should not be called until another good solution was found */ if( !heurdata->randomization ) { heurdata->prevbestsol = SCIPgetBestSol(scip); heurdata->prevlastsol = SCIPgetSols(scip)[heurdata->nusedsols-1]; } } /* if solution is not better then incumbent or could not be added to problem => run is counted as a failure */ if( !success || solindex != SCIPsolGetIndex(SCIPgetBestSol(scip)) ) updateFailureStatistic(scip, heurdata); } else { /* if no new solution was found, run was a failure */ updateFailureStatistic(scip, heurdata); } TERMINATE: /* free subproblem */ SCIPfreeBufferArray(scip, &selection); SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** avoid to generate columns which are fixed to zero; therefore add for each variable which is fixed to zero a * corresponding logicor constraint to forbid this column * * @note variable which are fixed locally to zero should not be generated again by the pricing MIP */ static SCIP_RETCODE addFixedVarsConss( SCIP* scip, /**< SCIP data structure */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars, /**< variable array of the subscuip */ SCIP_CONS** conss, /**< array of setppc constraint for each item one */ int nitems /**< number of items */ ) { SCIP_VAR** origvars; int norigvars; SCIP_CONS* cons; int* consids; int nconsids; int consid; int nvars; SCIP_VAR** logicorvars; SCIP_VAR* var; SCIP_VARDATA* vardata; SCIP_Bool needed; int nlogicorvars; int v; int c; int o; /* collect all variable which are currently existing */ origvars = SCIPgetVars(scip); norigvars = SCIPgetNVars(scip); /* loop over all these variables and check if they are fixed to zero */ for( v = 0; v < norigvars; ++v ) { assert(SCIPvarGetType(origvars[v]) == SCIP_VARTYPE_BINARY); /* if the upper bound is smaller than 0.5 if follows due to the integrality that the binary variable is fixed to zero */ if( SCIPvarGetUbLocal(origvars[v]) < 0.5 ) { SCIPdebugMessage("variable <%s> glb=[%.15g,%.15g] loc=[%.15g,%.15g] is fixed to zero\n", SCIPvarGetName(origvars[v]), SCIPvarGetLbGlobal(origvars[v]), SCIPvarGetUbGlobal(origvars[v]), SCIPvarGetLbLocal(origvars[v]), SCIPvarGetUbLocal(origvars[v]) ); /* coolect the constraints/items the variable belongs to */ vardata = SCIPvarGetData(origvars[v]); nconsids = SCIPvardataGetNConsids(vardata); consids = SCIPvardataGetConsids(vardata); needed = TRUE; SCIP_CALL( SCIPallocBufferArray(subscip, &logicorvars, nitems) ); nlogicorvars = 0; consid = consids[0]; nvars = 0; /* loop over these items and create a linear (logicor) constraint which forbids this item combination in the * pricing problem; thereby check if this item combination is already forbidden */ for( c = 0, o = 0; o < nitems && needed; ++o ) { assert(o <= consid); cons = conss[o]; if( SCIPconsIsEnabled(cons) ) { assert( SCIPgetNFixedonesSetppc(scip, cons) == 0 ); var = vars[nvars]; nvars++; assert(var != NULL); if( o == consid ) { SCIP_CALL( SCIPgetNegatedVar(subscip, var, &var) ); } logicorvars[nlogicorvars] = var; nlogicorvars++; } else if( o == consid ) needed = FALSE; if( o == consid ) { c++; if ( c == nconsids ) consid = nitems + 100; else { assert(consid < consids[c]); consid = consids[c]; } } } if( needed ) { SCIP_CALL( SCIPcreateConsBasicLogicor(subscip, &cons, SCIPvarGetName(origvars[v]), nlogicorvars, logicorvars) ); SCIP_CALL( SCIPsetConsInitial(subscip, cons, FALSE) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); } SCIPfreeBufferArray(subscip, &logicorvars); } } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecForward) { /*lint --e{715}*/ SCIP_PROBDATA* probdata; int n; int p; int ndep; /* "_" means the matrix for blas */ SCIP_Real* y; /* [n] */ SCIP_Real* orig_X_; /* [n*p] */ SCIP_Real* orig_Q_; /* [p*p] <- (X^t) X */ SCIP_Real* orig_q; /* [p] <- (X^t) y */ SCIP_Real r; int* Mdep; /* [ndep] */ int* groupX; /* [ndep*p] */ /* for forward selection */ int dim; int* list; /* [p] */ SCIP_Real* a; /* [dim] */ SCIP_Real* a_old; /* [dim-1] */ SCIP_Real* a_new; /* [dim] */ SCIP_Real RSS; /* residual sum of square */ SCIP_Real RSS_new; SCIP_Real AIC; SCIP_Real AIC_new; int ublb; int *Branchz; /* [3*p] */ /* * X: sub matrix of orig_X_ * Y: (X^t X)^-1 * X_new = (X, x_i); * Z: (X_new ^t X_new)^-1 * = ( V v v^t u ) */ SCIP_Real* Xy; /* sub vector of orig_q */ SCIP_Real* X_; SCIP_Real* Y_; /* [(dim-1)*(dim-1)] */ SCIP_Real* Z_; /* [dim*dim] */ SCIP_Real* W_; /* [dim*dim] */ SCIP_Real* V_; /* [(dim-1)*(dim-1)] */ SCIP_Real* v; /* [dim-1] */ SCIP_Real u; SCIP_Real* b; /* [dim-1] */ SCIP_Real* c; /* [dim-1] */ SCIP_Real* d; /* [n] */ /* variables */ SCIP_VAR** var_a; /* [p] continuous variables */ SCIP_VAR** var_z; /* [p] 01 variables */ SCIP_VAR** var_ep; /* [n] continuous variables */ SCIP_VAR* var_rss; /* continuous variable, residual sum of squares */ SCIP_VAR* var_log; /* continuous variable, log(rss) */ /* set solution */ SCIP_Real *ep; int nsols; int store; SCIP_SOL** sols; SCIP_Real objval; SCIP_SOL* sol; SCIP_Real* solvals; SCIP_Bool success; int nvars = SCIPgetNVars(scip); SCIP_VAR** vars; int i,j,t,ct; int memo; assert(heur != NULL); assert(scip != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); #if MYPARA_LOG printf("forward selection!\n"); #endif /* get heuristic data */ /* SCIP_HEURDATA* heurdata; heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); assert(lastsolindices != NULL); */ /* get values from probdata */ probdata = SCIPgetProbData(scip); assert(probdata != NULL); n = SCIPprobdataGetNdatas(probdata); p = SCIPprobdataGetNexvars(probdata); ndep = SCIPprobdataGetNdep(probdata); y = SCIPprobdataGety(probdata); orig_X_ = SCIPprobdataGetX(probdata); orig_Q_ = SCIPprobdataGetQ(probdata); orig_q = SCIPprobdataGetq(probdata); r = SCIPprobdataGetr(probdata); if( ndep ){ Mdep = SCIPprobdataGetMdep(probdata); groupX = SCIPprobdataGetgroupX(probdata); }else{ Mdep = NULL; groupX = NULL; } /* variables */ var_a = SCIPprobdataGetVars_a(probdata); var_z = SCIPprobdataGetVars_z(probdata); var_ep = SCIPprobdataGetVars_ep(probdata); var_rss = SCIPprobdataGetVar_rss(probdata); var_log = SCIPprobdataGetVar_log(probdata); /* get branching info */ /* alloc */ SCIP_CALL( SCIPallocBufferArray(scip, &Branchz, 3*p)); GenerateZeroVecInt( 3*p, Branchz); for(i=0; i<p; ++i){ ublb = SCIPround(scip, SCIPcomputeVarUbLocal(scip, var_z[i]) + SCIPcomputeVarLbLocal(scip, var_z[i])); *(Branchz+(ublb*p)+i) = 1; } #if MYPARA_LOG for(i=0; i<3; i++){ for(j=0; j<p; j++){ printf("%d, ", *(Branchz+(i*p)+j)); } newline(); } #endif if( ndep ){ for(i=0; i<ndep; i++){ memo = -1; for(j=0; j<p; j++){ if( *(groupX+(i*p)+j)==1 ){ if( *(Branchz+j)==1 ) break; if( *(Branchz+p+j)==1 ) memo=j; if( j==Mdep[i] ){ if( memo==-1 ){ printf("error in heur_backward.c\n"); stop(); } *(Branchz+p+memo) = 0; *(Branchz+memo) = 1; break; } } } } } #if MYPARA_LOG printf("linear dependent\n"); if( ndep ){ for(i=0; i<3; i++){ for(j=0; j<p; j++){ printf("%d, ", *(Branchz+(i*p)+j)); } newline(); } } #endif /* alloc */ SCIP_CALL( SCIPallocBufferArray(scip, &X_, n*p)); SCIP_CALL( SCIPallocBufferArray(scip, &Xy, p)); SCIP_CALL( SCIPallocBufferArray(scip, &d, n)); SCIP_CALL( SCIPallocBufferArray(scip, &list, p)); /* initialize from Branchz */ #if MYPARA_LOG printf("initialization\n"); #endif GenerateZeroVecInt( p, list); dim = 0; memo = -1; AIC = 1e+06; SCIP_CALL( SCIPallocBufferArray(scip, &a_old, dim+1)); for(i=0; i<p; i++){ if( Branchz[i]==1 ){ /* if z_i is fixed to 0 */ list[i] = -1; }else if( Branchz[p+i]==1 ){ /* if z_i is unfixed */ list[i] = 0; }else if( Branchz[2*p+i]==1 ){ /* if z_i is fixed 1 */ dim++; list[i] = dim; if( dim == 1 ){ a_old[0] = orig_q[i] / mat_( orig_Q_, p, i, i); RSS = RSSvalue( 1, a_old, &orig_q[i], r); AIC = AICvalue( n, dim, RSS); /* update X_ and Xy */ mydcopy_( &orig_X_[n * i], &X_[n * (dim-1)], n); Xy[dim-1] = orig_q[i]; /* generate Y ( dim = 1 ) */ SCIP_CALL( SCIPallocBufferArray( scip, &Y_, dim*dim)); Y_[0] = 1 / mat_( orig_Q_, p, i, i); }else{ /* alloc */ SCIPfreeBufferArray(scip, &a_old); SCIP_CALL( SCIPallocBufferArray( scip, &a_old, dim)); SCIP_CALL( SCIPallocBufferArray( scip, &b, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &c, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &v, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &V_, (dim-1)*(dim-1))); SCIP_CALL( SCIPallocBufferArray( scip, &Z_, (dim)*(dim))); /* 1. b <- X^t x_i */ dgemv_t( X_, n, dim-1, &orig_X_[n * i], b); //printv( dim-1, b); /* 2. c <- Y b */ dgemv_2( Y_, dim-1, dim-1, b, c); //printv( dim-1, c); /* 3. d <- - X c + x_i */ dgemv_1( X_, n, dim-1, c, &orig_X_[n * i], -1.0, 1.0, d); //printv( n, d); /* 4. u <- 1/<x_i, d> */ u = 1.0 / myddot_( &orig_X_[n * i], d, n); //prints(u); /* 5. v <- - u c */ mydscal_( c, dim-1, -u, v); //printv( dim-1, v); /* 6. V <- Y + u c c^t */ dger_1( Y_, c, c, dim-1, dim-1, u, V_); //printM_( V_, dim-1, dim-1); /* 7. Z */ /* V */ for(j=0; j<(dim-1); j++){ for(t=0; t<(dim-1); t++){ *(Z_ + j + (t*dim) ) = mat_( V_, dim-1, j, t); } } /* v */ for(j=0; j<(dim-1); j++){ *(Z_ + dim-1 + (j*dim) ) = v[j]; *(Z_ + j + ((dim-1)*dim)) = v[j]; } /* u */ *(Z_ + dim-1 + ((dim-1)*dim)) = u; //printM_( Z_, dim, dim); /* 8. a_old <- Z (Xy) */ Xy[dim-1] = orig_q[i]; dgemv_2( Z_, dim, dim, Xy, a_old); //printv( dim, a_old); RSS = RSSvalue( dim, a_old, Xy, r); AIC = AICvalue( n, dim, RSS); /* copy */ SCIPfreeBufferArray(scip, &Y_); SCIP_CALL( SCIPallocBufferArray(scip, &Y_, dim*dim)); mydcopy_( Z_, Y_, dim*dim); /* update X_ and Xy */ mydcopy_( &orig_X_[n * i], &X_[n * (dim-1)], n); Xy[dim-1] = orig_q[i]; /* free */ SCIPfreeBufferArray(scip, &b); SCIPfreeBufferArray(scip, &c); SCIPfreeBufferArray(scip, &v); SCIPfreeBufferArray(scip, &V_); SCIPfreeBufferArray(scip, &Z_); } #if MYPARA_LOG printf("---> %dth variable, AIC:%f\n", i, AIC); #endif }else{ printf("error:heur_forward.c\n"); stop(); } } if( dim == 0 ){ #if MYPARA_LOG printf("[dim:0]\n"); #endif dim++; RSS = 1e+06; for(i=0; i<p; i++){ if( list[i] == 0 ){ a_old[0] = orig_q[i] / mat_( orig_Q_, p, i, i); RSS_new = RSSvalue( 1, a_old, &orig_q[i], r); if( RSS_new < RSS ){ RSS = RSS_new; memo = i; } #if MYPARA_LOG printf("%d: RSS = %f\n", i, RSS_new); #endif } } if( memo < 0 || memo >= p ){ printf("error in heur_forward.c\n"); stop(); } AIC = AICvalue( n, dim, RSS); list[memo] = dim; /* update X_ and Xy */ mydcopy_( &orig_X_[n * memo], &X_[n * (dim-1)], n); Xy[dim-1] = orig_q[memo]; /* generate Y ( dim = 1 ) */ SCIP_CALL( SCIPallocBufferArray( scip, &Y_, dim*dim)); Y_[0] = 1 / mat_( orig_Q_, p, memo, memo); #if MYPARA_LOG printf("---> %dth variable, AIC:%f\n", memo, AIC); #endif } /* if ( dim==0 ) */ while(1){ dim++; memo = -1; RSS = 1e+06; #if MYPARA_LOG printf("(dim=%d) ", dim); Longline(); #endif /* alloc */ SCIP_CALL( SCIPallocBufferArray( scip, &a_new, dim)); SCIP_CALL( SCIPallocBufferArray( scip, &a, dim)); SCIP_CALL( SCIPallocBufferArray( scip, &b, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &c, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &v, dim-1)); SCIP_CALL( SCIPallocBufferArray( scip, &V_, (dim-1)*(dim-1))); SCIP_CALL( SCIPallocBufferArray( scip, &Z_, (dim)*(dim))); SCIP_CALL( SCIPallocBufferArray( scip, &W_, (dim)*(dim))); for(i=0; i<p; i++){ /* * 1. b <- X^t x_i * 2. c <- Y b * 3. d <- - X c + x_i * 4. u <- 1 / <x_i, d> * 5. v <- - u c * 6. V <- Y + u c c^t * 7. Z <- ( V v v^t u ) * 8. a_new <- Z (Xy) */ if( list[i]==0 ){ /* 1. b <- X^t x_i */ dgemv_t( X_, n, dim-1, &orig_X_[n * i], b); //printv( dim-1, b); /* 2. c <- Y b */ dgemv_2( Y_, dim-1, dim-1, b, c); //printv( dim-1, c); /* 3. d <- - X c + x_i */ dgemv_1( X_, n, dim-1, c, &orig_X_[n * i], -1.0, 1.0, d); //printv( n, d); /* 4. u <- 1/<x_i, d> */ u = 1.0 / myddot_( &orig_X_[n * i], d, n); //prints(u); /* 5. v <- - u c */ mydscal_( c, dim-1, -u, v); //printv( dim-1, v); /* 6. V <- Y + u c c^t */ dger_1( Y_, c, c, dim-1, dim-1, u, V_); //printM_( V_, dim-1, dim-1); /* 7. Z */ /* V */ for(j=0; j<(dim-1); j++){ for(t=0; t<(dim-1); t++){ *(Z_ + j + (t*dim) ) = mat_( V_, dim-1, j, t); } } /* v */ for(j=0; j<(dim-1); j++){ *(Z_ + dim-1 + (j*dim) ) = v[j]; *(Z_ + j + ((dim-1)*dim)) = v[j]; } /* u */ *(Z_ + dim-1 + ((dim-1)*dim)) = u; //printM_( Z_, dim, dim); /* 8. a_new <- Z (Xy) */ Xy[dim-1] = orig_q[i]; dgemv_2( Z_, dim, dim, Xy, a_new); //printv( dim, a_new); /* test */ RSS_new = RSSvalue( dim, a_new, Xy, r); if( RSS_new < RSS ){ RSS = RSS_new; memo = i; mydcopy_( Z_, W_, dim*dim); mydcopy_( a_new, a, dim); } #if MYPARA_LOG printf("%d: RSS = %f\n", i, RSS_new); #endif } } if( memo < 0 || memo >= p ){ if( memo == -1 ){ for(i=0; i<p; i++){ if( list[i] == 0 ){ memo = i; break; } } if( memo != -1 ){ printf("error in heur_forward.c\n"); stop(); } }else{ printf("error in heur_forward.c\n"); stop(); } } AIC_new = AICvalue( n, dim, RSS); if( AIC_new < AIC ){ AIC = AIC_new; list[memo] = dim; #if MYPARA_LOG printf("---> %dth variable, AIC:%f\n", memo, AIC); #endif /* copy and free */ SCIPfreeBufferArray(scip, &Y_); SCIP_CALL( SCIPallocBufferArray(scip, &Y_, dim*dim)); mydcopy_( W_, Y_, dim*dim); SCIPfreeBufferArray(scip, &a_old); SCIP_CALL( SCIPallocBufferArray(scip, &a_old, dim)); mydcopy_( a, a_old, dim); /* update X_ and Xy */ mydcopy_( &orig_X_[n * memo], &X_[n * (dim-1)], n); Xy[dim-1] = orig_q[memo]; }else{ memo = -1; SCIPfreeBufferArray(scip, Y_); #if MYPARA_LOG printf("--> no selection, (AIC:%f)\n", AIC_new); #endif } /* free */ SCIPfreeBufferArray(scip, &a_new); SCIPfreeBufferArray(scip, &a); SCIPfreeBufferArray(scip, &b); SCIPfreeBufferArray(scip, &c); SCIPfreeBufferArray(scip, &v); SCIPfreeBufferArray(scip, &V_); SCIPfreeBufferArray(scip, &Z_); SCIPfreeBufferArray(scip, &W_); if( memo == -1 ){ dim--; break; } } nsols = SCIPgetNSols(scip); if( nsols < MP_NUM_SOL ){ store = 1; }else{ sols = SCIPgetSols(scip); objval = AIC; nsols = MP_NUM_SOL; if( objval < SCIPgetSolOrigObj(scip,sols[nsols-1]) ){ store = 1; }else{ store = 0; } } if( store ){ /* generate solution */ /* alloc */ SCIP_CALL( SCIPallocBufferArray(scip, &ep, n)); dgemv_1( X_, n, dim, a_old, y, -1.0, 1.0, ep); /* set solution */ /* alloc */ SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars)); SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars)); ct=0; /* a */ for(i=0; i<p; ++i){ vars[ct] = var_a[i]; if( list[i] > 0 ){ solvals[ct] = a_old[list[i]-1]; }else{ solvals[ct] = 0.0; } ct++; } /* z */ for(i=0; i<p; i++){ vars[ct] = var_z[i]; if( list[i] > 0 ){ solvals[ct] = 1.0; }else{ solvals[ct] = 0.0; } ct++; } /* ep */ for(i=0; i<n; ++i){ vars[ct] = var_ep[i]; solvals[ct] = ep[i]; ct++; } vars[ct] = var_rss; solvals[ct] = myddot_( ep, ep, n); ct++; vars[ct] = var_log; solvals[ct] = log(myddot_( ep, ep, n)); ct++; if( ct!=nvars ){ SCIPerrorMessage("It is unexpected error in set sol,"); printf("( ct, nvars) = ( %d, %d)", ct, nvars); stop(); } SCIP_CALL( SCIPcreateSol(scip, &sol, heur)); SCIP_CALL( SCIPsetSolVals(scip, sol, nvars, vars, solvals)); SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, FALSE, TRUE, TRUE, &success)); /* free */ SCIPfreeBufferArray(scip, &ep); SCIPfreeBufferArray(scip, &solvals); SCIPfreeBufferArray(scip, &vars); } /* free */ SCIPfreeBufferArray(scip, &d); SCIPfreeBufferArray(scip, &X_); SCIPfreeBufferArray(scip, &Xy); SCIPfreeBufferArray(scip, &a_old); SCIPfreeBufferArray(scip, &list); SCIPfreeBufferArray(scip, &Branchz); *result = SCIP_FOUNDSOL; return SCIP_OKAY; }
/** reduced cost pricing method of variable pricer for feasible LPs */ static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking) { /*lint --e{715}*/ SCIP* subscip; SCIP_PRICERDATA* pricerdata; SCIP_CONS** conss; SCIP_VAR** vars; int* ids; SCIP_Bool addvar; SCIP_SOL** sols; int nsols; int s; int nitems; SCIP_Longint capacity; SCIP_Real timelimit; SCIP_Real memorylimit; assert(scip != NULL); assert(pricer != NULL); (*result) = SCIP_DIDNOTRUN; /* get the pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); capacity = pricerdata->capacity; conss = pricerdata->conss; ids = pricerdata->ids; nitems = pricerdata->nitems; /* get the remaining time and memory limit */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; /* initialize SCIP */ SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* create problem in sub SCIP */ SCIP_CALL( SCIPcreateProbBasic(subscip, "pricing") ); SCIP_CALL( SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE) ); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* set time and memory limit */ SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPallocMemoryArray(subscip, &vars, nitems) ); /* initialization local pricing problem */ SCIP_CALL( initPricing(scip, pricerdata, subscip, vars) ); SCIPdebugMessage("solve pricer problem\n"); /* solve sub SCIP */ SCIP_CALL( SCIPsolve(subscip) ); sols = SCIPgetSols(subscip); nsols = SCIPgetNSols(subscip); addvar = FALSE; /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master, * that is the objective value i greater than 1.0 */ for( s = 0; s < nsols; ++s ) { SCIP_Bool feasible; SCIP_SOL* sol; /* the soultion should be sorted w.r.t. the objective function value */ assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s-1]), SCIPgetSolOrigObj(subscip, sols[s]))); sol = sols[s]; assert(sol != NULL); /* check if solution is feasible in original sub SCIP */ SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE ) ); if( !feasible ) { SCIPwarningMessage(scip, "solution in pricing problem (capacity <%d>) is infeasible\n", capacity); continue; } /* check if the solution has a value greater than 1.0 */ if( SCIPisFeasGT(subscip, SCIPgetSolOrigObj(subscip, sol), 1.0) ) { SCIP_VAR* var; SCIP_VARDATA* vardata; int* consids; char strtmp[SCIP_MAXSTRLEN]; char name[SCIP_MAXSTRLEN]; int nconss; int o; int v; SCIPdebug( SCIP_CALL( SCIPprintSol(subscip, sol, NULL, FALSE) ) ); nconss = 0; (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items"); SCIP_CALL( SCIPallocBufferArray(scip, &consids, nitems) ); /* check which variables are fixed -> which item belongs to this packing */ for( o = 0, v = 0; o < nitems; ++o ) { if( !SCIPconsIsEnabled(conss[o]) ) continue; assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0); if( SCIPgetSolVal(subscip, sol, vars[v]) > 0.5 ) { (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]); strcat(name, strtmp); consids[nconss] = o; nconss++; } else assert( SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0) ); v++; } SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss) ); /* create variable for a new column with objective function coefficient 0.0 */ SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, FALSE, TRUE, vardata) ); /* add the new variable to the pricer store */ SCIP_CALL( SCIPaddPricedVar(scip, var, 1.0) ); addvar = TRUE; /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have * a positive reduced cost */ SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) ); /* check which variable are fixed -> which orders belong to this packing */ for( v = 0; v < nconss; ++v ) { assert(SCIPconsIsEnabled(conss[consids[v]])); SCIP_CALL( SCIPaddCoefSetppc(scip, conss[consids[v]], var) ); } SCIPdebug(SCIPprintVar(scip, var, NULL) ); SCIP_CALL( SCIPreleaseVar(scip, &var) ); SCIPfreeBufferArray(scip, &consids); } else break; } /* free pricer MIP */ SCIPfreeMemoryArray(subscip, &vars); if( addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL ) (*result) = SCIP_SUCCESS; /* free sub SCIP */ SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpStrongcg) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_VAR** vars; SCIP_COL** cols; SCIP_ROW** rows; SCIP_Real* varsolvals; SCIP_Real* binvrow; SCIP_Real* cutcoefs; SCIP_Real cutrhs; SCIP_Real cutact; SCIP_Real maxscale; SCIP_Longint maxdnom; int* basisind; int* inds; int ninds; int nvars; int ncols; int nrows; int ncalls; int depth; int maxdepth; int maxsepacuts; int ncuts; int c; int i; int cutrank; SCIP_Bool success; SCIP_Bool cutislocal; char normtype; assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); depth = SCIPgetDepth(scip); ncalls = SCIPsepaGetNCallsAtNode(sepa); /* only call separator, if we are not close to terminating */ if( SCIPisStopped(scip) ) return SCIP_OKAY; /* only call the strong CG cut separator a given number of times at each node */ if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) ) return SCIP_OKAY; /* only call separator, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call separator, if the LP solution is basic */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* only call separator, if there are fractional variables */ if( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; /* get variables data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* get LP data */ SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); if( ncols == 0 || nrows == 0 ) return SCIP_OKAY; #if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */ if( ncols >= 50*nrows ) return SCIP_OKAY; if( ncols >= 5*nrows ) { int ncutsfound; ncutsfound = SCIPgetNCutsFound(scip); if( ncutsfound > sepadata->lastncutsfound || !SCIPsepaWasLPDelayed(sepa) ) { sepadata->lastncutsfound = ncutsfound; *result = SCIP_DELAYED; return SCIP_OKAY; } } #endif /* get the type of norm to use for efficacy calculations */ SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &normtype) ); /* set the maximal denominator in rational representation of strong CG cut and the maximal scale factor to * scale resulting cut to integral values to avoid numerical instabilities */ /**@todo find better but still stable strong CG cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */ maxdepth = SCIPgetMaxDepth(scip); if( depth == 0 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/4 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/2 ) { maxdnom = 100; maxscale = 100.0; } else { maxdnom = 10; maxscale = 10.0; } *result = SCIP_DIDNOTFIND; /* allocate temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) ); varsolvals = NULL; /* allocate this later, if needed */ /* get basis indices */ SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* get the maximal number of cuts allowed in a separation round */ if( depth == 0 ) maxsepacuts = sepadata->maxsepacutsroot; else maxsepacuts = sepadata->maxsepacuts; SCIPdebugMessage("searching strong CG cuts: %d cols, %d rows, maxdnom=%" SCIP_LONGINT_FORMAT ", maxscale=%g, maxcuts=%d\n", ncols, nrows, maxdnom, maxscale, maxsepacuts); /* for all basic columns belonging to integer variables, try to generate a strong CG cut */ ncuts = 0; for( i = 0; i < nrows && ncuts < maxsepacuts && !SCIPisStopped(scip) && *result != SCIP_CUTOFF; ++i ) { SCIP_Bool tryrow; tryrow = FALSE; c = basisind[i]; if( c >= 0 ) { SCIP_VAR* var; assert(c < ncols); var = SCIPcolGetVar(cols[c]); if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real primsol; primsol = SCIPcolGetPrimsol(cols[c]); assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/ if( SCIPfeasFrac(scip, primsol) >= MINFRAC ) { SCIPdebugMessage("trying strong CG cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol); tryrow = TRUE; } } } #ifdef SEPARATEROWS else { SCIP_ROW* row; assert(0 <= -c-1 && -c-1 < nrows); row = rows[-c-1]; if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) ) { SCIP_Real primsol; primsol = SCIPgetRowActivity(scip, row); if( SCIPfeasFrac(scip, primsol) >= MINFRAC ) { SCIPdebugMessage("trying strong CG cut for row <%s> [%g]\n", SCIProwGetName(row), primsol); tryrow = TRUE; } } } #endif if( tryrow ) { /* get the row of B^-1 for this basic integer variable with fractional solution value */ SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow, inds, &ninds) ); #ifdef SCIP_DEBUG /* initialize variables, that might not have been initialized in SCIPcalcMIR if success == FALSE */ cutact = 0.0; cutrhs = SCIPinfinity(scip); #endif /* create a strong CG cut out of the weighted LP rows using the B^-1 row as weights */ SCIP_CALL( SCIPcalcStrongCG(scip, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, MINFRAC, MAXFRAC, binvrow, inds, ninds, 1.0, cutcoefs, &cutrhs, &cutact, &success, &cutislocal, &cutrank) ); assert(ALLOWLOCAL || !cutislocal); SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs); /* if successful, convert dense cut into sparse row, and add the row as a cut */ if( success && SCIPisFeasGT(scip, cutact, cutrhs) ) { SCIP_VAR** cutvars; SCIP_Real* cutvals; SCIP_Real cutnorm; int cutlen; /* if this is the first successful cut, get the LP solution for all COLUMN variables */ if( varsolvals == NULL ) { int v; SCIP_CALL( SCIPallocBufferArray(scip, &varsolvals, nvars) ); for( v = 0; v < nvars; ++v ) { if( SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_COLUMN ) varsolvals[v] = SCIPvarGetLPSol(vars[v]); } } assert(varsolvals != NULL); /* get temporary memory for storing the cut as sparse row */ SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars) ); /* store the cut as sparse row, calculate activity and norm of cut */ SCIP_CALL( storeCutInArrays(scip, nvars, vars, cutcoefs, varsolvals, normtype, cutvars, cutvals, &cutlen, &cutact, &cutnorm) ); SCIPdebugMessage(" -> strong CG cut for <%s>: act=%f, rhs=%f, norm=%f, eff=%f, rank=%d\n", c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]), cutact, cutrhs, cutnorm, (cutact - cutrhs)/cutnorm, cutrank); if( SCIPisPositive(scip, cutnorm) && SCIPisEfficacious(scip, (cutact - cutrhs)/cutnorm) ) { SCIP_ROW* cut; char cutname[SCIP_MAXSTRLEN]; /* create the cut */ if( c >= 0 ) (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_x%d", SCIPgetNLPs(scip), c); else (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_s%d", SCIPgetNLPs(scip), -c-1); SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) ); SCIP_CALL( SCIPaddVarsToRow(scip, cut, cutlen, cutvars, cutvals) ); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ SCIProwChgRank(cut, cutrank); assert(success); #ifdef MAKECUTINTEGRAL /* try to scale the cut to integral values */ SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); #else #ifdef MAKEINTCUTINTEGRAL /* try to scale the cut to integral values if there are no continuous variables * -> leads to an integral slack variable that can later be used for other cuts */ { int k = 0; while ( k < cutlen && SCIPvarIsIntegral(cutvars[k]) ) ++k; if( k == cutlen ) { SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); } } #endif #endif #ifndef FORCECUTINTEGRAL success = TRUE; #endif if( success ) { if( !SCIPisCutEfficacious(scip, NULL, cut) ) { SCIPdebugMessage(" -> strong CG cut <%s> no longer efficacious: act=%f, rhs=%f, norm=%f, eff=%f\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut)); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ success = FALSE; } else { SCIP_Bool infeasible; SCIPdebugMessage(" -> found strong CG cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut), SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut)); /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/ SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE, &infeasible) ); if ( infeasible ) *result = SCIP_CUTOFF; else { if( !cutislocal ) { SCIP_CALL( SCIPaddPoolCut(scip, cut) ); } *result = SCIP_SEPARATED; } ncuts++; } } else { SCIPdebugMessage(" -> strong CG cut <%s> couldn't be scaled to integral coefficients: act=%f, rhs=%f, norm=%f, eff=%f\n", cutname, cutact, cutrhs, cutnorm, SCIPgetCutEfficacy(scip, NULL, cut)); } /* release the row */ SCIP_CALL( SCIPreleaseRow(scip, &cut) ); } /* free temporary memory */ SCIPfreeBufferArray(scip, &cutvals); SCIPfreeBufferArray(scip, &cutvars); } } } /* free temporary memory */ SCIPfreeBufferArrayNull(scip, &varsolvals); SCIPfreeBufferArray(scip, &inds); SCIPfreeBufferArray(scip, &binvrow); SCIPfreeBufferArray(scip, &basisind); SCIPfreeBufferArray(scip, &cutcoefs); SCIPdebugMessage("end searching strong CG cuts: found %d cuts\n", ncuts); sepadata->lastncutsfound = SCIPgetNCutsFound(scip); return SCIP_OKAY; }
/** evalutate solution */ SCIP_RETCODE LOPevalSolution( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; SCIP_VAR*** vars; SCIP_SOL* sol; int* outDegree; int* indices; int i; int j; int n; /* get problem data */ probdata = SCIPgetProbData(scip); assert( probdata != NULL ); assert( probdata->vars != NULL ); n = probdata->n; vars = probdata->vars; sol = SCIPgetBestSol(scip); if ( sol == NULL ) printf("\nNo solution found.\n"); else { SCIP_CALL( SCIPallocBufferArray(scip, &outDegree, n) ); SCIP_CALL( SCIPallocBufferArray(scip, &indices, n) ); /* compute out-degree */ for (i = 0; i < n; ++i) { int deg = 0; for (j = 0; j < n; ++j) { SCIP_Real val; if (j == i) continue; val = SCIPgetSolVal(scip, sol, vars[i][j]); assert( SCIPisIntegral(scip, val) ); if ( val < 0.5 ) ++deg; } outDegree[i] = deg; indices[i] = i; } /* sort such that degrees are non-decreasing */ SCIPsortIntInt(outDegree, indices, n); /* output */ printf("\nFinal order:\n"); for (i = 0; i < n; ++i) printf("%d ", indices[i]); printf("\n"); SCIPfreeBufferArray(scip, &indices); SCIPfreeBufferArray(scip, &outDegree); } return SCIP_OKAY; }
/** problem reading method of reader */ static SCIP_DECL_READERREAD(readerReadCip) { /*lint --e{715}*/ CIPINPUT cipinput; SCIP_Real objscale; SCIP_Real objoffset; SCIP_Bool dynamicconss; SCIP_Bool dynamiccols; SCIP_Bool dynamicrows; SCIP_Bool initialvar; SCIP_Bool removablevar; SCIP_Bool initialcons; SCIP_Bool removablecons; if( NULL == (cipinput.file = SCIPfopen(filename, "r")) ) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); SCIPprintSysError(filename); return SCIP_NOFILE; } cipinput.len = 131071; SCIP_CALL( SCIPallocBufferArray(scip, &(cipinput.strbuf), cipinput.len) ); cipinput.linenumber = 0; cipinput.section = CIP_START; cipinput.haserror = FALSE; cipinput.endfile = FALSE; cipinput.readingsize = 65535; SCIP_CALL( SCIPcreateProb(scip, filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/"READER_NAME"/dynamiccols", &dynamiccols) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/"READER_NAME"/dynamicconss", &dynamicconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/"READER_NAME"/dynamicrows", &dynamicrows) ); initialvar = !dynamiccols; removablevar = dynamiccols; initialcons = !dynamicrows; removablecons = dynamicrows; objscale = 1.0; objoffset = 0.0; while( cipinput.section != CIP_END && !cipinput.haserror ) { /* get next input string */ SCIP_CALL( getInputString(scip, &cipinput) ); if( cipinput.endfile ) break; switch( cipinput.section ) { case CIP_START: SCIP_CALL( getStart(scip, &cipinput) ); break; case CIP_STATISTIC: SCIP_CALL( getStatistic(scip, &cipinput) ); break; case CIP_OBJECTIVE: SCIP_CALL( getObjective(scip, &cipinput, &objscale, &objoffset) ); break; case CIP_VARS: SCIP_CALL( getVariable(scip, &cipinput, initialvar, removablevar, objscale) ); break; case CIP_FIXEDVARS: SCIP_CALL( getFixedVariables(scip, &cipinput) ); break; case CIP_CONSTRAINTS: SCIP_CALL( getConstraints(scip, &cipinput, initialcons, dynamicconss, removablecons) ); break; default: SCIPerrorMessage("invalid CIP state\n"); SCIPABORT(); } /*lint !e788*/ } if( !SCIPisZero(scip, objoffset) && !cipinput.haserror ) { SCIP_VAR* objoffsetvar; objoffset *= objscale; SCIP_CALL( SCIPcreateVar(scip, &objoffsetvar, "objoffset", objoffset, objoffset, 1.0, SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, objoffsetvar) ); SCIP_CALL( SCIPreleaseVar(scip, &objoffsetvar) ); SCIPdebugMessage("added variables <objoffset> for objective offset of <%g>\n", objoffset); } /* close file stream */ SCIPfclose(cipinput.file); if( cipinput.section != CIP_END && !cipinput.haserror ) { SCIPerrorMessage("unexpected EOF\n"); } SCIPfreeBufferArray(scip, &cipinput.strbuf); if( cipinput.haserror ) return SCIP_READERROR; /* successfully parsed cip format */ *result = SCIP_SUCCESS; return SCIP_OKAY; }