/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreGuideddiving) { SCIP_SOL* bestsol; SCIP_Real bestsolval; SCIP_Real obj; SCIP_Real objnorm; SCIP_Real objgain; bestsol = SCIPgetBestSol(scip); assert(bestsol != NULL); assert(!SCIPsolIsOriginal(bestsol)); bestsolval = SCIPgetSolVal(scip, bestsol, cand); /* variable should be rounded (guided) into the direction of its incumbent solution value */ if( candsol < bestsolval ) *roundup = TRUE; else *roundup = FALSE; obj = SCIPvarGetObj(cand); objnorm = SCIPgetObjNorm(scip); /* divide by objective norm to normalize obj into [-1,1] */ if( SCIPisPositive(scip, objnorm) ) obj /= objnorm; /* calculate objective gain and fractionality for the selected rounding direction */ if( *roundup ) { candsfrac = 1.0 - candsfrac; objgain = obj * candsfrac; } else objgain = -obj * candsfrac; assert(objgain >= -1.0 && objgain <= 1.0); /* penalize too small fractions */ if( candsfrac < 0.01 ) candsfrac *= 0.1; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) candsfrac *= 0.1; /* prefer variables which cannot be rounded by scoring their fractionality */ if( !(SCIPvarMayRoundDown(cand) || SCIPvarMayRoundUp(cand)) ) *score = -candsfrac; else *score = -2.0 - objgain; return SCIP_OKAY; }
/** perform dual presolving */ static SCIP_RETCODE performDualfix( SCIP* scip, /**< SCIP data structure */ int* nfixedvars, /**< pointer to store number of fixed variables */ SCIP_Bool* unbounded, /**< pointer to store if an unboundness was detected */ SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */ ) { SCIP_VAR** vars; int nvars; int v; /* get active problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* look for fixable variables * loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array */ for( v = nvars - 1; v >= 0; --v ) { SCIP_VAR* var; SCIP_Real bound; SCIP_Real obj; SCIP_Bool infeasible; SCIP_Bool fixed; var = vars[v]; assert(var != NULL); /* don't perform dual presolving operations on deleted variables */ if( SCIPvarIsDeleted(var) ) continue; /* ignore already fixed variables (use feasibility tolerance since this is used in SCIPfixVar() */ if( SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ) continue; obj = SCIPvarGetObj(var); /* if the objective coefficient of the variable is 0 and it may be rounded both * up and down, then fix it to the closest feasible value to 0 */ if( SCIPisZero(scip, obj) && SCIPvarMayRoundDown(var) && SCIPvarMayRoundUp(var) ) { SCIP_Real roundbound; bound = SCIPvarGetLbGlobal(var); if( SCIPisLT(scip, bound, 0.0) ) { if( SCIPisLE(scip, 0.0, SCIPvarGetUbGlobal(var)) ) bound = 0.0; else { /* try to take an integer value, only for polishing */ roundbound = SCIPfloor(scip, SCIPvarGetUbGlobal(var)); if( roundbound < bound ) bound = SCIPvarGetUbGlobal(var); else bound = roundbound; } } else { /* try to take an integer value, only for polishing */ roundbound = SCIPceil(scip, bound); if( roundbound < SCIPvarGetUbGlobal(var) ) bound = roundbound; } SCIPdebugMessage("fixing variable <%s> with objective 0 to %g\n", SCIPvarGetName(var), bound); } else { /* if it is always possible to round variable in direction of objective value, fix it to its proper bound */ if( SCIPvarMayRoundDown(var) && !SCIPisNegative(scip, obj) ) { bound = SCIPvarGetLbGlobal(var); if ( SCIPisInfinity(scip, -bound) ) { /* variable can be fixed to -infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksUp(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than -infinity and do nothing * here. */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d uplocks to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksUp(var), bound); } else if( SCIPvarMayRoundUp(var) && !SCIPisPositive(scip, obj) ) { bound = SCIPvarGetUbGlobal(var); if ( SCIPisInfinity(scip, bound) ) { /* variable can be fixed to infinity */ if ( SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING ) { /* Fixing variables to infinity is not allowed after presolving, since LP-solvers cannot handle this * consistently. We thus have to ignore this (should better be handled in presolving). */ continue; } if ( SCIPisZero(scip, obj) && SCIPvarGetNLocksDown(var) == 1 ) { /* Variable is only contained in one constraint: we hope that the corresponding constraint handler is * clever enough to set/aggregate the variable to something more useful than +infinity and do nothing * here */ continue; } } SCIPdebugMessage("fixing variable <%s> with objective %g and %d downlocks to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetObj(var), SCIPvarGetNLocksDown(var), bound); } else continue; } if( SCIPisInfinity(scip, REALABS(bound)) && !SCIPisZero(scip, obj) ) { SCIPdebugMessage(" -> unbounded fixing\n"); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible or unbounded: variable <%s> with objective %.15g can be made infinitely %s\n", SCIPvarGetName(var), SCIPvarGetObj(var), bound < 0.0 ? "small" : "large"); *unbounded = TRUE; return SCIP_OKAY; } /* apply the fixing */ SCIPdebugMessage("apply fixing of variable %s to %g\n", SCIPvarGetName(var), bound); SCIP_CALL( SCIPfixVar(scip, var, bound, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *cutoff = TRUE; return SCIP_OKAY; } assert(fixed || (SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisFeasEQ(scip, bound, SCIPvarGetLbLocal(var)) && SCIPisFeasEQ(scip, bound, SCIPvarGetUbLocal(var)))); (*nfixedvars)++; } return SCIP_OKAY; }
/** calculate score and preferred rounding direction for the candidate variable; the best candidate maximizes the * score */ static SCIP_DECL_DIVESETGETSCORE(divesetGetScoreFracdiving) { SCIP_Real obj; SCIP_Real objnorm; SCIP_Real objgain; SCIP_Bool mayrounddown; SCIP_Bool mayroundup; /* score fractionality if candidate is an SOS1 variable */ if ( divetype == SCIP_DIVETYPE_SOS1VARIABLE ) { *score = candsfrac; /* 'round' in nonzero direction, i.e., fix the candidates neighbors in the conflict graph to zero */ *roundup = SCIPisFeasPositive(scip, candsol); return SCIP_OKAY; } mayrounddown = SCIPvarMayRoundDown(cand); mayroundup = SCIPvarMayRoundUp(cand); /* choose rounding direction: * - if variable may be rounded in either both or neither direction, round corresponding to the fractionality * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding * the current fractional solution */ if( mayrounddown != mayroundup ) *roundup = mayrounddown; else *roundup = (candsfrac > 0.5); obj = SCIPvarGetObj(cand); objnorm = SCIPgetObjNorm(scip); /* divide by objective norm to normalize obj into [-1,1] */ if( SCIPisPositive(scip, objnorm) ) obj /= objnorm; /* calculate objective gain and fractionality for the selected rounding direction */ if( *roundup ) { candsfrac = 1.0 - candsfrac; objgain = obj * candsfrac; } else objgain = -obj * candsfrac; assert(objgain >= -1.0 && objgain <= 1.0); /* penalize too small fractions */ if( candsfrac < 0.01 ) candsfrac += 10.0; /* prefer decisions on binary variables */ if( !SCIPvarIsBinary(cand) ) candsfrac *= 1000.0; /* prefer variables which cannot be rounded by scoring their fractionality */ if( !(mayrounddown || mayroundup) ) *score = -candsfrac; else *score = -2.0 - objgain; return SCIP_OKAY; }
/** separate 2-cuts */ static SCIP_RETCODE sep_2cut( SCIP* scip, /**< SCIP data structure */ SCIP_CONSHDLR* conshdlr, /**< constraint handler */ SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */ SCIP_CONSDATA* consdata, /**< constraint data */ int maxcuts, /**< maximal number of cuts */ int* ncuts /**< pointer to store number of cuts */ ) { const SCIP_Bool nested_cut = conshdlrdata->nestedcut; const SCIP_Bool back_cut = conshdlrdata->backcut; const SCIP_Bool creep_flow = conshdlrdata->creepflow; const SCIP_Bool disjunct_cut = conshdlrdata->disjunctcut; const SCIP_Bool flowsep = conshdlrdata->flowsep; GRAPH* g; SCIP_Real* xval; SCIP_Real* cost; PATH* path; int* w; int* capa; int* term; int terms = 0; int tsave; int i; int k; int layer; int count = 0; int rerun = FALSE; int nedges; int nnodes; SCIP_Bool addedcut; assert(scip != NULL); assert(conshdlr != NULL); assert(conshdlrdata != NULL); g = consdata->graph; assert(g != NULL); nedges = g->edges; nnodes = g->knots; addedcut = FALSE; xval = SCIPprobdataGetXval(scip, NULL); assert(xval != NULL); SCIP_CALL( SCIPallocBufferArray(scip, &capa, nedges) ); SCIP_CALL( SCIPallocBufferArray(scip, &cost, nedges) ); SCIP_CALL( SCIPallocBufferArray(scip, &w, nnodes) ); SCIP_CALL( SCIPallocBufferArray(scip, &term, g->terms) ); SCIP_CALL( SCIPallocBufferArray(scip, &path, nnodes) ); for( layer = 0; layer < g->layers; layer++ ) { /* For 2-terminal nets no cuts are necessary if flows are given */ if( flowsep && (g->locals[layer] == 2) ) continue; for( i = 0; i < nedges; i++ ) cost[i] = SCIPisFeasLT(scip, xval[layer * nedges + i], 1.0) ? 1.0 : 0.0; for( i = 0; i < nnodes; i++ ) { w[i] = 0; g->mark[i] = TRUE; } graph_path_exec(scip, g, FSP_MODE, g->source[layer], cost, path); /* search all terminals not connected to the root by the LP solution */ for( i = 0, count = 0; i < nnodes; i++ ) { if( (g->term[i] == layer) && (i != g->source[layer]) ) { if( SCIPisPositive(scip, path[i].dist) ) term[terms++] = i; else count++; } } SCIPdebugMessage("Cut Pretest: %d eliminations\n", count); count = 0; tsave = terms; /* from source to terminal */ if( !nested_cut || disjunct_cut ) set_capacity(g, layer, creep_flow, 0, capa, xval); while( terms > 0 ) { if( SCIPisStopped(scip) && terms % 100 == 0 ) break; /* look for reachable terminal */ i = graph_next_term(terms, term, w); terms--; assert(g->term[i] == layer); assert(g->source[layer] != i); if( nested_cut && !disjunct_cut ) set_capacity(g, layer, creep_flow, 0, capa, xval); do { graph_mincut_exec(g, g->source[layer], i, capa, w, rerun); rerun = TRUE; /* cut */ for( k = 0; k < nnodes; k++ ) g->mark[k] = (w[k] != 0); SCIP_CALL( cut_add(scip, conshdlr, g, layer, xval, capa, nested_cut || disjunct_cut, ncuts, &addedcut) ); if( addedcut ) { count++; if( *ncuts >= maxcuts ) goto TERMINATE; } else break; } while( nested_cut ); /* Nested Cut is CONSTANT ! */ } /* back cuts enabled? */ if( back_cut ) { if( !nested_cut || disjunct_cut ) set_capacity(g, layer, creep_flow, 1, capa, xval); terms = tsave; while( terms > 0 ) { /* look for reachable terminal */ i = graph_next_term(terms, term, w); terms--; assert(g->term[i] == layer); assert(g->source[layer] != i); if( nested_cut && !disjunct_cut ) set_capacity(g, layer, creep_flow, 1, capa, xval); rerun = FALSE; do { graph_mincut_exec(g, i, g->source[layer], capa, w, rerun); rerun = TRUE; for( k = 0; k < nnodes; k++ ) g->mark[k] = (w[k] != 0) ? 1 : 0; SCIP_CALL( cut_add(scip, conshdlr, g, layer, xval, capa, nested_cut || disjunct_cut, ncuts, &addedcut) ); if( addedcut ) { count++; if( *ncuts >= maxcuts ) goto TERMINATE; } else break; #if 0 if (nested_cut || disjunct_cut) for(k = p->beg[p->rcnt - 1]; k < p->nzcnt; k++) capa[p->ind[k] % nedges + (((p->ind[k] % nedges) % 2) ? -1 : 1)] = FLOW_FACTOR; #endif } while( nested_cut ); /* Nested Cut is CONSTANT ! */ rerun = FALSE; } } } TERMINATE: SCIPfreeBufferArray(scip, &path); SCIPfreeBufferArray(scip, &term); SCIPfreeBufferArray(scip, &w); SCIPfreeBufferArray(scip, &cost); SCIPfreeBufferArray(scip, &capa); SCIPdebugMessage("2-cut Separator: %d Inequalities added\n", count); return SCIP_OKAY; }
/** execution method of presolver */ static SCIP_DECL_PRESOLEXEC(presolExecDualfix) { /*lint --e{715}*/ SCIP_VAR** vars; SCIP_Real bound; SCIP_Real roundbound; SCIP_Real obj; SCIP_Bool infeasible; SCIP_Bool fixed; int nvars; int v; assert(presol != NULL); assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0); assert(result != NULL); *result = SCIP_DIDNOTFIND; /* get active problem variables */ vars = SCIPgetVars(scip); nvars = SCIPgetNVars(scip); /* look for fixable variables * loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array */ for( v = nvars - 1; v >= 0; --v ) { /* don't perform dual presolving operations on deleted variables */ if( SCIPvarIsDeleted(vars[v]) ) continue; obj = SCIPvarGetObj(vars[v]); /* if the objective coefficient of the variable is 0 and it may be rounded both * up and down, then fix it to the closest feasible value to 0 */ if( SCIPisZero(scip, obj) && SCIPvarMayRoundDown(vars[v]) && SCIPvarMayRoundUp(vars[v]) ) { bound = SCIPvarGetLbGlobal(vars[v]); if( SCIPisLT(scip, bound, 0.0) ) { if( SCIPisLE(scip, 0.0, SCIPvarGetUbGlobal(vars[v])) ) bound = 0.0; else { /* try to take an integer value, only for polishing */ roundbound = SCIPfloor(scip, SCIPvarGetUbGlobal(vars[v])); if( roundbound < bound ) bound = SCIPvarGetUbGlobal(vars[v]); else bound = roundbound; } } else { /* try to take an integer value, only for polishing */ roundbound = SCIPceil(scip, bound); if( roundbound < SCIPvarGetUbGlobal(vars[v]) ) bound = roundbound; } SCIPdebugMessage("variable <%s> with objective 0 fixed to %g\n", SCIPvarGetName(vars[v]), bound); } else { /* if it is always possible to round variable in direction of objective value, * fix it to its proper bound */ if( SCIPvarMayRoundDown(vars[v]) && !SCIPisNegative(scip, obj) ) { bound = SCIPvarGetLbGlobal(vars[v]); if( SCIPisZero(scip, obj) && SCIPvarGetNLocksUp(vars[v]) == 1 && SCIPisInfinity(scip, -bound) ) { /* variable can be set to -infinity, and it is only contained in one constraint: * we hope that the corresponding constraint handler is clever enough to set/aggregate the variable * to something more useful than -infinity and do nothing here */ continue; } SCIPdebugMessage("variable <%s> with objective %g and %d uplocks fixed to lower bound %g\n", SCIPvarGetName(vars[v]), SCIPvarGetObj(vars[v]), SCIPvarGetNLocksUp(vars[v]), bound); } else if( SCIPvarMayRoundUp(vars[v]) && !SCIPisPositive(scip, obj) ) { bound = SCIPvarGetUbGlobal(vars[v]); if( SCIPisZero(scip, obj) && SCIPvarGetNLocksDown(vars[v]) == 1 && SCIPisInfinity(scip, bound) ) { /* variable can be set to +infinity, and it is only contained in one constraint: * we hope that the corresponding constraint handler is clever enough to set/aggregate the variable * to something more useful than +infinity and do nothing here */ continue; } SCIPdebugMessage("variable <%s> with objective %g and %d downlocks fixed to upper bound %g\n", SCIPvarGetName(vars[v]), SCIPvarGetObj(vars[v]), SCIPvarGetNLocksDown(vars[v]), bound); } else continue; } /* apply the fixing */ if( SCIPisInfinity(scip, REALABS(bound)) && !SCIPisZero(scip, obj) ) { SCIPdebugMessage(" -> unbounded fixing\n"); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "problem infeasible or unbounded: variable <%s> with objective %.15g can be made infinitely %s\n", SCIPvarGetName(vars[v]), SCIPvarGetObj(vars[v]), bound < 0.0 ? "small" : "large"); *result = SCIP_UNBOUNDED; return SCIP_OKAY; } SCIP_CALL( SCIPfixVar(scip, vars[v], bound, &infeasible, &fixed) ); if( infeasible ) { SCIPdebugMessage(" -> infeasible fixing\n"); *result = SCIP_CUTOFF; return SCIP_OKAY; } assert(fixed); (*nfixedvars)++; *result = SCIP_SUCCESS; } return SCIP_OKAY; }
/** transforms given solution of the master problem into solution of the original problem * @todo think about types of epsilons used in this method */ SCIP_RETCODE GCGrelaxTransformMastersolToOrigsol( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* mastersol, /**< solution of the master problem, or NULL for current LP solution */ SCIP_SOL** origsol /**< pointer to store the new created original problem's solution */ ) { SCIP* masterprob; int npricingprobs; int* blocknrs; SCIP_Real* blockvalue; SCIP_Real increaseval; SCIP_VAR** mastervars; SCIP_Real* mastervals; int nmastervars; SCIP_VAR** vars; int nvars; SCIP_Real feastol; int i; int j; assert(scip != NULL); assert(origsol != NULL); masterprob = GCGrelaxGetMasterprob(scip); npricingprobs = GCGrelaxGetNPricingprobs(scip); assert( !SCIPisInfinity(scip, SCIPgetSolOrigObj(masterprob, mastersol)) ); SCIP_CALL( SCIPcreateSol(scip, origsol, GCGrelaxGetProbingheur(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &blockvalue, npricingprobs) ); SCIP_CALL( SCIPallocBufferArray(scip, &blocknrs, npricingprobs) ); /* get variables of the master problem and their solution values */ SCIP_CALL( SCIPgetVarsData(masterprob, &mastervars, &nmastervars, NULL, NULL, NULL, NULL) ); assert(mastervars != NULL); assert(nmastervars >= 0); SCIP_CALL( SCIPallocBufferArray(scip, &mastervals, nmastervars) ); SCIP_CALL( SCIPgetSolVals(masterprob, mastersol, nmastervars, mastervars, mastervals) ); /* initialize the block values for the pricing problems */ for( i = 0; i < npricingprobs; i++ ) { blockvalue[i] = 0.0; blocknrs[i] = 0; } /* loop over all given master variables */ for( i = 0; i < nmastervars; i++ ) { SCIP_VAR** origvars; int norigvars; SCIP_Real* origvals; SCIP_Bool isray; int blocknr; origvars = GCGmasterVarGetOrigvars(mastervars[i]); norigvars = GCGmasterVarGetNOrigvars(mastervars[i]); origvals = GCGmasterVarGetOrigvals(mastervars[i]); blocknr = GCGvarGetBlock(mastervars[i]); isray = GCGmasterVarIsRay(mastervars[i]); assert(GCGvarIsMaster(mastervars[i])); assert(!SCIPisFeasNegative(scip, mastervals[i])); /** @todo handle infinite master solution values */ assert(!SCIPisInfinity(scip, mastervals[i])); /* first of all, handle variables representing rays */ if( isray ) { assert(blocknr >= 0); /* we also want to take into account variables representing rays, that have a small value (between normal and feas eps), * so we do no feas comparison here */ if( SCIPisPositive(scip, mastervals[i]) ) { /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { if( SCIPisZero(scip, origvals[j]) ) break; assert(!SCIPisZero(scip, origvals[j])); /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done later) */ if( GCGvarIsLinking(origvars[j]) ) continue; SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[j]), origvals[j] * mastervals[i], SCIPvarGetName(mastervars[i])); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[j], origvals[j] * mastervals[i]) ); } } mastervals[i] = 0.0; continue; } /* handle the variables with value >= 1 to get integral values in original solution */ while( SCIPisFeasGE(scip, mastervals[i], 1.0) ) { /* variable was directly transferred to the master problem (only in linking conss or linking variable) */ /** @todo this may be the wrong place for this case, handle it before the while loop * and remove the similar case in the next while loop */ if( blocknr == -1 ) { assert(norigvars == 1); assert(origvals[0] == 1.0); /* increase the corresponding value */ SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[0]), origvals[0] * mastervals[i], SCIPvarGetName(mastervars[i])); SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[0], origvals[0] * mastervals[i]) ); mastervals[i] = 0.0; } else { assert(blocknr >= 0); /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { SCIP_VAR* pricingvar; int norigpricingvars; SCIP_VAR** origpricingvars; if( SCIPisZero(scip, origvals[j]) ) break; assert(!SCIPisZero(scip, origvals[j])); /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done above) */ if( GCGvarIsLinking(origvars[j]) ) continue; pricingvar = GCGoriginalVarGetPricingVar(origvars[j]); assert(GCGvarIsPricing(pricingvar)); norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar); origpricingvars = GCGpricingVarGetOrigvars(pricingvar); /* just in case a variable has a value higher than the number of blocks, it represents */ if( norigpricingvars <= blocknrs[blocknr] ) { SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[norigpricingvars-1]), mastervals[i] * origvals[j], SCIPvarGetName(mastervars[i])); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[norigpricingvars-1], mastervals[i] * origvals[j]) ); mastervals[i] = 1.0; } /* this should be default */ else { SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[blocknrs[blocknr]]), origvals[j], SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[blocknrs[blocknr]], origvals[j]) ); } } mastervals[i] = mastervals[i] - 1.0; blocknrs[blocknr]++; } } } /* loop over all given master variables */ for( i = 0; i < nmastervars; i++ ) { SCIP_VAR** origvars; int norigvars; SCIP_Real* origvals; int blocknr; origvars = GCGmasterVarGetOrigvars(mastervars[i]); norigvars = GCGmasterVarGetNOrigvars(mastervars[i]); origvals = GCGmasterVarGetOrigvals(mastervars[i]); blocknr = GCGvarGetBlock(mastervars[i]); if( SCIPisFeasZero(scip, mastervals[i]) ) { continue; } assert(SCIPisFeasGE(scip, mastervals[i], 0.0) && SCIPisFeasLT(scip, mastervals[i], 1.0)); while( SCIPisFeasPositive(scip, mastervals[i]) ) { assert(GCGvarIsMaster(mastervars[i])); assert(!GCGmasterVarIsRay(mastervars[i])); if( blocknr == -1 ) { assert(norigvars == 1); assert(origvals[0] == 1.0); SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origvars[0]), origvals[0] * mastervals[i], SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origvars[0], origvals[0] * mastervals[i]) ); mastervals[i] = 0.0; } else { increaseval = MIN(mastervals[i], 1.0 - blockvalue[blocknr]); /* loop over all original variables contained in the current master variable */ for( j = 0; j < norigvars; j++ ) { SCIP_VAR* pricingvar; int norigpricingvars; SCIP_VAR** origpricingvars; if( SCIPisZero(scip, origvals[j]) ) continue; /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done above) */ if( GCGvarIsLinking(origvars[j]) ) continue; pricingvar = GCGoriginalVarGetPricingVar(origvars[j]); assert(GCGvarIsPricing(pricingvar)); norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar); origpricingvars = GCGpricingVarGetOrigvars(pricingvar); if( norigpricingvars <= blocknrs[blocknr] ) { increaseval = mastervals[i]; SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[norigpricingvars-1]), origvals[j] * increaseval, SCIPvarGetName(mastervars[i]) ); /* increase the corresponding value */ SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[norigpricingvars-1], origvals[j] * increaseval) ); } else { /* increase the corresponding value */ SCIPdebugMessage("Increasing value of %s by %f because of %s\n", SCIPvarGetName(origpricingvars[blocknrs[blocknr]]), origvals[j] * increaseval, SCIPvarGetName(mastervars[i]) ); SCIP_CALL( SCIPincSolVal(scip, *origsol, origpricingvars[blocknrs[blocknr]], origvals[j] * increaseval) ); } } mastervals[i] = mastervals[i] - increaseval; if( SCIPisFeasZero(scip, mastervals[i]) ) { mastervals[i] = 0.0; } blockvalue[blocknr] += increaseval; /* if the value assigned to the block is equal to 1, this block is full and we take the next block */ if( SCIPisFeasGE(scip, blockvalue[blocknr], 1.0) ) { blockvalue[blocknr] = 0.0; blocknrs[blocknr]++; } } } } SCIPfreeBufferArray(scip, &mastervals); SCIPfreeBufferArray(scip, &blocknrs); SCIPfreeBufferArray(scip, &blockvalue); /* if the solution violates one of its bounds by more than feastol * and less than 10*feastol, round it and print a warning */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPgetRealParam(scip, "numerics/feastol", &feastol) ); for( i = 0; i < nvars; ++i ) { SCIP_Real solval; SCIP_Real lb; SCIP_Real ub; solval = SCIPgetSolVal(scip, *origsol, vars[i]); lb = SCIPvarGetLbLocal(vars[i]); ub = SCIPvarGetUbLocal(vars[i]); if( SCIPisFeasGT(scip, solval, ub) && EPSEQ(solval, ub, 10 * feastol) ) { SCIP_CALL( SCIPsetSolVal(scip, *origsol, vars[i], ub) ); SCIPwarningMessage(scip, "Variable %s rounded from %g to %g in relaxation solution\n", SCIPvarGetName(vars[i]), solval, ub); } else if( SCIPisFeasLT(scip, solval, lb) && EPSEQ(solval, lb, 10 * feastol) ) { SCIP_CALL( SCIPsetSolVal(scip, *origsol, vars[i], lb) ); SCIPwarningMessage(scip, "Variable %s rounded from %g to %g in relaxation solution\n", SCIPvarGetName(vars[i]), solval, lb); } } 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; }
/** returns a variable, that pushes activity of the row in the given direction with minimal negative impact on other rows; * if variables have equal impact, chooses the one with best objective value improvement in corresponding direction; * prefer fractional integers over other variables in order to become integral during the process; * shifting in a direction is forbidden, if this forces the objective value over the upper bound, or if the variable * was already shifted in the opposite direction */ static SCIP_RETCODE selectShifting( SCIP* scip, /**< SCIP data structure */ SCIP_SOL* sol, /**< primal solution */ SCIP_ROW* row, /**< LP row */ SCIP_Real rowactivity, /**< activity of LP row */ int direction, /**< should the activity be increased (+1) or decreased (-1)? */ SCIP_Real* nincreases, /**< array with weighted number of increasings per variables */ SCIP_Real* ndecreases, /**< array with weighted number of decreasings per variables */ SCIP_Real increaseweight, /**< current weight of increase/decrease updates */ SCIP_VAR** shiftvar, /**< pointer to store the shifting variable, returns NULL if impossible */ SCIP_Real* oldsolval, /**< pointer to store old solution value of shifting variable */ SCIP_Real* newsolval /**< pointer to store new (shifted) solution value of shifting variable */ ) { SCIP_COL** rowcols; SCIP_Real* rowvals; int nrowcols; SCIP_Real activitydelta; SCIP_Real bestshiftscore; SCIP_Real bestdeltaobj; int c; assert(direction == +1 || direction == -1); assert(nincreases != NULL); assert(ndecreases != NULL); assert(shiftvar != NULL); assert(oldsolval != NULL); assert(newsolval != NULL); /* get row entries */ rowcols = SCIProwGetCols(row); rowvals = SCIProwGetVals(row); nrowcols = SCIProwGetNLPNonz(row); /* calculate how much the activity must be shifted in order to become feasible */ activitydelta = (direction == +1 ? SCIProwGetLhs(row) - rowactivity : SCIProwGetRhs(row) - rowactivity); assert((direction == +1 && SCIPisPositive(scip, activitydelta)) || (direction == -1 && SCIPisNegative(scip, activitydelta))); /* select shifting variable */ bestshiftscore = SCIP_REAL_MAX; bestdeltaobj = SCIPinfinity(scip); *shiftvar = NULL; *newsolval = 0.0; *oldsolval = 0.0; for( c = 0; c < nrowcols; ++c ) { SCIP_COL* col; SCIP_VAR* var; SCIP_Real val; SCIP_Real solval; SCIP_Real shiftval; SCIP_Real shiftscore; SCIP_Bool isinteger; SCIP_Bool isfrac; SCIP_Bool increase; col = rowcols[c]; var = SCIPcolGetVar(col); val = rowvals[c]; assert(!SCIPisZero(scip, val)); solval = SCIPgetSolVal(scip, sol, var); isinteger = (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER); isfrac = isinteger && !SCIPisFeasIntegral(scip, solval); increase = (direction * val > 0.0); /* calculate the score of the shifting (prefer smaller values) */ if( isfrac ) shiftscore = increase ? -1.0 / (SCIPvarGetNLocksUp(var) + 1.0) : -1.0 / (SCIPvarGetNLocksDown(var) + 1.0); else { int probindex; probindex = SCIPvarGetProbindex(var); if( increase ) shiftscore = ndecreases[probindex]/increaseweight; else shiftscore = nincreases[probindex]/increaseweight; if( isinteger ) shiftscore += 1.0; } if( shiftscore <= bestshiftscore ) { SCIP_Real deltaobj; if( !increase ) { /* shifting down */ assert(direction * val < 0.0); if( isfrac ) shiftval = SCIPfeasFloor(scip, solval); else { SCIP_Real lb; assert(activitydelta/val < 0.0); shiftval = solval + activitydelta/val; assert(shiftval <= solval); /* may be equal due to numerical digit erasement in the subtraction */ if( SCIPvarIsIntegral(var) ) shiftval = SCIPfeasFloor(scip, shiftval); lb = SCIPvarGetLbGlobal(var); shiftval = MAX(shiftval, lb); } } else { /* shifting up */ assert(direction * val > 0.0); if( isfrac ) shiftval = SCIPfeasCeil(scip, solval); else { SCIP_Real ub; assert(activitydelta/val > 0.0); shiftval = solval + activitydelta/val; assert(shiftval >= solval); /* may be equal due to numerical digit erasement in the subtraction */ if( SCIPvarIsIntegral(var) ) shiftval = SCIPfeasCeil(scip, shiftval); ub = SCIPvarGetUbGlobal(var); shiftval = MIN(shiftval, ub); } } if( SCIPisEQ(scip, shiftval, solval) ) continue; deltaobj = SCIPvarGetObj(var) * (shiftval - solval); if( shiftscore < bestshiftscore || deltaobj < bestdeltaobj ) { bestshiftscore = shiftscore; bestdeltaobj = deltaobj; *shiftvar = var; *oldsolval = solval; *newsolval = shiftval; } } } return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecOctane) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_SOL** first_sols; /* stores the first ffirst sols in order to check for common violation of a row */ SCIP_VAR** vars; /* the variables of the problem */ SCIP_VAR** fracvars; /* variables, that are fractional in current LP solution */ SCIP_VAR** subspacevars; /* the variables on which the search is performed. Either coinciding with vars or with the * space of all fractional variables of the current LP solution */ SCIP_Real p; /* n/2 - <delta,x> ( for some facet delta ) */ SCIP_Real q; /* <delta,a> */ SCIP_Real* rayorigin; /* origin of the ray, vector x in paper */ SCIP_Real* raydirection; /* direction of the ray, vector a in paper */ SCIP_Real* negquotient; /* negated quotient of rayorigin and raydirection, vector v in paper */ SCIP_Real* lambda; /* stores the distance of the facets (s.b.) to the origin of the ray */ SCIP_Bool usefracspace; /* determines whether the search concentrates on fractional variables and fixes integer ones */ SCIP_Bool cons_viol; /* used for checking whether a linear constraint is violated by one of the possible solutions */ SCIP_Bool success; SCIP_Bool* sign; /* signature of the direction of the ray */ SCIP_Bool** facets; /* list of extended facets */ int nvars; /* number of variables */ int nbinvars; /* number of 0-1-variables */ int nfracvars; /* number of fractional variables in current LP solution */ int nsubspacevars; /* dimension of the subspace on which the search is performed */ int nfacets; /* number of facets hidden by the ray that where already found */ int i; /* counter */ int j; /* counter */ int f_max; /* {0,1}-points to be checked */ int f_first; /* {0,1}-points to be generated at first in order to check whether a restart is necessary */ int r; /* counter */ int firstrule; int* perm; /* stores the way in which the coordinates were permuted */ int* fracspace; /* maps the variables of the subspace to the original variables */ assert(heur != NULL); assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(scip != NULL); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DELAYED; /* only call heuristic, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; *result = SCIP_DIDNOTRUN; SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) ); /* OCTANE is for use in 0-1 programs only */ if( nvars != nbinvars ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* don't call heuristic, if it was not successful enough in the past */ /*lint --e{647}*/ if( SCIPgetNNodes(scip) % (SCIPheurGetNCalls(heur) / (100 * SCIPheurGetNBestSolsFound(heur) + 10*heurdata->nsuccess + 1) + 1) != 0 ) return SCIP_OKAY; SCIP_CALL( SCIPgetLPBranchCands(scip, &fracvars, NULL, NULL, &nfracvars, NULL) ); /* don't use integral starting points */ if( nfracvars == 0 ) return SCIP_OKAY; /* get working pointers from heurdata */ sol = heurdata->sol; assert( sol != NULL ); f_max = heurdata->f_max; f_first = heurdata->f_first; usefracspace = heurdata->usefracspace; SCIP_CALL( SCIPallocBufferArray(scip, &fracspace, nvars) ); /* determine the space one which OCTANE should work either as the whole space or as the space of fractional variables */ if( usefracspace ) { nsubspacevars = nfracvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); BMScopyMemoryArray(subspacevars, fracvars, nsubspacevars); for( i = nvars - 1; i >= 0; --i ) fracspace[i] = -1; for( i = nsubspacevars - 1; i >= 0; --i ) fracspace[SCIPvarGetProbindex(subspacevars[i])] = i; } else { int currentindex; nsubspacevars = nvars; SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) ); /* only copy the variables which are in the current LP */ currentindex = 0; for( i = 0; i < nvars; ++i ) { if( SCIPcolGetLPPos(SCIPvarGetCol(vars[i])) >= 0 ) { subspacevars[currentindex] = vars[i]; fracspace[i] = currentindex; ++currentindex; } else { fracspace[i] = -1; --nsubspacevars; } } } /* nothing to do for empty search space */ if( nsubspacevars == 0 ) return SCIP_OKAY; assert(0 < nsubspacevars && nsubspacevars <= nvars); for( i = 0; i < nsubspacevars; i++) assert(fracspace[SCIPvarGetProbindex(subspacevars[i])] == i); /* at most 2^(n-1) facets can be hit */ if( nsubspacevars < 30 ) { /*lint --e{701}*/ assert(f_max > 0); f_max = MIN(f_max, 1 << (nsubspacevars - 1) ); } f_first = MIN(f_first, f_max); /* memory allocation */ SCIP_CALL( SCIPallocBufferArray(scip, &rayorigin, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &raydirection, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &negquotient, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &sign, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &perm, nsubspacevars) ); SCIP_CALL( SCIPallocBufferArray(scip, &lambda, f_max + 1) ); SCIP_CALL( SCIPallocBufferArray(scip, &facets, f_max + 1) ); for( i = f_max; i >= 0; --i ) { /*lint --e{866}*/ SCIP_CALL( SCIPallocBufferArray(scip, &facets[i], nsubspacevars) ); } SCIP_CALL( SCIPallocBufferArray(scip, &first_sols, f_first) ); *result = SCIP_DIDNOTFIND; /* starting OCTANE */ SCIPdebugMessage("run Octane heuristic on %s variables, which are %d vars, generate at most %d facets, using rule number %d\n", usefracspace ? "fractional" : "all", nsubspacevars, f_max, (heurdata->lastrule+1)%5); /* generate starting point in original coordinates */ SCIP_CALL( generateStartingPoint(scip, rayorigin, subspacevars, nsubspacevars) ); for( i = nsubspacevars - 1; i >= 0; --i ) rayorigin[i] -= 0.5; firstrule = heurdata->lastrule; ++firstrule; for( r = firstrule; r <= firstrule + 10 && !SCIPisStopped(scip); r++ ) { SCIP_ROW** rows; int nrows; /* generate shooting ray in original coordinates by certain rules */ switch(r % 5) { case 1: if( heurdata->useavgnbray ) { SCIP_CALL( generateAverageNBRay(scip, raydirection, fracspace, subspacevars, nsubspacevars) ); } break; case 2: if( heurdata->useobjray ) { SCIP_CALL( generateObjectiveRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 3: if( heurdata->usediffray ) { SCIP_CALL( generateDifferenceRay(scip, raydirection, subspacevars, nsubspacevars) ); } break; case 4: if( heurdata->useavgwgtray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, TRUE) ); } break; case 0: if( heurdata->useavgray && SCIPisLPSolBasic(scip) ) { SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, FALSE) ); } break; default: SCIPerrorMessage("invalid ray rule identifier\n"); SCIPABORT(); } /* there must be a feasible direction for the shooting ray */ if( isZero(scip, raydirection, nsubspacevars) ) continue; /* transform coordinates such that raydirection >= 0 */ flipCoords(rayorigin, raydirection, sign, nsubspacevars); for( i = f_max - 1; i >= 0; --i) lambda[i] = SCIPinfinity(scip); /* calculate negquotient, initialize perm, facets[0], p, and q */ p = 0.5 * nsubspacevars; q = 0.0; for( i = nsubspacevars - 1; i >= 0; --i ) { /* calculate negquotient, the ratio of rayorigin and raydirection, paying special attention to the case raydirection[i] == 0 */ if( SCIPisFeasZero(scip, raydirection[i]) ) { if( rayorigin[i] < 0 ) negquotient[i] = SCIPinfinity(scip); else negquotient[i] = -SCIPinfinity(scip); } else negquotient[i] = - (rayorigin[i] / raydirection[i]); perm[i] = i; /* initialization of facets[0] to the all-one facet with p and q its characteristic values */ facets[0][i] = TRUE; p -= rayorigin[i]; q += raydirection[i]; } assert(SCIPisPositive(scip, q)); /* resort the coordinates in nonincreasing order of negquotient */ SCIPsortDownRealRealRealBoolPtr( negquotient, raydirection, rayorigin, sign, (void**) subspacevars, nsubspacevars); #ifndef NDEBUG for( i = 0; i < nsubspacevars; i++ ) assert( raydirection[i] >= 0 ); for( i = 1; i < nsubspacevars; i++ ) assert( negquotient[i - 1] >= negquotient[i] ); #endif /* finished initialization */ /* find the first facet of the octahedron hit by a ray shot from rayorigin into direction raydirection */ for( i = 0; i < nsubspacevars && negquotient[i] * q > p; ++i ) { facets[0][i] = FALSE; p += 2 * rayorigin[i]; q -= 2 * raydirection[i]; assert(SCIPisPositive(scip, p)); assert(SCIPisPositive(scip, q)); } /* avoid dividing by values close to 0.0 */ if( !SCIPisFeasPositive(scip, q) ) continue; /* assert necessary for flexelint */ assert(q > 0); lambda[0] = p / q; nfacets = 1; /* find the first facets hit by the ray */ for( i = 0; i < nfacets && i < f_first; ++i) generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); /* construct the first ffirst possible solutions */ for( i = 0; i < nfacets && i < f_first; ++i ) { SCIP_CALL( SCIPcreateSol(scip, &first_sols[i], heur) ); SCIP_CALL( getSolFromFacet(scip, facets[i], first_sols[i], sign, subspacevars, nsubspacevars) ); assert( first_sols[i] != NULL ); } /* try, whether there is a row violated by all of the first ffirst solutions */ cons_viol = FALSE; SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); for( i = nrows - 1; i >= 0; --i ) { if( !SCIProwIsLocal(rows[i]) ) { SCIP_COL** cols; SCIP_Real constant; SCIP_Real lhs; SCIP_Real rhs; SCIP_Real rowval; SCIP_Real* coeffs; int nnonzerovars; int k; /* get the row's data */ constant = SCIProwGetConstant(rows[i]); lhs = SCIProwGetLhs(rows[i]); rhs = SCIProwGetRhs(rows[i]); coeffs = SCIProwGetVals(rows[i]); nnonzerovars = SCIProwGetNNonz(rows[i]); cols = SCIProwGetCols(rows[i]); rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[0], SCIPcolGetVar(cols[j])); /* if the row's lhs is violated by the first sol, test, whether it is violated by the next ones, too */ if( lhs > rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( lhs <= rowval ) { cons_viol = FALSE; break; } } } /* dito for the right hand side */ else if( rhs < rowval ) { cons_viol = TRUE; for( k = MIN(f_first, nfacets) - 1; k > 0; --k ) { rowval = constant; for( j = nnonzerovars - 1; j >= 0; --j ) rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j])); if( rhs >= rowval ) { cons_viol = FALSE; break; } } } /* break as soon as one row is violated by all of the ffirst solutions */ if( cons_viol ) break; } } if( !cons_viol ) { /* if there was no row violated by all solutions, try whether one or more of them are feasible */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { assert(first_sols[i] != NULL); SCIP_CALL( SCIPtrySol(scip, first_sols[i], FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } /* search for further facets and construct and try solutions out of facets fixed as closest ones */ for( i = f_first; i < f_max; ++i) { if( i >= nfacets ) break; generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets); SCIP_CALL( getSolFromFacet(scip, facets[i], sol, sign, subspacevars, nsubspacevars) ); SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &success) ); if( success ) *result = SCIP_FOUNDSOL; } } /* finished OCTANE */ for( i = MIN(f_first, nfacets) - 1; i >= 0; --i ) { SCIP_CALL( SCIPfreeSol(scip, &first_sols[i]) ); } } heurdata->lastrule = r; if( *result == SCIP_FOUNDSOL ) ++(heurdata->nsuccess); /* free temporary memory */ SCIPfreeBufferArray(scip, &first_sols); for( i = f_max; i >= 0; --i ) SCIPfreeBufferArray(scip, &facets[i]); SCIPfreeBufferArray(scip, &facets); SCIPfreeBufferArray(scip, &lambda); SCIPfreeBufferArray(scip, &perm); SCIPfreeBufferArray(scip, &sign); SCIPfreeBufferArray(scip, &negquotient); SCIPfreeBufferArray(scip, &raydirection); SCIPfreeBufferArray(scip, &rayorigin); SCIPfreeBufferArray(scip, &subspacevars); SCIPfreeBufferArray(scip, &fracspace); return SCIP_OKAY; }