/** presolving method of constraint handler */ static SCIP_DECL_CONSPRESOL(consPresolConjunction) { /*lint --e{715}*/ SCIP_CONSDATA* consdata; int c; int i; assert(result != NULL); *result = SCIP_DIDNOTFIND; /* all constraints in a conjunction constraint of the global problem can be added directly to the problem and * removed from the conjunction constraint; * an unmodifiable conjunction constraint can be deleted */ for( c = 0; c < nconss; ++c ) { consdata = SCIPconsGetData(conss[c]); assert(consdata != NULL); /* add all inactive constraints to the global problem */ for( i = 0; i < consdata->nconss; ++i ) { /* update check flag for sub constraints when upgrade takes place */ if( SCIPconsIsChecked(conss[c]) ) { /* make sure, the constraint is checked for feasibility */ SCIP_CALL( SCIPsetConsChecked(scip, consdata->conss[i], TRUE) ); } /* add constraint, if it is not active yet */ if( !SCIPconsIsActive(consdata->conss[i]) ) { SCIPdebugMessage("adding constraint <%s> from add conjunction <%s>\n", SCIPconsGetName(consdata->conss[i]), SCIPconsGetName(conss[c])); SCIP_CALL( SCIPaddCons(scip, consdata->conss[i]) ); *result = SCIP_SUCCESS; } /* release constraint because it will be removed from the conjunction constraint */ SCIP_CALL( SCIPreleaseCons(scip, &(consdata->conss[i])) ); } /* all constraints where removed, so we need to clear the array */ consdata->nconss = 0; /* delete conjunction constraint, if it is unmodifiable */ if( !SCIPconsIsModifiable(conss[c]) ) { SCIP_CALL( SCIPdelCons(scip, conss[c]) ); } } return SCIP_OKAY; }
/** adds all constraints in conjunction constraints to the problem; disables unmodifiable conjunction constraints */ static SCIP_RETCODE addAllConss( SCIP* scip, /**< SCIP data structure */ SCIP_CONS** conss, /**< active conjunction constraints */ int nconss, /**< number of active conjunction constraints */ SCIP_RESULT* result /**< pointer to store the result */ ) { SCIP_CONSDATA* consdata; int c; int i; assert(result != NULL); for( c = 0; c < nconss; ++c ) { consdata = SCIPconsGetData(conss[c]); assert(consdata != NULL); /* add all inactive constraints to local subproblem */ for( i = 0; i < consdata->nconss; ++i ) { /* update check flag for sub constraints when upgrade takes place */ if( SCIPconsIsChecked(conss[c]) ) { /* make sure, the constraint is checked for feasibility */ SCIP_CALL( SCIPsetConsChecked(scip, consdata->conss[i], TRUE) ); } if( !SCIPconsIsActive(consdata->conss[i]) ) { SCIPdebugMessage("adding constraint <%s> from add conjunction <%s>\n", SCIPconsGetName(consdata->conss[i]), SCIPconsGetName(conss[c])); SCIP_CALL( SCIPaddConsLocal(scip, consdata->conss[i], NULL) ); *result = SCIP_CONSADDED; } } /* disable conjunction constraint, if it is unmodifiable */ if( !SCIPconsIsModifiable(conss[c]) ) { SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) ); } } return SCIP_OKAY; }
/** presolving method of constraint handler */ static SCIP_DECL_CONSPRESOL(consPresolDisjunction) { /*lint --e{715}*/ SCIP_CONSDATA* consdata; int oldndelconss; int c; assert(result != NULL); *result = SCIP_DIDNOTFIND; oldndelconss = *ndelconss; /* all disjunction constraints with one constraint can be replaced with that corresponding constraint */ for( c = 0; c < nconss; ++c ) { consdata = SCIPconsGetData(conss[c]); assert(consdata != NULL); if( !SCIPconsIsModifiable(conss[c]) && consdata->nconss == 1 ) { /* add constraint to the problem */ if( !SCIPconsIsActive(consdata->conss[0]) ) { SCIP_CALL( SCIPaddCons(scip, consdata->conss[0]) ); /* release constraint from the disjunction constraint */ SCIP_CALL( SCIPreleaseCons(scip, &consdata->conss[0]) ); } /* remove disjunction constraint */ SCIP_CALL( SCIPdelCons(scip, conss[0]) ); *result = SCIP_SUCCESS; } /* propagate constraint */ SCIP_CALL( propagateCons(scip, conss[c], ndelconss) ); } if( *ndelconss > oldndelconss ) *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** propagation method for disjunction constraint */ static SCIP_RETCODE propagateCons( SCIP* scip, /**< SCIP data structure */ SCIP_CONS* cons, /**< knapsack constraint */ int* ndelconss /**< pointer to count number of deleted constraints */ ) { SCIP_CONSDATA* consdata; SCIP_CONS** conss; int nconss; int c; assert(scip != NULL); assert(cons != NULL); assert(ndelconss != NULL); consdata = SCIPconsGetData(cons); assert(consdata != NULL); conss = consdata->conss; assert(conss != NULL); nconss = consdata->nconss; assert(nconss > 1); for( c = 0; c < nconss; ++c ) { if( SCIPconsIsActive(conss[c]) ) { (*ndelconss)++; SCIP_CALL( SCIPdelConsLocal(scip, cons) ); break; } } return SCIP_OKAY; }
/** try one-opt on given solution */ static SCIP_RETCODE tryOneOpt( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int cnt = 0; int i; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Performing one-opt ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[i]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); /* skip constraints with fixed variables */ if ( SCIPvarGetUbLocal(binvar) < 0.5 || SCIPvarGetLbLocal(binvar) > 0.5 ) continue; /* return if the we would exceed the depth limit of the tree */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) break; /* get rid of all bound changes */ SCIP_CALL( SCIPnewProbingNode(scip) ); ++cnt; /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_Bool s; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* fix variables according to solution candidate, except constraint i */ if ( c == i ) s = ! solcand[c]; else s = solcand[c]; if ( ! s ) { if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); #endif SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); continue; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ SCIPdebugMessage("One-opt found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); SCIP_CALL( SCIPbacktrackProbing(scip, 0) ); } SCIP_CALL( SCIPendProbing(scip) ); SCIPdebugMessage("Finished one-opt (tried variables: %d, found sols: %d).\n", cnt, *nfoundsols); return SCIP_OKAY; }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecIndicator) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; int nfoundsols = 0; assert( heur != NULL ); assert( scip != NULL ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; if ( SCIPgetSubscipDepth(scip) > 0 ) return SCIP_OKAY; /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* call heuristic, if solution candidate is available */ if ( heurdata->solcand != NULL ) { assert( heurdata->nindconss > 0 ); assert( heurdata->indconss != NULL ); /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || heurdata->nindconss < SCIPgetNBinVars(scip) ) return SCIP_OKAY; SCIP_CALL( trySolCandidate(scip, heur, heurdata, heurdata->nindconss, heurdata->indconss, heurdata->solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; /* free memory */ SCIPfreeBlockMemoryArray(scip, &(heurdata->solcand), heurdata->nindconss); SCIPfreeBlockMemoryArray(scip, &(heurdata->indconss), heurdata->nindconss); } else { SCIP_CONS** indconss; SCIP_Bool* solcand; SCIP_SOL* bestsol; int nindconss; int i; if ( heurdata->indicatorconshdlr == NULL ) return SCIP_OKAY; /* check whether a new best solution has been found */ bestsol = SCIPgetBestSol(scip); if ( bestsol == heurdata->lastsol ) return SCIP_OKAY; heurdata->lastsol = bestsol; /* avoid solutions produced by this heuristic */ if ( SCIPsolGetHeur(bestsol) == heur ) return SCIP_OKAY; /* The heuristic will only be successful if there are no integral variables and no binary variables except the * indicator variables. */ if ( SCIPgetNIntVars(scip) > 0 || SCIPconshdlrGetNConss(heurdata->indicatorconshdlr) < SCIPgetNBinVars(scip) ) return SCIP_OKAY; nindconss = SCIPconshdlrGetNConss(heurdata->indicatorconshdlr); if ( nindconss == 0 ) return SCIP_OKAY; indconss = SCIPconshdlrGetConss(heurdata->indicatorconshdlr); assert( indconss != NULL ); /* fill solutin candidate */ SCIP_CALL( SCIPallocBufferArray(scip, &solcand, nindconss) ); for (i = 0; i < nindconss; ++i) { SCIP_VAR* binvar; SCIP_Real val; solcand[i] = FALSE; if ( SCIPconsIsActive(indconss[i]) ) { binvar = SCIPgetBinaryVarIndicator(indconss[i]); assert( binvar != NULL ); val = SCIPgetSolVal(scip, bestsol, binvar); assert( SCIPisFeasIntegral(scip, val) ); if ( val > 0.5 ) solcand[i] = TRUE; } } SCIPdebugMessage("Trying to improve best solution of value %f.\n", SCIPgetSolOrigObj(scip, bestsol) ); /* try one-opt heuristic */ SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfoundsols) ); if ( nfoundsols > 0 ) *result = SCIP_FOUNDSOL; else *result = SCIP_DIDNOTFIND; SCIPfreeBufferArray(scip, &solcand); } return SCIP_OKAY; }
/** try given solution */ static SCIP_RETCODE trySolCandidate( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ SCIP_HEURDATA* heurdata, /**< heuristic data */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand, /**< values for indicator variables in partial solution */ int* nfoundsols /**< number of solutions found */ ) { SCIP_Bool cutoff; SCIP_Bool lperror; SCIP_Bool stored; SCIP_SOL* sol; int c; assert( scip != NULL ); assert( heur != NULL ); assert( heurdata != NULL ); assert( nindconss == 0 || indconss != NULL ); assert( solcand != NULL ); assert( nfoundsols != NULL ); SCIPdebugMessage("Trying to generate feasible solution with indicators from solution candidate ...\n"); *nfoundsols = 0; SCIP_CALL( SCIPstartProbing(scip) ); /* we can stop here if we have already reached the maximal depth */ if( SCIPgetDepthLimit(scip) <= SCIPgetDepth(scip) ) { SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } SCIP_CALL( SCIPnewProbingNode(scip) ); /* fix variables */ for (c = 0; c < nindconss; ++c) { SCIP_VAR* binvar; /* skip nonactive constraints */ if ( ! SCIPconsIsActive(indconss[c]) ) continue; binvar = SCIPgetBinaryVarIndicator(indconss[c]); assert( binvar != NULL ); /* Fix binary variables not in cover to 1 and corresponding slack variables to 0. The other binary variables are fixed to 0. */ if ( ! solcand[c] ) { /* to be sure, check for non-fixed variables */ if ( SCIPvarGetLbLocal(binvar) < 0.5 && SCIPvarGetUbLocal(binvar) > 0.5 ) { SCIP_CALL( SCIPchgVarLbProbing(scip, binvar, 1.0) ); } } else { if ( SCIPvarGetUbLocal(binvar) > 0.5 && SCIPvarGetLbLocal(binvar) < 0.5 ) { SCIP_CALL( SCIPchgVarUbProbing(scip, binvar, 0.0) ); } } } /* propagate variables */ SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, NULL) ); if ( cutoff ) { SCIPdebugMessage("Solution candidate reaches cutoff (in propagation).\n"); SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* solve LP to move continuous variables */ SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &cutoff) ); /* the LP often reaches the objective limit - we currently do not use such solutions */ if ( lperror || cutoff || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) { #ifdef SCIP_DEBUG if ( lperror ) SCIPdebugMessage("An LP error occured.\n"); else SCIPdebugMessage("Solution candidate reaches cutoff (in LP solving).\n"); #endif SCIP_CALL( SCIPendProbing(scip) ); return SCIP_OKAY; } /* create solution */ SCIP_CALL( SCIPcreateSol(scip, &sol, heur) ); /* copy the current LP solution to the working solution */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); /* check solution for feasibility */ #ifdef SCIP_DEBUG SCIPdebugMessage("Found solution candidate with value %g.\n", SCIPgetSolTransObj(scip, sol)); #ifdef SCIP_MORE_DEBUG SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, TRUE, &stored) ); if ( stored ) { ++(*nfoundsols); SCIPdebugMessage("Solution is feasible and stored.\n"); } else SCIPdebugMessage("Solution was not stored.\n"); #else /* only check integrality, because we solved an LP */ SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, &stored) ); if ( stored ) ++(*nfoundsols); #endif SCIP_CALL( SCIPendProbing(scip) ); /* possibly perform one-opt */ if ( stored && heurdata->oneopt ) { int nfound = 0; assert( *nfoundsols > 0 ); SCIP_CALL( tryOneOpt(scip, heur, heurdata, nindconss, indconss, solcand, &nfound) ); } return SCIP_OKAY; }
/** add branching decisions constraints to the sub SCIP */ static SCIP_RETCODE addBranchingDecisionConss( SCIP* scip, /**< SCIP data structure */ SCIP* subscip, /**< pricing SCIP data structure */ SCIP_VAR** vars, /**< variable array of the subscuip oder variables */ SCIP_CONSHDLR* conshdlr /**< constraint handler for branching data */ ) { SCIP_CONS** conss; SCIP_CONS* cons; int nconss; int id1; int id2; CONSTYPE type; SCIP_Real vbdcoef; SCIP_Real lhs; SCIP_Real rhs; int c; assert( scip != NULL ); assert( subscip != NULL ); assert( conshdlr != NULL ); /* collect all branching decision constraints */ conss = SCIPconshdlrGetConss(conshdlr); nconss = SCIPconshdlrGetNConss(conshdlr); /* loop over all branching decision constraints and apply the branching decision if the corresponding constraint is * active */ for( c = 0; c < nconss; ++c ) { cons = conss[c]; /* ignore constraints which are not active since these are not laying on the current active path of the search * tree */ if( !SCIPconsIsActive(cons) ) continue; /* collect the two item ids and the branching type (SAME or DIFFER) on which the constraint branched */ id1 = SCIPgetItemid1Samediff(scip, cons); id2 = SCIPgetItemid2Samediff(scip, cons); type = SCIPgetTypeSamediff(scip, cons); SCIPdebugMessage("create varbound for %s(%d,%d)\n", type == SAME ? "same" : "diff", SCIPprobdataGetIds(SCIPgetProbData(scip))[id1], SCIPprobdataGetIds(SCIPgetProbData(scip))[id2]); /* depending on the branching type select the correct left and right hand side for the linear constraint which * enforces this branching decision in the pricing problem MIP */ if( type == SAME ) { lhs = 0.0; rhs = 0.0; vbdcoef = -1.0; } else if( type == DIFFER ) { lhs = -SCIPinfinity(scip); rhs = 1.0; vbdcoef = 1.0; } else { SCIPerrorMessage("unknow constraint type <%d>\n, type"); return SCIP_INVALIDDATA; } /* add linear (in that case a variable bound) constraint to pricing MIP depending on the branching type: * * - branching type SAME: x1 = x2 <=> x1 - x2 = 0 <=> 0 <= x1 - x2 <= 0 * * - branching type DIFFER: x1 - x2 <= 1 <=> -inf <= x1 - x2 <= 1 * */ SCIP_CALL( SCIPcreateConsBasicVarbound(subscip, &cons, SCIPconsGetName(conss[c]), vars[id1], vars[id2], vbdcoef, lhs, rhs) ); SCIPdebug( SCIPprintCons(subscip, cons, NULL) ); SCIP_CALL( SCIPaddCons(subscip, cons) ); SCIP_CALL( SCIPreleaseCons(subscip, &cons) ); } return SCIP_OKAY; }