/** copy method for separator plugins (called when SCIP copies plugins) */ static SCIP_DECL_SEPACOPY(sepaCopyDisjunctive) { assert( scip != NULL ); assert( sepa != NULL ); assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 ); /* call inclusion method of constraint handler */ SCIP_CALL( SCIPincludeSepaDisjunctive(scip) ); return SCIP_OKAY; }
/** copy method for separator plugins (called when SCIP copies plugins) */ static SCIP_DECL_SEPACOPY(sepaCopyIntobj) { /*lint --e{715}*/ assert(scip != NULL); assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); /* call inclusion method of constraint handler */ SCIP_CALL( SCIPincludeSepaIntobj(scip) ); return SCIP_OKAY; }
/** copies the given separator to a new scip */ SCIP_RETCODE SCIPsepaCopyInclude( SCIP_SEPA* sepa, /**< separator */ SCIP_SET* set /**< SCIP_SET of SCIP to copy to */ ) { assert(sepa != NULL); assert(set != NULL); assert(set->scip != NULL); if( sepa->sepacopy != NULL ) { SCIPdebugMessage("including separator %s in subscip %p\n", SCIPsepaGetName(sepa), (void*)set->scip); SCIP_CALL( sepa->sepacopy(set->scip, sepa) ); } return SCIP_OKAY; }
/** destructor of separator to free user data (called when SCIP is exiting) */ static SCIP_DECL_SEPAFREE(sepaFreeGomory) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); /* free separator data */ sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); SCIPfreeMemory(scip, &sepadata); SCIPsepaSetData(sepa, NULL); return SCIP_OKAY; }
/** solving process deinitialization method of separator (called before branch and bound process data is freed) */ static SCIP_DECL_SEPAEXITSOL(sepaExitsolClosecuts) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; assert( sepa != NULL ); assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 ); sepadata = SCIPsepaGetData(sepa); assert( sepadata != NULL ); if ( sepadata->separelint && sepadata->sepasol != NULL ) { SCIP_CALL( SCIPfreeSol(scip, &sepadata->sepasol) ); } return SCIP_OKAY; }
/** destructor of separator to free user data (called when SCIP is exiting) */ static SCIP_DECL_SEPAFREE(sepaFreeImpliedbounds) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; assert(scip != NULL); assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); /* get separation data and free it */ sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); SCIPfreeMemory(scip, &sepadata); /* reset data pointer to NULL */ SCIPsepaSetData(sepa, NULL); return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpClosecuts) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_Longint currentnodenumber; SCIP_Bool isroot; assert( sepa != NULL ); assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; /* only call separator, if there are fractional variables */ if ( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; sepadata = SCIPsepaGetData(sepa); assert( sepadata != NULL ); currentnodenumber = SCIPnodeGetNumber(SCIPgetCurrentNode(scip)); if ( sepadata->discardnode == currentnodenumber ) return SCIP_OKAY; isroot = FALSE; if (SCIPgetNNodes(scip) == 0) isroot = TRUE; /* only separate close cuts in the root if required */ if ( sepadata->separootonly || isroot ) { SCIP_SOL* point = NULL; SCIPdebugMessage("Separation method of closecuts separator.\n"); *result = SCIP_DIDNOTFIND; /* check whether we have to compute a relative interior point */ if ( sepadata->separelint ) { /* check if previous relative interior point should be forgotten, * otherwise it is computed only once and the same point is used for all nodes */ if ( sepadata->recomputerelint && sepadata->sepasol != NULL ) { SCIP_CALL( SCIPfreeSol(scip, &sepadata->sepasol) ); } if ( sepadata->sepasol == NULL ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, 0, "Computing relative interior point (norm type: %c) ...\n", sepadata->relintnormtype); assert(sepadata->relintnormtype == 'o' || sepadata->relintnormtype == 's'); SCIP_CALL( SCIPcomputeLPRelIntPoint(scip, TRUE, sepadata->inclobjcutoff, sepadata->relintnormtype, &sepadata->sepasol) ); } } else { /* get best solution (NULL if not present) */ sepadata->sepasol = SCIPgetBestSol(scip); } /* separate close cuts */ if ( sepadata->sepasol != NULL ) { SCIPdebugMessage("Generating close cuts ... (combination value: %f)\n", sepadata->sepacombvalue); /* generate point to be separated */ SCIP_CALL( generateCloseCutPoint(scip, sepadata, &point) ); /* apply a separation round to generated point */ if ( point != NULL ) { int noldcuts; SCIP_Bool delayed; SCIP_Bool cutoff; noldcuts = SCIPgetNCuts(scip); SCIP_CALL( SCIPseparateSol(scip, point, isroot, FALSE, &delayed, &cutoff) ); SCIP_CALL( SCIPfreeSol(scip, &point) ); assert( point == NULL ); /* the cuts can be not violated by the current LP if the computed point is strange */ SCIP_CALL( SCIPremoveInefficaciousCuts(scip) ); if ( cutoff ) *result = SCIP_CUTOFF; else { if ( SCIPgetNCuts(scip) - noldcuts > sepadata->sepathreshold ) { sepadata->nunsuccessful = 0; *result = SCIP_NEWROUND; } else { if ( SCIPgetNCuts(scip) > noldcuts ) { sepadata->nunsuccessful = 0; *result = SCIP_SEPARATED; } else ++sepadata->nunsuccessful; } } SCIPdebugMessage("Separated close cuts: %d (enoughcuts: %d, unsuccessful: %d).\n", SCIPgetNCuts(scip) - noldcuts, SCIPgetNCuts(scip) - noldcuts > sepadata->sepathreshold, sepadata->nunsuccessful); if ( sepadata->maxunsuccessful >= 0 && sepadata->nunsuccessful > sepadata->maxunsuccessful ) { SCIPdebugMessage("Turn off close cut separation, because of %d unsuccessful calls.\n", sepadata->nunsuccessful); sepadata->discardnode = currentnodenumber; } } } } return SCIP_OKAY; }
/** LP solution separation method of separator */ static SCIP_DECL_SEPAEXECLP(sepaExeclpGomory) { /*lint --e{715}*/ SCIP_SEPADATA* sepadata; SCIP_VAR** vars; SCIP_COL** cols; SCIP_ROW** rows; SCIP_Real* binvrow; SCIP_Real* cutcoefs; SCIP_Real maxscale; SCIP_Real minfrac; SCIP_Real maxfrac; SCIP_Longint maxdnom; SCIP_Bool cutoff; int* basisind; int naddedcuts; int nvars; int ncols; int nrows; int ncalls; int depth; int maxdepth; int maxsepacuts; int c; int i; assert(sepa != NULL); assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0); assert(scip != NULL); assert(result != NULL); *result = SCIP_DIDNOTRUN; sepadata = SCIPsepaGetData(sepa); assert(sepadata != NULL); depth = SCIPgetDepth(scip); ncalls = SCIPsepaGetNCallsAtNode(sepa); minfrac = sepadata->away; maxfrac = 1.0 - sepadata->away; /* only call separator, if we are not close to terminating */ if( SCIPisStopped(scip) ) return SCIP_OKAY; /* only call the gomory cut separator a given number of times at each node */ if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) ) return SCIP_OKAY; /* only call separator, if an optimal LP solution is at hand */ if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only call separator, if the LP solution is basic */ if( !SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* only call separator, if there are fractional variables */ if( SCIPgetNLPBranchCands(scip) == 0 ) return SCIP_OKAY; /* get variables data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* get LP data */ SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); if( ncols == 0 || nrows == 0 ) return SCIP_OKAY; #if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */ if( ncols >= 50*nrows ) return SCIP_OKAY; if( ncols >= 5*nrows ) { int ncutsfound; ncutsfound = SCIPgetNCutsFound(scip); if( ncutsfound > sepadata->lastncutsfound || !SCIPsepaWasLPDelayed(sepa) ) { sepadata->lastncutsfound = ncutsfound; *result = SCIP_DELAYED; return SCIP_OKAY; } } #endif /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to * scale resulting cut to integral values to avoid numerical instabilities */ /**@todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */ maxdepth = SCIPgetMaxDepth(scip); if( depth == 0 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/4 ) { maxdnom = 1000; maxscale = 1000.0; } else if( depth <= maxdepth/2 ) { maxdnom = 100; maxscale = 100.0; } else { maxdnom = 10; maxscale = 10.0; } /* allocate temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) ); /* get basis indices */ SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* get the maximal number of cuts allowed in a separation round */ if( depth == 0 ) maxsepacuts = sepadata->maxsepacutsroot; else maxsepacuts = sepadata->maxsepacuts; SCIPdebugMessage("searching gomory cuts: %d cols, %d rows, maxdnom=%"SCIP_LONGINT_FORMAT", maxscale=%g, maxcuts=%d\n", ncols, nrows, maxdnom, maxscale, maxsepacuts); cutoff = FALSE; naddedcuts = 0; /* for all basic columns belonging to integer variables, try to generate a gomory cut */ for( i = 0; i < nrows && naddedcuts < maxsepacuts && !SCIPisStopped(scip) && !cutoff; ++i ) { SCIP_Bool tryrow; tryrow = FALSE; c = basisind[i]; if( c >= 0 ) { SCIP_VAR* var; assert(c < ncols); var = SCIPcolGetVar(cols[c]); if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ) { SCIP_Real primsol; primsol = SCIPcolGetPrimsol(cols[c]); assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/ if( SCIPfeasFrac(scip, primsol) >= minfrac ) { SCIPdebugMessage("trying gomory cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol); tryrow = TRUE; } } } else if( sepadata->separaterows ) { SCIP_ROW* row; assert(0 <= -c-1 && -c-1 < nrows); row = rows[-c-1]; if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) ) { SCIP_Real primsol; primsol = SCIPgetRowActivity(scip, row); if( SCIPfeasFrac(scip, primsol) >= minfrac ) { SCIPdebugMessage("trying gomory cut for row <%s> [%g]\n", SCIProwGetName(row), primsol); tryrow = TRUE; } } } if( tryrow ) { SCIP_Real cutrhs; SCIP_Real cutact; SCIP_Bool success; SCIP_Bool cutislocal; /* get the row of B^-1 for this basic integer variable with fractional solution value */ SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow) ); cutact = 0.0; cutrhs = SCIPinfinity(scip); /* create a MIR cut out of the weighted LP rows using the B^-1 row as weights */ SCIP_CALL( SCIPcalcMIR(scip, NULL, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, FIXINTEGRALRHS, NULL, NULL, (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, minfrac, maxfrac, binvrow, 1.0, NULL, NULL, cutcoefs, &cutrhs, &cutact, &success, &cutislocal) ); assert(ALLOWLOCAL || !cutislocal); /* @todo Currently we are using the SCIPcalcMIR() function to compute the coefficients of the Gomory * cut. Alternatively, we could use the direct version (see thesis of Achterberg formula (8.4)) which * leads to cut a of the form \sum a_i x_i \geq 1. Rumor has it that these cuts are better. */ SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs); /* if successful, convert dense cut into sparse row, and add the row as a cut */ if( success && SCIPisFeasGT(scip, cutact, cutrhs) ) { SCIP_ROW* cut; char cutname[SCIP_MAXSTRLEN]; int v; /* construct cut name */ if( c >= 0 ) (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_x%d", SCIPgetNLPs(scip), c); else (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_s%d", SCIPgetNLPs(scip), -c-1); /* create empty cut */ SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) ); /* cache the row extension and only flush them if the cut gets added */ SCIP_CALL( SCIPcacheRowExtensions(scip, cut) ); /* collect all non-zero coefficients */ for( v = 0; v < nvars; ++v ) { if( !SCIPisZero(scip, cutcoefs[v]) ) { SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[v], cutcoefs[v]) ); } } if( SCIProwGetNNonz(cut) == 0 ) { assert(SCIPisFeasNegative(scip, cutrhs)); SCIPdebugMessage(" -> gomory cut detected infeasibility with cut 0 <= %f\n", cutrhs); cutoff = TRUE; } else if( SCIProwGetNNonz(cut) == 1 ) { /* add the bound change as cut to avoid that the LP gets modified. that would mean the LP is not flushed * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply that bound change automatically */ SCIP_CALL( SCIPaddCut(scip, NULL, cut, TRUE) ); naddedcuts++; } else { /* Only take efficacious cuts, except for cuts with one non-zero coefficients (= bound * changes); the latter cuts will be handeled internally in sepastore. */ if( SCIPisCutEfficacious(scip, NULL, cut) ) { assert(success == TRUE); SCIPdebugMessage(" -> gomory cut for <%s>: act=%f, rhs=%f, eff=%f\n", c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]), cutact, cutrhs, SCIPgetCutEfficacy(scip, NULL, cut)); if( sepadata->makeintegral ) { /* try to scale the cut to integral values */ SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, MAKECONTINTEGRAL, &success) ); if( sepadata->forcecuts ) success = TRUE; /* in case the left hand side in minus infinity and the right hand side is plus infinity the cut is * useless so we are not taking it at all */ if( (SCIPisInfinity(scip, -SCIProwGetLhs(cut)) && SCIPisInfinity(scip, SCIProwGetRhs(cut))) ) success = FALSE; /* @todo Trying to make the Gomory cut integral might fail. Due to numerical reasons/arguments we * currently ignore such cuts. If the cut, however, has small support (let's say smaller or equal to * 5), we might want to add that cut (even it does not have integral coefficients). To be able to * do that we need to add a rank to the data structure of a row. The rank of original rows are * zero and for aggregated rows it is the maximum over all used rows plus one. */ } if( success ) { SCIPdebugMessage(" -> found gomory cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut), SCIPgetCutEfficacy(scip, NULL, cut), SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut)); /* flush all changes before adding the cut */ SCIP_CALL( SCIPflushRowExtensions(scip, cut) ); /* add global cuts which are not implicit bound changes to the cut pool */ if( !cutislocal ) { if( sepadata->delayedcuts ) { SCIP_CALL( SCIPaddDelayedPoolCut(scip, cut) ); } else { SCIP_CALL( SCIPaddPoolCut(scip, cut) ); } } else { /* local cuts we add to the sepastore */ SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE) ); } naddedcuts++; } } } /* release the row */ SCIP_CALL( SCIPreleaseRow(scip, &cut) ); } } } /* free temporary memory */ SCIPfreeBufferArray(scip, &binvrow); SCIPfreeBufferArray(scip, &basisind); SCIPfreeBufferArray(scip, &cutcoefs); SCIPdebugMessage("end searching gomory cuts: found %d cuts\n", naddedcuts); sepadata->lastncutsfound = SCIPgetNCutsFound(scip); /* evalute the result of the separation */ if( cutoff ) *result = SCIP_CUTOFF; else if ( naddedcuts > 0 ) *result = SCIP_SEPARATED; else *result = SCIP_DIDNOTFIND; return SCIP_OKAY; }
/** LP solution separation method for disjunctive cuts */ static SCIP_DECL_SEPAEXECLP(sepaExeclpDisjunctive) { SCIP_SEPADATA* sepadata; SCIP_CONSHDLR* conshdlr; SCIP_DIGRAPH* conflictgraph; SCIP_ROW** rows; SCIP_COL** cols; SCIP_Real* cutcoefs = NULL; SCIP_Real* simplexcoefs1 = NULL; SCIP_Real* simplexcoefs2 = NULL; SCIP_Real* coef = NULL; SCIP_Real* binvrow = NULL; SCIP_Real* rowsmaxval = NULL; SCIP_Real* violationarray = NULL; int* fixings1 = NULL; int* fixings2 = NULL; int* basisind = NULL; int* basisrow = NULL; int* varrank = NULL; int* edgearray = NULL; int nedges; int ndisjcuts; int nrelevantedges; int nsos1vars; int nconss; int maxcuts; int ncalls; int depth; int ncols; int nrows; int ind; int j; int i; assert( sepa != NULL ); assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 ); assert( scip != NULL ); assert( result != NULL ); *result = SCIP_DIDNOTRUN; /* only generate disjunctive cuts if we are not close to terminating */ if ( SCIPisStopped(scip) ) return SCIP_OKAY; /* only generate disjunctive cuts if an optimal LP solution is at hand */ if ( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL ) return SCIP_OKAY; /* only generate disjunctive cuts if the LP solution is basic */ if ( ! SCIPisLPSolBasic(scip) ) return SCIP_OKAY; /* get LP data */ SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) ); SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) ); /* return if LP has no columns or no rows */ if ( ncols == 0 || nrows == 0 ) return SCIP_OKAY; assert( cols != NULL ); assert( rows != NULL ); /* get sepa data */ sepadata = SCIPsepaGetData(sepa); assert( sepadata != NULL ); /* get constraint handler */ conshdlr = sepadata->conshdlr; if ( conshdlr == NULL ) return SCIP_OKAY; /* get number of constraints */ nconss = SCIPconshdlrGetNConss(conshdlr); if ( nconss == 0 ) return SCIP_OKAY; /* check for maxdepth < depth, maxinvcutsroot = 0 and maxinvcuts = 0 */ depth = SCIPgetDepth(scip); if ( ( sepadata->maxdepth >= 0 && sepadata->maxdepth < depth ) || ( depth == 0 && sepadata->maxinvcutsroot == 0 ) || ( depth > 0 && sepadata->maxinvcuts == 0 ) ) return SCIP_OKAY; /* only call the cut separator a given number of times at each node */ ncalls = SCIPsepaGetNCallsAtNode(sepa); if ( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) ) return SCIP_OKAY; /* get conflict graph and number of conflict graph edges (note that the digraph arcs were added in both directions) */ conflictgraph = SCIPgetConflictgraphSOS1(conshdlr); nedges = (int)SCIPceil(scip, (SCIP_Real)SCIPdigraphGetNArcs(conflictgraph)/2); /* if too many conflict graph edges, the separator can be slow: delay it until no other cuts have been found */ if ( sepadata->maxconfsdelay >= 0 && nedges >= sepadata->maxconfsdelay ) { int ncutsfound; ncutsfound = SCIPgetNCutsFound(scip); if ( ncutsfound > sepadata->lastncutsfound || ! SCIPsepaWasLPDelayed(sepa) ) { sepadata->lastncutsfound = ncutsfound; *result = SCIP_DELAYED; return SCIP_OKAY; } } /* check basis status */ for (j = 0; j < ncols; ++j) { if ( SCIPcolGetBasisStatus(cols[j]) == SCIP_BASESTAT_ZERO ) return SCIP_OKAY; } /* get number of SOS1 variables */ nsos1vars = SCIPgetNSOS1Vars(conshdlr); /* allocate buffer arrays */ SCIP_CALL( SCIPallocBufferArray(scip, &edgearray, nedges) ); SCIP_CALL( SCIPallocBufferArray(scip, &fixings1, nedges) ); SCIP_CALL( SCIPallocBufferArray(scip, &fixings2, nedges) ); SCIP_CALL( SCIPallocBufferArray(scip, &violationarray, nedges) ); /* get all violated conflicts {i, j} in the conflict graph and sort them based on the degree of a violation value */ nrelevantedges = 0; for (j = 0; j < nsos1vars; ++j) { SCIP_VAR* var; var = SCIPnodeGetVarSOS1(conflictgraph, j); if ( SCIPvarIsActive(var) && ! SCIPisFeasZero(scip, SCIPcolGetPrimsol(SCIPvarGetCol(var))) && SCIPcolGetBasisStatus(SCIPvarGetCol(var)) == SCIP_BASESTAT_BASIC ) { int* succ; int nsucc; /* get successors and number of successors */ nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j); succ = SCIPdigraphGetSuccessors(conflictgraph, j); for (i = 0; i < nsucc; ++i) { SCIP_VAR* varsucc; int succind; succind = succ[i]; varsucc = SCIPnodeGetVarSOS1(conflictgraph, succind); if ( SCIPvarIsActive(varsucc) && succind < j && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, varsucc) ) && SCIPcolGetBasisStatus(SCIPvarGetCol(varsucc)) == SCIP_BASESTAT_BASIC ) { fixings1[nrelevantedges] = j; fixings2[nrelevantedges] = succind; edgearray[nrelevantedges] = nrelevantedges; violationarray[nrelevantedges++] = SCIPgetSolVal(scip, NULL, var) * SCIPgetSolVal(scip, NULL, varsucc); } } } } /* sort violation score values */ if ( nrelevantedges > 0) SCIPsortDownRealInt(violationarray, edgearray, nrelevantedges); else { SCIPfreeBufferArrayNull(scip, &violationarray); SCIPfreeBufferArrayNull(scip, &fixings2); SCIPfreeBufferArrayNull(scip, &fixings1); SCIPfreeBufferArrayNull(scip, &edgearray); return SCIP_OKAY; } SCIPfreeBufferArrayNull(scip, &violationarray); /* compute maximal number of cuts */ if ( SCIPgetDepth(scip) == 0 ) maxcuts = MIN(sepadata->maxinvcutsroot, nrelevantedges); else maxcuts = MIN(sepadata->maxinvcuts, nrelevantedges); assert( maxcuts > 0 ); /* allocate buffer arrays */ SCIP_CALL( SCIPallocBufferArray(scip, &varrank, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &rowsmaxval, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisrow, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) ); SCIP_CALL( SCIPallocBufferArray(scip, &coef, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &simplexcoefs1, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &simplexcoefs2, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, ncols) ); SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) ); /* get basis indices */ SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) ); /* create vector "basisrow" with basisrow[column of non-slack basis variable] = corresponding row of B^-1; * compute maximum absolute value of nonbasic row coefficients */ for (j = 0; j < nrows; ++j) { SCIP_COL** rowcols; SCIP_Real* rowvals; SCIP_ROW* row; SCIP_Real val; SCIP_Real max = 0.0; int nnonz; /* fill basisrow vector */ ind = basisind[j]; if ( ind >= 0 ) basisrow[ind] = j; /* compute maximum absolute value of nonbasic row coefficients */ row = rows[j]; assert( row != NULL ); rowvals = SCIProwGetVals(row); nnonz = SCIProwGetNNonz(row); rowcols = SCIProwGetCols(row); for (i = 0; i < nnonz; ++i) { if ( SCIPcolGetBasisStatus(rowcols[i]) == SCIP_BASESTAT_LOWER || SCIPcolGetBasisStatus(rowcols[i]) == SCIP_BASESTAT_UPPER ) { val = REALABS(rowvals[i]); if ( SCIPisFeasGT(scip, val, max) ) max = REALABS(val); } } /* handle slack variable coefficient and save maximum value */ rowsmaxval[j] = MAX(max, 1.0); } /* initialize variable ranks with -1 */ for (j = 0; j < ncols; ++j) varrank[j] = -1; /* free buffer array */ SCIPfreeBufferArrayNull(scip, &basisind); /* for the most promising disjunctions: try to generate disjunctive cuts */ ndisjcuts = 0; for (i = 0; i < maxcuts; ++i) { SCIP_Bool madeintegral; SCIP_Real cutlhs1; SCIP_Real cutlhs2; SCIP_Real bound1; SCIP_Real bound2; SCIP_ROW* row = NULL; SCIP_VAR* var; SCIP_COL* col; int nonbasicnumber; int cutrank = 0; int edgenumber; int rownnonz; edgenumber = edgearray[i]; /* determine first simplex row */ var = SCIPnodeGetVarSOS1(conflictgraph, fixings1[edgenumber]); col = SCIPvarGetCol(var); ind = SCIPcolGetLPPos(col); assert( ind >= 0 ); assert( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_BASIC ); /* get the 'ind'th row of B^-1 and B^-1 \cdot A */ SCIP_CALL( SCIPgetLPBInvRow(scip, basisrow[ind], binvrow, NULL, NULL) ); SCIP_CALL( SCIPgetLPBInvARow(scip, basisrow[ind], binvrow, coef, NULL, NULL) ); /* get the simplex-coefficients of the non-basic variables */ SCIP_CALL( getSimplexCoefficients(scip, rows, nrows, cols, ncols, coef, binvrow, simplexcoefs1, &nonbasicnumber) ); /* get rank of variable if not known already */ if ( varrank[ind] < 0 ) varrank[ind] = getVarRank(scip, binvrow, rowsmaxval, sepadata->maxweightrange, rows, nrows); cutrank = MAX(cutrank, varrank[ind]); /* get right hand side and bound of simplex talbeau row */ cutlhs1 = SCIPcolGetPrimsol(col); if ( SCIPisFeasPositive(scip, cutlhs1) ) bound1 = SCIPcolGetUb(col); else bound1 = SCIPcolGetLb(col); /* determine second simplex row */ var = SCIPnodeGetVarSOS1(conflictgraph, fixings2[edgenumber]); col = SCIPvarGetCol(var); ind = SCIPcolGetLPPos(col); assert( ind >= 0 ); assert( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_BASIC ); /* get the 'ind'th row of B^-1 and B^-1 \cdot A */ SCIP_CALL( SCIPgetLPBInvRow(scip, basisrow[ind], binvrow, NULL, NULL) ); SCIP_CALL( SCIPgetLPBInvARow(scip, basisrow[ind], binvrow, coef, NULL, NULL) ); /* get the simplex-coefficients of the non-basic variables */ SCIP_CALL( getSimplexCoefficients(scip, rows, nrows, cols, ncols, coef, binvrow, simplexcoefs2, &nonbasicnumber) ); /* get rank of variable if not known already */ if ( varrank[ind] < 0 ) varrank[ind] = getVarRank(scip, binvrow, rowsmaxval, sepadata->maxweightrange, rows, nrows); cutrank = MAX(cutrank, varrank[ind]); /* get right hand side and bound of simplex talbeau row */ cutlhs2 = SCIPcolGetPrimsol(col); if ( SCIPisFeasPositive(scip, cutlhs2) ) bound2 = SCIPcolGetUb(col); else bound2 = SCIPcolGetLb(col); /* add coefficients to cut */ SCIP_CALL( generateDisjCutSOS1(scip, sepa, rows, nrows, cols, ncols, ndisjcuts, TRUE, sepadata->strengthen, cutlhs1, cutlhs2, bound1, bound2, simplexcoefs1, simplexcoefs2, cutcoefs, &row, &madeintegral) ); if ( row == NULL ) continue; /* raise cutrank for present cut */ ++cutrank; /* check if there are numerical evidences */ if ( ( madeintegral && ( sepadata->maxrankintegral == -1 || cutrank <= sepadata->maxrankintegral ) ) || ( ! madeintegral && ( sepadata->maxrank == -1 || cutrank <= sepadata->maxrank ) ) ) { /* possibly add cut to LP if it is useful; in case the lhs of the cut is minus infinity (due to scaling) the cut is useless */ rownnonz = SCIProwGetNNonz(row); if ( rownnonz > 0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) && ! SCIProwIsInLP(row) && SCIPisCutEfficacious(scip, NULL, row) ) { SCIP_Bool infeasible; /* set cut rank */ SCIProwChgRank(row, cutrank); /* add cut */ SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) ); SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) ); if ( infeasible ) { *result = SCIP_CUTOFF; break; } ++ndisjcuts; } } /* release row */ SCIP_CALL( SCIPreleaseRow(scip, &row) ); } /* save total number of cuts found so far */ sepadata->lastncutsfound = SCIPgetNCutsFound(scip); /* evaluate the result of the separation */ if ( *result != SCIP_CUTOFF ) { if ( ndisjcuts > 0 ) *result = SCIP_SEPARATED; else *result = SCIP_DIDNOTFIND; } SCIPdebugMessage("Number of found disjunctive cuts: %d.\n", ndisjcuts); /* free buffer arrays */ SCIPfreeBufferArrayNull(scip, &cutcoefs); SCIPfreeBufferArrayNull(scip, &simplexcoefs2); SCIPfreeBufferArrayNull(scip, &simplexcoefs1); SCIPfreeBufferArrayNull(scip, &coef); SCIPfreeBufferArrayNull(scip, &binvrow); SCIPfreeBufferArrayNull(scip, &basisrow); SCIPfreeBufferArrayNull(scip, &fixings2); SCIPfreeBufferArrayNull(scip, &fixings1); SCIPfreeBufferArrayNull(scip, &edgearray); SCIPfreeBufferArrayNull(scip, &rowsmaxval); SCIPfreeBufferArrayNull(scip, &varrank); return SCIP_OKAY; }
/** computes a disjunctive cut inequality based on two simplex taubleau rows */ static SCIP_RETCODE generateDisjCutSOS1( SCIP* scip, /**< SCIP pointer */ SCIP_SEPA* sepa, /**< separator */ SCIP_ROW** rows, /**< LP rows */ int nrows, /**< number of LP rows */ SCIP_COL** cols, /**< LP columns */ int ncols, /**< number of LP columns */ int ndisjcuts, /**< number of disjunctive cuts found so far */ SCIP_Bool scale, /**< should cut be scaled */ SCIP_Bool strengthen, /**< should cut be strengthened if integer variables are present */ SCIP_Real cutlhs1, /**< left hand side of the first simplex row */ SCIP_Real cutlhs2, /**< left hand side of the second simplex row */ SCIP_Real bound1, /**< bound of first simplex row */ SCIP_Real bound2, /**< bound of second simplex row */ SCIP_Real* simplexcoefs1, /**< simplex coefficients of first row */ SCIP_Real* simplexcoefs2, /**< simplex coefficients of second row */ SCIP_Real* cutcoefs, /**< pointer to store cut coefficients (length: nscipvars) */ SCIP_ROW** row, /**< pointer to store disjunctive cut inequality */ SCIP_Bool* madeintegral /**< pointer to store whether cut has been scaled to integral values */ ) { char cutname[SCIP_MAXSTRLEN]; SCIP_COL** rowcols; SCIP_COL* col; SCIP_Real* rowvals; SCIP_Real lhsrow; SCIP_Real rhsrow; SCIP_Real cutlhs; SCIP_Real sgn; SCIP_Real lb; SCIP_Real ub; int nonbasicnumber = 0; int rownnonz; int ind; int r; int c; assert( scip != NULL ); assert( row != NULL ); assert( rows != NULL ); assert( cols != NULL ); assert( simplexcoefs1 != NULL ); assert( simplexcoefs2 != NULL ); assert( cutcoefs != NULL ); assert( sepa != NULL ); assert( madeintegral != NULL ); *madeintegral = FALSE; /* check signs */ if ( SCIPisFeasPositive(scip, cutlhs1) == SCIPisFeasPositive(scip, cutlhs2) ) sgn = 1.0; else sgn = -1.0; /* check bounds */ if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) ) strengthen = FALSE; /* compute left hand side of row (a later update is possible, see below) */ cutlhs = sgn * cutlhs1 * cutlhs2; /* add cut-coefficients of the non-basic non-slack variables */ for (c = 0; c < ncols; ++c) { col = cols[c]; assert( col != NULL ); ind = SCIPcolGetLPPos(col); assert( ind >= 0 ); if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_LOWER ) { lb = SCIPcolGetLb(col); /* for integer variables we may obtain stronger coefficients */ if ( strengthen && SCIPcolIsIntegral(col) ) { SCIP_Real mval; SCIP_Real mvalfloor; SCIP_Real mvalceil; mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2); mvalfloor = SCIPfloor(scip, mval); mvalceil = SCIPceil(scip, mval); cutcoefs[ind] = MIN(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] - mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] + mvalceil * bound2)); assert( SCIPisFeasLE(scip, cutcoefs[ind], MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) ); } else cutcoefs[ind] = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs += cutcoefs[ind] * lb; ++nonbasicnumber; } else if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_UPPER ) { ub = SCIPcolGetUb(col); /* for integer variables we may obtain stronger coefficients */ if ( strengthen && SCIPcolIsIntegral(col) ) { SCIP_Real mval; SCIP_Real mvalfloor; SCIP_Real mvalceil; mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2); mvalfloor = SCIPfloor(scip, -mval); mvalceil = SCIPceil(scip, -mval); cutcoefs[ind] = MAX(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] + mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] - mvalceil * bound2)); assert( SCIPisFeasLE(scip, -cutcoefs[ind], -MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) ); } else cutcoefs[ind] = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs += cutcoefs[ind] * ub; ++nonbasicnumber; } else { assert( SCIPcolGetBasisStatus(col) != SCIP_BASESTAT_ZERO ); cutcoefs[ind] = 0.0; } } /* add cut-coefficients of the non-basic slack variables */ for (r = 0; r < nrows; ++r) { rhsrow = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]); lhsrow = SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]); assert( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_ZERO ); assert( SCIPisFeasZero(scip, lhsrow - rhsrow) || SCIPisNegative(scip, lhsrow - rhsrow) ); assert( SCIProwIsInLP(rows[r]) ); if ( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_BASIC ) { SCIP_Real cutcoef; if ( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_UPPER ) { assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetRhs(rows[r])) ); cutcoef = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs -= cutcoef * rhsrow; ++nonbasicnumber; } else /* SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER */ { assert( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER ); assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetLhs(rows[r])) ); cutcoef = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]); cutlhs -= cutcoef * lhsrow; ++nonbasicnumber; } rownnonz = SCIProwGetNNonz(rows[r]); rowvals = SCIProwGetVals(rows[r]); rowcols = SCIProwGetCols(rows[r]); for (c = 0; c < rownnonz; ++c) { ind = SCIPcolGetLPPos(rowcols[c]); /* if column is not in LP, then return without generating cut */ if ( ind < 0 ) { *row = NULL; return SCIP_OKAY; } cutcoefs[ind] -= cutcoef * rowvals[c]; } } } /* create cut */ (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_%d_%d", SCIPsepaGetName(sepa), SCIPgetNLPs(scip), ndisjcuts); if ( SCIPgetDepth(scip) == 0 ) SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) ); else SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), TRUE, FALSE, TRUE) ); SCIP_CALL( SCIPcacheRowExtensions(scip, *row) ); for (c = 0; c < ncols; ++c) { ind = SCIPcolGetLPPos(cols[c]); assert( ind >= 0 ); if ( ! SCIPisFeasZero(scip, cutcoefs[ind]) ) { SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPcolGetVar(cols[c]), cutcoefs[ind] ) ); } } SCIP_CALL( SCIPflushRowExtensions(scip, *row) ); /* try to scale the cut to integral values * @todo find better but still stable disjunctive cut settings */ if ( scale ) { int maxdepth; int depth; SCIP_Longint maxdnom; SCIP_Real maxscale; depth = SCIPgetDepth(scip); assert( depth >= 0 ); 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; } SCIP_CALL( SCIPmakeRowIntegral(scip, *row, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, TRUE, madeintegral) ); } 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; }