/** extends given clique by additional zero-weight nodes of the given node set */ static void extendCliqueZeroWeight( TCLIQUE_SELECTADJNODES((*selectadjnodes)), /**< user function to select adjacent edges */ TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */ int* buffer, /**< buffer of size nnodes */ int* Vzero, /**< zero weighted nodes */ int nVzero, /**< number of zero weighted nodes */ int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */ int* curcliquenodes, /**< nodes of the clique */ int* ncurcliquenodes /**< pointer to store number of nodes in the clique */ ) { int i; int* zerocands; int nzerocands; int nzeroextensions; assert(selectadjnodes != NULL); assert(buffer != NULL); assert(Vzero != NULL); assert(curcliquenodes != NULL); assert(ncurcliquenodes != NULL); debugMessage("extending temporary clique (size %d) with zero-weighted nodes (nVzero=%d)\n", *ncurcliquenodes, nVzero); if( maxnzeroextensions == 0 ) return; /* initialize the zero-weighted candidates for clique extension */ zerocands = buffer; BMScopyMemoryArray(zerocands, Vzero, nVzero); nzerocands = nVzero; /* for each node in the clique, remove non-adjacent nodes from the zero extension candidates */ for( i = 0; i < *ncurcliquenodes && nzerocands > 0; ++i ) { nzerocands = selectadjnodes(tcliquegraph, curcliquenodes[i], zerocands, nzerocands, zerocands); } /* put zero-weighted candidates into the clique, and remove non-adjacent nodes from the candidate set */ nzeroextensions = 0; while( nzerocands > 0 ) { /* put first candidate into the clique */ curcliquenodes[*ncurcliquenodes] = zerocands[0]; (*ncurcliquenodes)++; nzerocands--; zerocands++; nzeroextensions++; if( nzeroextensions >= maxnzeroextensions ) break; /* remove candidates that are not adjacent to the inserted zero-weighted node */ nzerocands = selectadjnodes(tcliquegraph, curcliquenodes[(*ncurcliquenodes)-1], zerocands, nzerocands, zerocands); } }
/** tries to insert the facet obtained from facet i flipped in component j into the list of the fmax nearest facets */ static void tryToInsert( SCIP* scip, /**< SCIP data structure */ SCIP_Bool** facets, /**< facets got so far */ SCIP_Real* lambda, /**< distances of the facets */ int i, /**< current facet */ int j, /**< component to flip */ int f_max, /**< maximal number of facets to create */ int nsubspacevars, /**< dimension of the fractional space */ SCIP_Real lam, /**< distance of the current facet */ int* nfacets /**< number of facets */ ) { SCIP_Bool* lastfacet; int k; assert(scip != NULL); assert(facets != NULL); assert(lambda != NULL); assert(nfacets != NULL); if( SCIPisFeasLE(scip, lam, 0.0) || SCIPisFeasGE(scip, lam, lambda[f_max-1]) ) return; lastfacet = facets[f_max]; /* shifting lam through lambda, lambda keeps increasingly sorted */ for( k = f_max; k > 0 && SCIPisFeasGT(scip, lambda[k-1], lam); --k ) { lambda[k] = lambda[k-1]; facets[k] = facets[k-1]; } assert(i < k && k < f_max ); /* inserting new facet into list, new facet is facet at position i flipped in coordinate j, new distance lam */ facets[k] = lastfacet; lambda[k] = lam; /*lint --e{866}*/ BMScopyMemoryArray(facets[k], facets[i], nsubspacevars); facets[k][j] = !facets[k][j]; (*nfacets)++; }
/** pass partial solution for indicator variables to heuristic */ SCIP_RETCODE SCIPheurPassIndicator( SCIP* scip, /**< SCIP data structure */ SCIP_HEUR* heur, /**< indicator heuristic */ int nindconss, /**< number of indicator constraints */ SCIP_CONS** indconss, /**< indicator constraints */ SCIP_Bool* solcand /**< values for indicator variables in partial solution */ ) { SCIP_HEURDATA* heurdata; assert( scip != NULL ); assert( heur != NULL ); assert( strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0 ); assert( nindconss > 0 ); assert( indconss != NULL ); assert( solcand != NULL ); /* get heuristic's data */ heurdata = SCIPheurGetData(heur); assert( heurdata != NULL ); /* copy indicator information */ if ( heurdata->indconss != NULL ) SCIPfreeBlockMemoryArray(scip, &(heurdata->indconss), heurdata->nindconss); SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(heurdata->indconss), indconss, nindconss) ); heurdata->nindconss = nindconss; /* copy partial solution */ if ( heurdata->solcand != NULL ) BMScopyMemoryArray(heurdata->solcand, solcand, nindconss); else SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(heurdata->solcand), solcand, nindconss) ); return SCIP_OKAY; }
/** creates a new tuple of solutions */ static SCIP_RETCODE createSolTuple( SCIP* scip, /**< original SCIP data structure */ SOLTUPLE** elem, /**< tuple of solutions which should be created */ int* indices, /**< indices of solutions */ int size, /**< number of solutions */ SCIP_HEURDATA* heurdata /**< primal heuristic data */ ) { /* memory allocation */ SCIP_CALL( SCIPallocBlockMemory(scip, elem) ); SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*elem)->indices,size) ); BMScopyMemoryArray((*elem)->indices, indices, size); /* data input */ sortArray(indices,size); (*elem)->size = size; (*elem)->key = calculateHashKey((*elem)->indices, (*elem)->size); (*elem)->prev = heurdata->lasttuple; /* update heurdata */ heurdata->lasttuple = *elem; return SCIP_OKAY; }
/** calls user callback after a new solution was found, that is better than the current incumbent; * the callback decides, whether this solution should be accepted as new incumbent, and whether the solution process * should be stopped */ static void newSolution( TCLIQUE_SELECTADJNODES((*selectadjnodes)), /**< user function to select adjacent edges */ TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */ TCLIQUE_NEWSOL ((*newsol)), /**< user function to call on every new solution */ TCLIQUE_DATA* tcliquedata, /**< user data to pass to user callback function */ CLIQUEHASH* cliquehash, /**< clique hash table */ int* buffer, /**< buffer of size nnodes */ int* Vzero, /**< zero weighted nodes */ int nVzero, /**< number of zero weighted nodes */ int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */ int* curcliquenodes, /**< nodes of the new clique */ int ncurcliquenodes, /**< number of nodes in the new clique */ TCLIQUE_WEIGHT curcliqueweight, /**< weight of the new clique */ int* maxcliquenodes, /**< pointer to store nodes of the maximum weight clique */ int* nmaxcliquenodes, /**< pointer to store number of nodes in the maximum weight clique */ TCLIQUE_WEIGHT* maxcliqueweight, /**< pointer to store weight of the maximum weight clique */ TCLIQUE_Bool* stopsolving /**< pointer to store whether the solving should be stopped */ ) { CLIQUE* clique; int insertpos; TCLIQUE_Bool acceptsol; assert(curcliquenodes != NULL); assert(maxcliquenodes != NULL); assert(nmaxcliquenodes != NULL); assert(maxcliqueweight != NULL); assert(curcliqueweight > *maxcliqueweight); assert(stopsolving != NULL); assert(newsol == NULL || cliquehash != NULL); acceptsol = TRUE; *stopsolving = FALSE; clique = NULL; insertpos = 0; if( newsol != NULL ) { /* check whether the clique is already stored in the table */ if( cliquehash->ncliques > 0 ) { createClique(&clique, curcliquenodes, ncurcliquenodes); acceptsol = !inCliquehash(cliquehash, clique, &insertpos); } } /* check, if this is a new clique */ if( acceptsol ) { /* extend the clique with the zero-weighted nodes */ extendCliqueZeroWeight(selectadjnodes, tcliquegraph, buffer, Vzero, nVzero, maxnzeroextensions, curcliquenodes, &ncurcliquenodes); if( newsol != NULL ) { /* call user callback method */ newsol(tcliquedata, curcliquenodes, ncurcliquenodes, curcliqueweight, maxcliqueweight, &acceptsol, stopsolving); /* if clique was accepted, clear the clique hash table; otherwise, insert it into the clique hash table, such that * the same or a weaker clique is not presented to the user again */ if( acceptsol ) clearCliquehash(cliquehash); else { /* if the clique was not yet created, do it now */ if( clique == NULL ) { assert(insertpos == 0); assert(cliquehash->ncliques == 0); createClique(&clique, curcliquenodes, ncurcliquenodes); } /* insert clique into clique hash table */ insertClique(cliquehash, clique, insertpos); clique = NULL; /* the clique now belongs to the table */ } } } /* free the clique, if it was created and not put into the clique hash table */ if( clique != NULL ) freeClique(&clique); if( acceptsol ) { /* copy the solution to the incumbent */ BMScopyMemoryArray(maxcliquenodes, curcliquenodes, ncurcliquenodes); *nmaxcliquenodes = ncurcliquenodes; if( curcliqueweight > *maxcliqueweight ) *maxcliqueweight = curcliqueweight; } #ifdef TCLIQUE_DEBUG debugMessage(" -> clique %s (weight %d):", acceptsol ? "accepted" : "rejected", curcliqueweight); { int i; for( i = 0; i < ncurcliquenodes; ++i ) debugPrintf(" %d", curcliquenodes[i]); debugPrintf("\n"); } #endif }
/** execution method of primal heuristic */ static SCIP_DECL_HEUREXEC(heurExecZirounding) { /*lint --e{715}*/ SCIP_HEURDATA* heurdata; SCIP_SOL* sol; SCIP_VAR** lpcands; SCIP_VAR** zilpcands; SCIP_VAR** slackvars; SCIP_Real* upslacks; SCIP_Real* downslacks; SCIP_Real* activities; SCIP_Real* slackvarcoeffs; SCIP_Bool* rowneedsslackvar; SCIP_ROW** rows; SCIP_Real* lpcandssol; SCIP_Real* solarray; SCIP_Longint nlps; int currentlpcands; int nlpcands; int nimplfracs; int i; int c; int nslacks; int nroundings; SCIP_RETCODE retcode; SCIP_Bool improvementfound; SCIP_Bool numericalerror; assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0); assert(result != NULL); assert(SCIPhasCurrentNodeLP(scip)); *result = SCIP_DIDNOTRUN; /* do not call heuristic of node was already detected to be infeasible */ if( nodeinfeasible ) return SCIP_OKAY; /* only call heuristic if an optimal LP-solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call heuristic, if the LP objective value is smaller than the cutoff bound */ if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation * to number of calls falls below heurdata->stoppercentage */ if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage ) return SCIP_OKAY; /* assure that heuristic has not already been called after the last LP had been solved */ nlps = SCIPgetNLPs(scip); if( nlps == heurdata->lastlp ) return SCIP_OKAY; heurdata->lastlp = nlps; /* get fractional variables */ SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) ); nlpcands = nlpcands + nimplfracs; /* make sure that there is at least one fractional variable that should be integral */ if( nlpcands == 0 ) return SCIP_OKAY; assert(nlpcands > 0); assert(lpcands != NULL); assert(lpcandssol != NULL); /* get LP rows data */ rows = SCIPgetLPRows(scip); nslacks = SCIPgetNLPRows(scip); /* cannot do anything if LP is empty */ if( nslacks == 0 ) return SCIP_OKAY; assert(rows != NULL); assert(nslacks > 0); /* get the working solution from heuristic's local data */ sol = heurdata->sol; assert(sol != NULL); *result = SCIP_DIDNOTFIND; solarray = NULL; zilpcands = NULL; retcode = SCIP_OKAY; /* copy the current LP solution to the working solution and allocate memory for local data */ SCIP_CALL( SCIPlinkLPSol(scip, sol) ); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &solarray, nlpcands), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &zilpcands, nlpcands), TERMINATE); /* copy necessary data to local arrays */ BMScopyMemoryArray(solarray, lpcandssol, nlpcands); BMScopyMemoryArray(zilpcands, lpcands, nlpcands); /* allocate buffer data arrays */ SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvars, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &upslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &downslacks, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks), TERMINATE); SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &activities, nslacks), TERMINATE); BMSclearMemoryArray(slackvars, nslacks); BMSclearMemoryArray(slackvarcoeffs, nslacks); BMSclearMemoryArray(rowneedsslackvar, nslacks); numericalerror = FALSE; nroundings = 0; /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */ for( c = 0; c < nlpcands; ++c ) { SCIP_VAR* cand; SCIP_ROW** candrows; int r; int ncandrows; cand = zilpcands[c]; assert(cand != NULL); assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0); candrows = SCIPcolGetRows(SCIPvarGetCol(cand)); ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand)); assert(candrows == NULL || ncandrows > 0); for( r = 0; r < ncandrows; ++r ) { int rowpos; assert(candrows != NULL); /* to please flexelint */ assert(candrows[r] != NULL); rowpos = SCIProwGetLPPos(candrows[r]); if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) ) { rowneedsslackvar[rowpos] = TRUE; SCIPdebugMessage(" Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand)); } } } /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero, * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering */ for( i = 0; i < nslacks; ++i ) { SCIP_ROW* row; SCIP_Real lhs; SCIP_Real rhs; row = rows[i]; assert(row != NULL); lhs = SCIProwGetLhs(row); rhs = SCIProwGetRhs(row); /* get row activity */ activities[i] = SCIPgetRowActivity(scip, row); assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs)); /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */ if( SCIPisInfinity(scip, -lhs) ) downslacks[i] = SCIPinfinity(scip); else downslacks[i] = activities[i] - lhs; if( SCIPisInfinity(scip, rhs) ) upslacks[i] = SCIPinfinity(scip); else upslacks[i] = rhs - activities[i]; SCIPdebugMessage("lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]); /* row is an equation. Try to find a slack variable in the row, i.e., * a continuous variable which occurs only in this row. If no such variable exists, * there is no hope for an IP-feasible solution in this round */ if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] ) { /* @todo: This is only necessary for rows containing fractional variables. */ rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i])); if( slackvars[i] == NULL ) { SCIPdebugMessage("No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row)); goto TERMINATE; } else { SCIP_Real ubslackvar; SCIP_Real lbslackvar; SCIP_Real solvalslackvar; SCIP_Real coeffslackvar; SCIP_Real ubgap; SCIP_Real lbgap; assert(SCIPvarGetType(slackvars[i]) == SCIP_VARTYPE_CONTINUOUS); solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]); ubslackvar = SCIPvarGetUbGlobal(slackvars[i]); lbslackvar = SCIPvarGetLbGlobal(slackvars[i]); coeffslackvar = slackvarcoeffs[i]; assert(!SCIPisFeasZero(scip, coeffslackvar)); ubgap = ubslackvar - solvalslackvar; lbgap = solvalslackvar - lbslackvar; if( SCIPisFeasZero(scip, ubgap) ) ubgap = 0.0; if( SCIPisFeasZero(scip, lbgap) ) lbgap = 0.0; if( SCIPisFeasPositive(scip, coeffslackvar) ) { if( !SCIPisInfinity(scip, lbslackvar) ) upslacks[i] += coeffslackvar * lbgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, ubslackvar) ) downslacks[i] += coeffslackvar * ubgap; else downslacks[i] = SCIPinfinity(scip); } else { if( !SCIPisInfinity(scip, ubslackvar) ) upslacks[i] -= coeffslackvar * ubgap; else upslacks[i] = SCIPinfinity(scip); if( !SCIPisInfinity(scip, lbslackvar) ) downslacks[i] -= coeffslackvar * lbgap; else downslacks[i] = SCIPinfinity(scip); } SCIPdebugMessage(" Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g \n", SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar, upslacks[i], downslacks[i]); } } /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are * significantly smaller than zero -> terminate */ if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) ) goto TERMINATE; } assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL)); /* initialize number of remaining variables and flag to enter the main loop */ currentlpcands = nlpcands; improvementfound = TRUE; /* iterate over variables as long as there are fractional variables left */ while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) ) { /*lint --e{850}*/ improvementfound = FALSE; nroundings++; SCIPdebugMessage("zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands); /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */ for( c = 0; c < currentlpcands; ++c ) { SCIP_VAR* var; SCIP_Real oldsolval; SCIP_Real upperbound; SCIP_Real lowerbound; SCIP_Real up; SCIP_Real down; SCIP_Real ziup; SCIP_Real zidown; SCIP_Real zicurrent; SCIP_Real shiftval; DIRECTION direction; /* get values from local data */ oldsolval = solarray[c]; var = zilpcands[c]; assert(!SCIPisFeasIntegral(scip, oldsolval)); assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN); /* calculate bounds for variable and make sure that there are no numerical inconsistencies */ upperbound = SCIPinfinity(scip); lowerbound = SCIPinfinity(scip); calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror); if( numericalerror ) goto TERMINATE; /* calculate the possible values after shifting */ up = oldsolval + upperbound; down = oldsolval - lowerbound; /* if the variable is integer or implicit binary, do not shift further than the nearest integer */ if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY) { SCIP_Real ceilx; SCIP_Real floorx; ceilx = SCIPfeasCeil(scip, oldsolval); floorx = SCIPfeasFloor(scip, oldsolval); up = MIN(up, ceilx); down = MAX(down, floorx); } /* calculate necessary values */ ziup = getZiValue(scip, up); zidown = getZiValue(scip, down); zicurrent = getZiValue(scip, oldsolval); /* calculate the shifting direction that reduces ZI-value the most, * if both directions improve ZI-value equally, take the direction which improves the objective */ if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) ) { if( SCIPisFeasEQ(scip,ziup, zidown) ) direction = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP; else if( SCIPisFeasLT(scip, zidown, ziup) ) direction = DIRECTION_DOWN; else direction = DIRECTION_UP; /* once a possible shifting direction and value have been found, variable value is updated */ shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval); /* this improves numerical stability in some cases */ if( direction == DIRECTION_UP ) shiftval = MIN(shiftval, upperbound); else shiftval = MIN(shiftval, lowerbound); /* update the solution */ solarray[c] = direction == DIRECTION_UP ? up : down; SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) ); /* update the rows activities and slacks */ SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks, downslacks, activities, slackvars, slackvarcoeffs, nslacks) ); SCIPdebugMessage("zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n", SCIPvarGetIndex(var), oldsolval, shiftval); /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement * might affect many LP rows and their current slacks and thus make further rounding steps possible */ improvementfound = TRUE; } /* if solution value of variable has become feasibly integral due to rounding step, * variable is put at the end of remaining candidates array so as not to be considered in future loops */ if( SCIPisFeasIntegral(scip, solarray[c]) ) { zilpcands[c] = zilpcands[currentlpcands - 1]; solarray[c] = solarray[currentlpcands - 1]; currentlpcands--; /* counter is decreased if end of candidates array has not been reached yet */ if( c < currentlpcands ) c--; } else if( nroundings == heurdata->maxroundingloops - 1 ) goto TERMINATE; } } /* in case that no candidate is left for rounding after the final main loop * the found solution has to be checked for feasibility in the original problem */ if( currentlpcands == 0 ) { SCIP_Bool stored; SCIP_CALL(SCIPtrySol(scip, sol, FALSE, FALSE, TRUE, FALSE, &stored)); if( stored ) { #ifdef SCIP_DEBUG SCIPdebugMessage("found feasible rounded solution:\n"); SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ); #endif SCIPstatisticMessage(" ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol)); *result = SCIP_FOUNDSOL; } } /* free memory for all locally allocated data */ TERMINATE: SCIPfreeBufferArrayNull(scip, &activities); SCIPfreeBufferArrayNull(scip, &rowneedsslackvar); SCIPfreeBufferArrayNull(scip, &slackvarcoeffs); SCIPfreeBufferArrayNull(scip, &downslacks); SCIPfreeBufferArrayNull(scip, &upslacks); SCIPfreeBufferArrayNull(scip, &slackvars); SCIPfreeBufferArrayNull(scip, &zilpcands); SCIPfreeBufferArrayNull(scip, &solarray); return retcode; }
/** colors the positive weighted nodes of a given set of nodes V with the lowest possible number of colors and * finds a clique in the graph induced by V, an upper bound and an apriori bound for further branching steps */ TCLIQUE_WEIGHT tcliqueColoring( TCLIQUE_GETNNODES((*getnnodes)), /**< user function to get the number of nodes */ TCLIQUE_GETWEIGHTS((*getweights)), /**< user function to get the node weights */ TCLIQUE_SELECTADJNODES((*selectadjnodes)), /**< user function to select adjacent edges */ TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */ BMS_CHKMEM* mem, /**< block memory */ int* buffer, /**< buffer of size nnodes */ int* V, /**< non-zero weighted nodes for branching */ int nV, /**< number of non-zero weighted nodes for branching */ NBC* gsd, /**< neighbor color information of all nodes */ TCLIQUE_Bool* iscolored, /**< coloring status of all nodes */ TCLIQUE_WEIGHT* apbound, /**< pointer to store apriori bound of nodes for branching */ int* clique, /**< buffer for storing the clique */ int* nclique, /**< pointer to store number of nodes in the clique */ TCLIQUE_WEIGHT* weightclique /**< pointer to store the weight of the clique */ ) { const TCLIQUE_WEIGHT* weights; TCLIQUE_WEIGHT maxsatdegree; TCLIQUE_WEIGHT range; TCLIQUE_Bool growclique; int node; int nodeVindex; int i; int j; LIST_ITV* colorinterval; LIST_ITV nwcitv; LIST_ITV* pnc; LIST_ITV* lcitv; LIST_ITV* item; LIST_ITV* tmpitem; int* workclique; int* currentclique; int ncurrentclique; int weightcurrentclique; int* Vadj; int nVadj; int adjidx; assert(getnnodes != NULL); assert(getweights != NULL); assert(selectadjnodes != NULL); assert(buffer != NULL); assert(V != NULL); assert(nV > 0); assert(clique != NULL); assert(nclique != NULL); assert(weightclique != NULL); assert(gsd != NULL); assert(iscolored != NULL); weights = getweights(tcliquegraph); assert(weights != NULL); /* initialize maximum weight clique found so far */ growclique = TRUE; *nclique = 0; *weightclique = 0; /* get node of V with maximum weight */ nodeVindex = getMaxWeightIndex(getnnodes, getweights, tcliquegraph, V, nV); node = V[nodeVindex]; assert(0 <= node && node < getnnodes(tcliquegraph)); range = weights[node]; assert(range > 0); /* set up data structures for coloring */ BMSclearMemoryArray(iscolored, nV); /* new-memory */ BMSclearMemoryArray(gsd, nV); /* new-memory */ iscolored[nodeVindex] = TRUE; /* color the first node */ debugMessage("---------------coloring-----------------\n"); debugMessage("1. node choosen: vindex=%d, vertex=%d, satdeg=%d, range=%d)\n", nodeVindex, node, gsd[nodeVindex].satdeg, range); /* set apriori bound: apbound(v_i) = satdeg(v_i) + weight(v_i) */ apbound[nodeVindex] = range; assert(apbound[nodeVindex] > 0); /* update maximum saturation degree: maxsatdeg = max { satdeg(v_i) + weight(v_i) | v_i in V } */ maxsatdegree = range; debugMessage("-> updated neighbors:\n"); /* set neighbor color of the adjacent nodes of node */ Vadj = buffer; nVadj = selectadjnodes(tcliquegraph, node, V, nV, Vadj); for( i = 0, adjidx = 0; i < nV && adjidx < nVadj; ++i ) { assert(V[i] <= Vadj[adjidx]); /* Vadj is a subset of V */ if( V[i] == Vadj[adjidx] ) { /* node is adjacent to itself, but we do not need to color it again */ if( i == nodeVindex ) { /* go to the next node in Vadj */ adjidx++; continue; } debugMessage(" nodeVindex=%d, node=%d, weight=%d, satdegold=%d -> ", i, V[i], weights[V[i]], gsd[i].satdeg); /* sets satdeg for adjacent node */ gsd[i].satdeg = range; /* creates new color interval [1,range] */ ALLOC_ABORT( BMSallocChunkMemory(mem, &colorinterval) ); colorinterval->next = NULL; colorinterval->itv.inf = 1; colorinterval->itv.sup = range; /* colorinterval is the first added element of the list of neighborcolors of the adjacent node */ gsd[i].lcitv = colorinterval; /* go to the next node in Vadj */ adjidx++; debugPrintf("satdegnew=%d, nbc=[%d,%d]\n", gsd[i].satdeg, gsd[i].lcitv->itv.inf, gsd[i].lcitv->itv.sup); } } /* set up data structures for the current clique */ ALLOC_ABORT( BMSallocMemoryArray(¤tclique, nV) ); workclique = clique; /* add node to the current clique */ currentclique[0] = node; ncurrentclique = 1; weightcurrentclique = range; /* color all other nodes of V */ for( i = 0 ; i < nV-1; i++ ) { assert((workclique == clique) != (currentclique == clique)); /* selects the next uncolored node to color */ nodeVindex = getMaxSatdegIndex(V, nV, gsd, iscolored, weights); if( nodeVindex == -1 ) /* no uncolored nodes left */ break; node = V[nodeVindex]; assert(0 <= node && node < getnnodes(tcliquegraph)); range = weights[node]; assert(range > 0); iscolored[nodeVindex] = TRUE; debugMessage("%d. node choosen: vindex=%d, vertex=%d, satdeg=%d, range=%d, growclique=%u, weight=%d)\n", i+2, nodeVindex, node, gsd[nodeVindex].satdeg, range, growclique, weightcurrentclique); /* set apriori bound: apbound(v_i) = satdeg(v_i) + weight(v_i) */ apbound[nodeVindex] = gsd[nodeVindex].satdeg + range; assert(apbound[nodeVindex] > 0); /* update maximum saturation degree: maxsatdeg = max { satdeg(v_i) + weight(v_i) | v_i in V } */ if( maxsatdegree < apbound[nodeVindex] ) maxsatdegree = apbound[nodeVindex]; /* update clique */ if( gsd[nodeVindex].satdeg == 0 ) { /* current node is not adjacent to nodes of current clique, * i.e. current clique can not be increased */ debugMessage("current node not adjacend to current clique (weight:%d) -> starting new clique\n", weightcurrentclique); /* check, if weight of current clique is larger than weight of maximum weight clique found so far */ if( weightcurrentclique > *weightclique ) { int* tmp; /* update maximum weight clique found so far */ assert((workclique == clique) != (currentclique == clique)); tmp = workclique; *weightclique = weightcurrentclique; *nclique = ncurrentclique; workclique = currentclique; currentclique = tmp; assert((workclique == clique) != (currentclique == clique)); } weightcurrentclique = 0; ncurrentclique = 0; growclique = TRUE; } if( growclique ) { /* check, if the current node is still adjacent to all nodes in the clique */ if( gsd[nodeVindex].satdeg == weightcurrentclique ) { assert(ncurrentclique < nV); currentclique[ncurrentclique] = node; ncurrentclique++; weightcurrentclique += range; #ifdef TCLIQUE_DEBUG { int k; debugMessage("current clique (size:%d, weight:%d):", ncurrentclique, weightcurrentclique); for( k = 0; k < ncurrentclique; ++k ) debugPrintf(" %d", currentclique[k]); debugPrintf("\n"); } #endif } else { debugMessage("node satdeg: %d, clique weight: %d -> stop growing clique\n", gsd[nodeVindex].satdeg, weightcurrentclique); growclique = FALSE; } } /* search for fitting color intervals for current node */ pnc = &nwcitv; if( gsd[nodeVindex].lcitv == NULL ) { /* current node has no colored neighbors yet: create new color interval [1,range] */ ALLOC_ABORT( BMSallocChunkMemory(mem, &colorinterval) ); colorinterval->next = NULL; colorinterval->itv.inf = 1; colorinterval->itv.sup = range; /* add the new colorinterval [1, range] to the list of chosen colorintervals for node */ pnc->next = colorinterval; pnc = colorinterval; } else { int tocolor; int dif; /* current node has colored neighbors */ tocolor = range; lcitv = gsd[nodeVindex].lcitv; /* check, if first neighbor color interval [inf, sup] has inf > 1 */ if( lcitv->itv.inf != 1 ) { /* create new interval [1, min{range, inf}] */ dif = lcitv->itv.inf - 1 ; if( dif > tocolor ) dif = tocolor; ALLOC_ABORT( BMSallocChunkMemory(mem, &colorinterval) ); colorinterval->next = NULL; colorinterval->itv.inf = 1; colorinterval->itv.sup = dif; tocolor -= dif; pnc->next = colorinterval; pnc = colorinterval; } /* as long as node is not colored with all colors, create new color interval by filling * the gaps in the existing neighbor color intervals of the neighbors of node */ while( tocolor > 0 ) { dif = tocolor; ALLOC_ABORT( BMSallocChunkMemory(mem, &colorinterval) ); colorinterval->next = NULL; colorinterval->itv.inf = lcitv->itv.sup+1; if( lcitv->next != NULL ) { int min; min = lcitv->next->itv.inf - lcitv->itv.sup - 1; if( dif > min ) dif = min; lcitv = lcitv->next; } colorinterval->itv.sup = colorinterval->itv.inf + dif - 1; tocolor -= dif; pnc->next = colorinterval; pnc = colorinterval; } } debugMessage("-> updated neighbors:\n"); /* update saturation degree and neighbor colorintervals of all neighbors of node */ Vadj = buffer; nVadj = selectadjnodes(tcliquegraph, node, V, nV, Vadj); for( j = 0, adjidx = 0; j < nV && adjidx < nVadj; ++j ) { assert(V[j] <= Vadj[adjidx]); /* Vadj is a subset of V */ if( V[j] == Vadj[adjidx] ) { if( !iscolored[j] ) { debugMessage(" nodeVindex=%d, node=%d, weight=%d, satdegold=%d -> ", j, V[j], weights[V[j]], gsd[j].satdeg); updateNeighbor(mem, &gsd[j], nwcitv.next); debugPrintf("satdegnew=%d, nbc=[%d,%d]\n", gsd[j].satdeg, gsd[j].lcitv->itv.inf, gsd[j].lcitv->itv.sup); } /* go to the next node in Vadj */ adjidx++; } } /* free data structure of created colorintervals */ item = nwcitv.next; while( item != NULL ) { tmpitem = item->next; BMSfreeChunkMemory(mem, &item); item = tmpitem; } /* free data structure of neighbor colorinterval of node just colored */ item = gsd[nodeVindex].lcitv; while( item != NULL ) { tmpitem = item->next; BMSfreeChunkMemory(mem, &item); item = tmpitem; } } assert((workclique == clique) != (currentclique == clique)); /* update maximum weight clique found so far */ if( weightcurrentclique > *weightclique ) { int* tmp; tmp = workclique; *weightclique = weightcurrentclique; *nclique = ncurrentclique; workclique = currentclique; currentclique = tmp; } assert((workclique == clique) != (currentclique == clique)); /* move the found clique to the provided clique pointer, if it is not the memory array */ if( workclique != clique ) { assert(clique == currentclique); assert(*nclique <= nV); BMScopyMemoryArray(clique, workclique, *nclique); currentclique = workclique; } /* free data structures */ BMSfreeMemoryArray(¤tclique); /* clear chunk memory */ BMSclearChunkMemory(mem); debugMessage("------------coloringend-----------------\n"); return maxsatdegree; }
/** 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; }