/** reads the objective section */ static SCIP_RETCODE readObjective( SCIP* scip, /**< SCIP data structure */ LPINPUT* lpinput /**< LP reading data */ ) { char name[LP_MAX_LINELEN]; SCIP_VAR** vars; SCIP_Real* coefs; int ncoefs; SCIP_Bool newsection; assert(lpinput != NULL); /* read the objective coefficients */ SCIP_CALL( readCoefficients(scip, lpinput, TRUE, name, &vars, &coefs, &ncoefs, &newsection) ); if( !hasError(lpinput) ) { int i; SCIP_VAR** oldvars; /* set all linear coefficients to 0 */ oldvars = SCIPgetVars(scip); for( i = 0; i < SCIPgetNVars(scip); i++ ) { SCIP_CALL( SCIPchgVarObj(scip, oldvars[i], 0.0) ); } /* set the linear objective values */ for( i = 0; i < ncoefs; ++i ) { SCIP_CALL( SCIPchgVarObj(scip, vars[i], coefs[i]) ); } } /* free memory */ SCIPfreeMemoryArrayNull(scip, &vars); SCIPfreeMemoryArrayNull(scip, &coefs); return SCIP_OKAY; }
/** read variable */ static SCIP_RETCODE getVariable( SCIP* scip, /**< SCIP data structure */ CIPINPUT* cipinput, /**< CIP parsing data */ SCIP_Bool initial, /**< should var's column be present in the initial root LP? */ SCIP_Bool removable, /**< is var's column removable from the LP (due to aging or cleanup)? */ SCIP_Real objscale /**< objective scale */ ) { SCIP_Bool success; SCIP_VAR* var; char* buf; char* endptr; buf = cipinput->strbuf; if( strncmp(buf, "FIXED", 5) == 0 ) cipinput->section = CIP_FIXEDVARS; else if( strncmp(buf, "CONSTRAINTS", 4) == 0 ) cipinput->section = CIP_CONSTRAINTS; else if( strncmp(buf, "END", 3) == 0 ) cipinput->section = CIP_END; if( cipinput->section != CIP_VARS ) return SCIP_OKAY; SCIPdebugMessage("parse variable\n"); /* parse the variable */ SCIP_CALL( SCIPparseVar(scip, &var, buf, initial, removable, NULL, NULL, NULL, NULL, NULL, &endptr, &success) ); if( !success ) { SCIPerrorMessage("syntax error in variable information (line: %d):\n%s\n", cipinput->linenumber, cipinput->strbuf); cipinput->haserror = TRUE; return SCIP_OKAY; } if( objscale != 1.0 ) { SCIP_CALL( SCIPchgVarObj(scip, var, SCIPvarGetObj(var) * objscale) ); } SCIP_CALL( SCIPaddVar(scip, var) ); SCIPdebug( SCIP_CALL( SCIPprintVar(scip, var, NULL) ) ); SCIP_CALL( SCIPreleaseVar(scip, &var) ); return SCIP_OKAY; }
/* Read SAT formula in "CNF File Format". * * The specification is taken from the * * Satisfiability Suggested Format * * Online available at http://www.intellektik.informatik.tu-darmstadt.de/SATLIB/Benchmarks/SAT/satformat.ps * * The method reads all files of CNF format. Other formats (SAT, SATX, SATE) are not supported. */ static SCIP_RETCODE readCnf( SCIP* scip, /**< SCIP data structure */ SCIP_FILE* file /**< input file */ ) { SCIP_RETCODE retcode; SCIP_VAR** vars; SCIP_VAR** clausevars; SCIP_CONS* cons; int* varsign; char* tok; char* nexttok; char line[MAXLINELEN]; char format[SCIP_MAXSTRLEN]; char varname[SCIP_MAXSTRLEN]; char s[SCIP_MAXSTRLEN]; SCIP_Bool dynamicconss; SCIP_Bool dynamiccols; SCIP_Bool dynamicrows; SCIP_Bool useobj; int linecount; int clauselen; int clausenum; int nvars; int nclauses; int varnum; int v; assert(scip != NULL); assert(file != NULL); retcode = SCIP_OKAY; linecount = 0; /* read header */ SCIP_CALL( readCnfLine(scip, file, line, (int) sizeof(line), &linecount) ); if( *line != 'p' ) { readError(scip, linecount, "problem declaration line expected"); return SCIP_READERROR; } if( sscanf(line, "p %8s %d %d", format, &nvars, &nclauses) != 3 ) { readError(scip, linecount, "invalid problem declaration (must be 'p cnf <nvars> <nclauses>')"); return SCIP_READERROR; } if( strcmp(format, "cnf") != 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid format tag <%s> (must be 'cnf')", format); readError(scip, linecount, s); return SCIP_READERROR; } if( nvars <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of variables <%d> (must be positive)", nvars); readError(scip, linecount, s); return SCIP_READERROR; } if( nclauses <= 0 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid number of clauses <%d> (must be positive)", nclauses); readError(scip, linecount, s); return SCIP_READERROR; } /* get parameter values */ SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamicconss", &dynamicconss) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamiccols", &dynamiccols) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/dynamicrows", &dynamicrows) ); SCIP_CALL( SCIPgetBoolParam(scip, "reading/cnfreader/useobj", &useobj) ); /* get temporary memory */ SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &clausevars, nvars) ); SCIP_CALL( SCIPallocBufferArray(scip, &varsign, nvars) ); /* create the variables */ for( v = 0; v < nvars; ++v ) { (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x%d", v+1); SCIP_CALL( SCIPcreateVar(scip, &vars[v], varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) ); SCIP_CALL( SCIPaddVar(scip, vars[v]) ); varsign[v] = 0; } /* read clauses */ clausenum = 0; clauselen = 0; do { retcode = readCnfLine(scip, file, line, (int) sizeof(line), &linecount); if( retcode != SCIP_OKAY ) goto TERMINATE; if( *line != '\0' && *line != '%' ) { tok = SCIPstrtok(line, " \f\n\r\t", &nexttok); while( tok != NULL ) { /* parse literal and check for errors */ if( sscanf(tok, "%d", &v) != 1 ) { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid literal <%s>", tok); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* interpret literal number: v == 0: end of clause, v < 0: negated literal, v > 0: positive literal */ if( v == 0 ) { /* end of clause: construct clause and add it to SCIP */ if( clauselen == 0 ) readWarning(scip, linecount, "empty clause detected in line -- problem infeasible"); clausenum++; (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "c%d", clausenum); if( SCIPfindConshdlr(scip, "logicor") != NULL ) { /* if the constraint handler logicor exit create a logicor constraint */ SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, s, clauselen, clausevars, !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else if( SCIPfindConshdlr(scip, "setppc") != NULL ) { /* if the constraint handler logicor does not exit but constraint * handler setppc create a setppc constraint */ SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, s, clauselen, clausevars, !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); } else { /* if none of the previous constraint handler exits create a linear * constraint */ SCIP_Real* vals; int i; SCIP_CALL( SCIPallocBufferArray(scip, &vals, clauselen) ); for( i = 0; i < clauselen; ++i ) vals[i] = 1.0; SCIP_CALL( SCIPcreateConsLinear(scip, &cons, s, clauselen, clausevars, vals, 1.0, SCIPinfinity(scip), !dynamicrows, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) ); SCIPfreeBufferArray(scip, &vals); } SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); clauselen = 0; } else if( v >= -nvars && v <= nvars ) { if( clauselen >= nvars ) { readError(scip, linecount, "too many literals in clause"); retcode = SCIP_READERROR; goto TERMINATE; } /* add literal to clause */ varnum = ABS(v)-1; if( v < 0 ) { SCIP_CALL( SCIPgetNegatedVar(scip, vars[varnum], &clausevars[clauselen]) ); varsign[varnum]--; } else { clausevars[clauselen] = vars[varnum]; varsign[varnum]++; } clauselen++; } else { (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "invalid variable number <%d>", ABS(v)); readError(scip, linecount, s); retcode = SCIP_READERROR; goto TERMINATE; } /* get next token */ tok = SCIPstrtok(NULL, " \f\n\r\t", &nexttok); } } } while( *line != '\0' && *line != '%' ); /* check for additional literals */ if( clauselen > 0 ) { SCIPwarningMessage(scip, "found %d additional literals after last clause\n", clauselen); } /* check number of clauses */ if( clausenum != nclauses ) { SCIPwarningMessage(scip, "expected %d clauses, but found %d\n", nclauses, clausenum); } TERMINATE: /* change objective values and release variables */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); if( useobj ) { for( v = 0; v < nvars; ++v ) { SCIP_CALL( SCIPchgVarObj(scip, vars[v], (SCIP_Real)varsign[v]) ); SCIP_CALL( SCIPreleaseVar(scip, &vars[v]) ); } } /* free temporary memory */ SCIPfreeBufferArray(scip, &varsign); SCIPfreeBufferArray(scip, &clausevars); SCIPfreeBufferArray(scip, &vars); return retcode; }
/** main procedure of the zeroobj heuristic, creates and solves a sub-SCIP */ SCIP_RETCODE SCIPapplyZeroobj( SCIP* scip, /**< original SCIP data structure */ SCIP_HEUR* heur, /**< heuristic data structure */ SCIP_RESULT* result, /**< result data structure */ SCIP_Real minimprove, /**< factor by which zeroobj should at least improve the incumbent */ SCIP_Longint nnodes /**< node limit for the subproblem */ ) { SCIP* subscip; /* the subproblem created by zeroobj */ SCIP_HASHMAP* varmapfw; /* mapping of SCIP variables to sub-SCIP variables */ SCIP_VAR** vars; /* original problem's variables */ SCIP_VAR** subvars; /* subproblem's variables */ SCIP_HEURDATA* heurdata; /* heuristic's private data structure */ SCIP_EVENTHDLR* eventhdlr; /* event handler for LP events */ SCIP_Real cutoff; /* objective cutoff for the subproblem */ SCIP_Real timelimit; /* time limit for zeroobj subproblem */ SCIP_Real memorylimit; /* memory limit for zeroobj subproblem */ SCIP_Real large; int nvars; /* number of original problem's variables */ int i; SCIP_Bool success; SCIP_Bool valid; SCIP_RETCODE retcode; SCIP_SOL** subsols; int nsubsols; assert(scip != NULL); assert(heur != NULL); assert(result != NULL); assert(nnodes >= 0); assert(0.0 <= minimprove && minimprove <= 1.0); *result = SCIP_DIDNOTRUN; /* only call heuristic once at the root */ if( SCIPgetDepth(scip) <= 0 && SCIPheurGetNCalls(heur) > 0 ) return SCIP_OKAY; /* get heuristic data */ heurdata = SCIPheurGetData(heur); assert(heurdata != NULL); /* only call the heuristic if we do not have an incumbent */ if( SCIPgetNSolsFound(scip) > 0 && heurdata->onlywithoutsol ) return SCIP_OKAY; /* check whether there is enough time and memory left */ timelimit = 0.0; memorylimit = 0.0; SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); /* substract the memory already used by the main SCIP and the estimated memory usage of external software */ if( !SCIPisInfinity(scip, memorylimit) ) { memorylimit -= SCIPgetMemUsed(scip)/1048576.0; memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0; } /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */ if( timelimit <= 0.0 || memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 ) return SCIP_OKAY; *result = SCIP_DIDNOTFIND; /* get variable data */ SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) ); /* initialize the subproblem */ SCIP_CALL( SCIPcreate(&subscip) ); /* create the variable mapping hash map */ SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), SCIPcalcHashtableSize(5 * nvars)) ); SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) ); /* different methods to create sub-problem: either copy LP relaxation or the CIP with all constraints */ valid = FALSE; /* copy complete SCIP instance */ SCIP_CALL( SCIPcopy(scip, subscip, varmapfw, NULL, "zeroobj", TRUE, FALSE, TRUE, &valid) ); SCIPdebugMessage("Copying the SCIP instance was %s complete.\n", valid ? "" : "not "); /* create event handler for LP events */ eventhdlr = NULL; SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecZeroobj, NULL) ); if( eventhdlr == NULL ) { SCIPerrorMessage("event handler for "HEUR_NAME" heuristic not found.\n"); return SCIP_PLUGINNOTFOUND; } /* determine large value to set variables to */ large = SCIPinfinity(scip); if( !SCIPisInfinity(scip, 0.1 / SCIPfeastol(scip)) ) large = 0.1 / SCIPfeastol(scip); /* get variable image and change to 0.0 in sub-SCIP */ for( i = 0; i < nvars; i++ ) { SCIP_Real adjustedbound; SCIP_Real lb; SCIP_Real ub; SCIP_Real inf; subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]); SCIP_CALL( SCIPchgVarObj(subscip, subvars[i], 0.0) ); lb = SCIPvarGetLbGlobal(subvars[i]); ub = SCIPvarGetUbGlobal(subvars[i]); inf = SCIPinfinity(subscip); /* adjust infinite bounds in order to avoid that variables with non-zero objective * get fixed to infinite value in zeroobj subproblem */ if( SCIPisInfinity(subscip, ub ) ) { adjustedbound = MAX(large, lb+large); adjustedbound = MIN(adjustedbound, inf); SCIP_CALL( SCIPchgVarUbGlobal(subscip, subvars[i], adjustedbound) ); } if( SCIPisInfinity(subscip, -lb ) ) { adjustedbound = MIN(-large, ub-large); adjustedbound = MAX(adjustedbound, -inf); SCIP_CALL( SCIPchgVarLbGlobal(subscip, subvars[i], adjustedbound) ); } } /* free hash map */ SCIPhashmapFree(&varmapfw); /* do not abort subproblem on CTRL-C */ SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) ); /* disable output to console */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) ); /* set limits for the subproblem */ SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nnodes) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPsetIntParam(subscip, "limits/solutions", 1) ); /* forbid recursive call of heuristics and separators solving sub-SCIPs */ SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) ); /* disable expensive techniques that merely work on the dual bound */ /* disable cutting plane separation */ SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) ); /* disable expensive presolving */ SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) ); if( !SCIPisParamFixed(subscip, "presolving/maxrounds") ) { SCIP_CALL( SCIPsetIntParam(subscip, "presolving/maxrounds", 50) ); } /* use best dfs node selection */ if( SCIPfindNodesel(subscip, "dfs") != NULL && !SCIPisParamFixed(subscip, "nodeselection/dfs/stdpriority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/dfs/stdpriority", INT_MAX/4) ); } /* use inference branching */ if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") ) { SCIP_CALL( SCIPsetIntParam(subscip, "branching/leastinf/priority", INT_MAX/4) ); } /* employ a limit on the number of enforcement rounds in the quadratic constraint handler; this fixes the issue that * sometimes the quadratic constraint handler needs hundreds or thousands of enforcement rounds to determine the * feasibility status of a single node without fractional branching candidates by separation (namely for uflquad * instances); however, the solution status of the sub-SCIP might get corrupted by this; hence no deductions shall be * made for the original SCIP */ if( SCIPfindConshdlr(subscip, "quadratic") != NULL && !SCIPisParamFixed(subscip, "constraints/quadratic/enfolplimit") ) { SCIP_CALL( SCIPsetIntParam(subscip, "constraints/quadratic/enfolplimit", 10) ); } /* disable feaspump and fracdiving */ if( !SCIPisParamFixed(subscip, "heuristics/feaspump/freq") ) { SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/feaspump/freq", -1) ); } if( !SCIPisParamFixed(subscip, "heuristics/fracdiving/freq") ) { SCIP_CALL( SCIPsetIntParam(subscip, "heuristics/fracdiving/freq", -1) ); } /* restrict LP iterations */ SCIP_CALL( SCIPsetLongintParam(subscip, "lp/iterlim", 2*heurdata->maxlpiters / MAX(1,nnodes)) ); SCIP_CALL( SCIPsetLongintParam(subscip, "lp/rootiterlim", heurdata->maxlpiters) ); #ifdef SCIP_DEBUG /* for debugging zeroobj, enable MIP output */ SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) ); SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 100000000) ); #endif /* if there is already a solution, add an objective cutoff */ if( SCIPgetNSols(scip) > 0 ) { SCIP_Real upperbound; SCIP_CONS* origobjcons; #ifndef NDEBUG int nobjvars; nobjvars = 0; #endif cutoff = SCIPinfinity(scip); assert( !SCIPisInfinity(scip,SCIPgetUpperbound(scip)) ); upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip); if( !SCIPisInfinity(scip,-1.0*SCIPgetLowerbound(scip)) ) { cutoff = (1-minimprove)*SCIPgetUpperbound(scip) + minimprove*SCIPgetLowerbound(scip); } else { if( SCIPgetUpperbound(scip) >= 0 ) cutoff = ( 1 - minimprove ) * SCIPgetUpperbound ( scip ); else cutoff = ( 1 + minimprove ) * SCIPgetUpperbound ( scip ); } cutoff = MIN(upperbound, cutoff); SCIP_CALL( SCIPcreateConsLinear(subscip, &origobjcons, "objbound_of_origscip", 0, NULL, NULL, -SCIPinfinity(subscip), cutoff, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); for( i = 0; i < nvars; ++i) { if( !SCIPisFeasZero(subscip, SCIPvarGetObj(vars[i])) ) { SCIP_CALL( SCIPaddCoefLinear(subscip, origobjcons, subvars[i], SCIPvarGetObj(vars[i])) ); #ifndef NDEBUG nobjvars++; #endif } } SCIP_CALL( SCIPaddCons(subscip, origobjcons) ); SCIP_CALL( SCIPreleaseCons(subscip, &origobjcons) ); assert(nobjvars == SCIPgetNObjVars(scip)); } /* catch LP events of sub-SCIP */ SCIP_CALL( SCIPtransformProb(subscip) ); SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) ); SCIPdebugMessage("solving subproblem: nnodes=%"SCIP_LONGINT_FORMAT"\n", nnodes); retcode = SCIPsolve(subscip); /* drop LP events of sub-SCIP */ SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_NODESOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) ); /* errors in solving the subproblem should not kill the overall solving process; * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop. */ if( retcode != SCIP_OKAY ) { #ifndef NDEBUG SCIP_CALL( retcode ); #endif SCIPwarningMessage(scip, "Error while solving subproblem in zeroobj heuristic; sub-SCIP terminated with code <%d>\n",retcode); } /* check, whether a solution was found; * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted */ nsubsols = SCIPgetNSols(subscip); subsols = SCIPgetSols(subscip); success = FALSE; for( i = 0; i < nsubsols && (!success || heurdata->addallsols); ++i ) { SCIP_CALL( createNewSol(scip, subscip, subvars, heur, subsols[i], &success) ); if( success ) *result = SCIP_FOUNDSOL; } #ifdef SCIP_DEBUG SCIP_CALL( SCIPprintStatistics(subscip, NULL) ); #endif /* free subproblem */ SCIPfreeBufferArray(scip, &subvars); SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }